For AI agents: markdown of this page — /docs-content-en/storage/upload/direct.md documentation index — /llms.txt
Direct file upload
POST /v1/storage/objects/upload
Uploads a file up to 10 MB in a single multipart/form-data request — the server accepts the file and returns the resulting storage object.
Request fields (body)
The request body must be in multipart/form-data format.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
file |
file | yes | — | Binary file no larger than 10 MB. The MIME type is determined from the Content-Type header of the form part. If the header is absent, application/octet-stream is used |
key |
string | yes | — | Logical object key: 1 to 1024 characters. Allowed characters: a-z, A-Z, 0-9, ., _, /, -. Must not start with / or . and must not contain .. |
visibility |
string | no | PRIVATE |
Object visibility: PRIVATE or PUBLIC |
Examples
curl — personal key
curl -X POST https://vibecode.bitrix24.com/v1/storage/objects/upload \
-H "X-Api-Key: YOUR_API_KEY" \
-F "file=@avatar.png;type=image/png" \
-F "key=users/42/avatar.png" \
-F "visibility=PRIVATE"
curl — OAuth application
curl -X POST https://vibecode.bitrix24.com/v1/storage/objects/upload \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-F "file=@avatar.png;type=image/png" \
-F "key=users/42/avatar.png" \
-F "visibility=PRIVATE"
JavaScript — personal key
const formData = new FormData()
formData.append('file', fileInput.files[0])
formData.append('key', 'users/42/avatar.png')
formData.append('visibility', 'PRIVATE')
const res = await fetch('https://vibecode.bitrix24.com/v1/storage/objects/upload', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
},
body: formData,
})
if (!res.ok) {
const { error } = await res.json()
console.error(error.code, error.message)
return
}
const { object } = await res.json()
console.log('Object ID:', object.id)
JavaScript — OAuth application
const formData = new FormData()
formData.append('file', fileInput.files[0])
formData.append('key', 'users/42/avatar.png')
formData.append('visibility', 'PRIVATE')
const res = await fetch('https://vibecode.bitrix24.com/v1/storage/objects/upload', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
body: formData,
})
const { object } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
object.id |
string | Object identifier |
object.key |
string | Logical object key |
object.contentType |
string | File MIME type |
object.sizeBytes |
string | File size in bytes (string) |
object.sha256 |
string | File SHA-256 hash. Always computed on direct upload |
object.visibility |
string | Visibility: PRIVATE or PUBLIC |
object.uploadStatus |
string | Upload status: COMPLETED |
object.createdAt |
string | Creation date (ISO 8601) |
object.deletedAt |
string | Deletion date or null |
Response example
{
"object": {
"id": "cmpf9b1gp003omr0zkc0qjojn",
"key": "users/42/avatar.png",
"contentType": "image/png",
"sizeBytes": "20480",
"sha256": "10068f1908d45621f11b50a1d23ddc0720a669c15f45a43d883604e7793537cd",
"visibility": "PRIVATE",
"uploadStatus": "COMPLETED",
"createdAt": "2026-05-21T08:56:32.809Z",
"deletedAt": null
}
}
Error response example
415 — the request passed a MIME type that is not allowed for PUBLIC objects because of cross-site scripting risks:
{
"success": false,
"error": {
"code": "STORAGE_FORBIDDEN_CONTENT_TYPE",
"message": "Content-Type text/html is not allowed for PUBLIC objects (XSS-prone)"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 403 | STORAGE_SCOPE_REQUIRED |
The API key lacks the vibe:storage scope |
| 401 | STORAGE_NO_AUTH_CONTEXT |
The request was made without authorization |
| 400 | STORAGE_FILE_REQUIRED |
The file field was not provided |
| 400 | STORAGE_KEY_REQUIRED |
The key field was not provided |
| 400 | STORAGE_INVALID_KEY |
The key value violates the format rules |
| 400 | STORAGE_INVALID_VISIBILITY |
Invalid visibility value |
| 400 | STORAGE_MULTIPART_PARSE_FAILED |
Failed to parse the request body as multipart/form-data |
| 413 | STORAGE_UPLOAD_TOO_LARGE |
The file exceeds 10 MB — use a presigned URL |
| 415 | STORAGE_FORBIDDEN_CONTENT_TYPE |
For PUBLIC objects the types text/html, application/javascript, application/x-javascript, image/svg+xml are forbidden |
| 402 | BILLING_INSUFFICIENT |
Insufficient balance |
| 503 | STORAGE_FEATURE_DISABLED |
Storage is disabled for the portal |
| 502 | STORAGE_BUCKET_ERROR |
Error while interacting with storage |
Full list of common API errors — Errors.
Known specifics
Files larger than 10 MB. For files from 10 MB to 5 GB use a presigned URL (Path B). For files larger than 5 GB — multipart upload (Path C).
Type check for PUBLIC objects. The check runs against the declared Content-Type of the form part before the file is written — if it fails, the request is rejected without accessing storage.