لوكلاء AI: ملف markdown لهذه الصفحة — /docs-content-en/storage/upload.md فهرس التوثيق — /llms.txt
مقالات التوثيق متاحة حاليًا باللغة الإنجليزية فقط.
Upload
Three file upload paths into storage: a direct form for small files, a presigned PUT for browser uploads, and multipart upload for large files.
Scope: vibe:storage | Base URL: https://vibecode.bitrix24.com/v1 | Authorization: API key (X-Api-Key)
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.
Uploading again under the same key replaces the object content. This also applies to a soft-deleted object when it belongs to the same owner tuple, has COMPLETED status, and has no open multipart session. The row is revived with the same object.id, createdAt, key, physical address, owner tuple, and visibility; deletedAt is cleared, while sizeBytes, sha256, contentType, and contentUpdatedAt are updated to match the new bytes.
This does not restore the deleted content: Path A writes new bytes over the old ones. For a PUBLIC object, a previously issued anonymous URL with the same object.id starts working again and serves the new bytes. To replace or revive an object, omit visibility or pass the stored value — visibility cannot change (STORAGE_VISIBILITY_MISMATCH). Deleted PENDING rows and rows with a multipart session stay occupied and return 409 STORAGE_KEY_DELETED.
Replacement and revival work the same way for an app-bound key and for a personal developer key: uploading again under the same key does not create a second object.
For Path A direct uploads, concurrent requests to the same physical address run one at a time. A request waits for its turn for no more than 60 seconds; if safe write ownership cannot be confirmed, the server returns 409 STORAGE_KEY_CONFLICT before writing to object storage. Retry the entire request. The guarantee also covers a personal key (appId = null). Path C serializes every key, but replaces a live object only for an app-bound key; it accepts a personal key after explicit DELETE. Path B is excluded.
Request fields (body)
The request body must be in multipart/form-data format.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
Parameterfile |
Typefile | Requiredyes | Default— | DescriptionBinary 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 |
Parameterkey |
Typestring | Requiredyes | Default— | DescriptionLogical object key: 1 to 1024 characters. Allowed characters: a-z, A-Z, 0-9, ., _, /, -. Must not start with / or . and must not contain .. |
Parametervisibility |
Typestring | Requiredno | DefaultPRIVATE |
DescriptionObject visibility: PRIVATE or PUBLIC. On a new object an omitted field means PRIVATE. When replacing or reviving an existing object visibility does not change: omit the field or pass the stored value |
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 |
|---|---|---|
Fieldobject.id |
Typestring | DescriptionObject identifier |
Fieldobject.key |
Typestring | DescriptionLogical object key |
Fieldobject.contentType |
Typestring | DescriptionFile MIME type |
Fieldobject.sizeBytes |
Typestring | DescriptionFile size in bytes (string) |
Fieldobject.sha256 |
Typestring | DescriptionFile SHA-256 hash. Always computed on direct upload |
Fieldobject.visibility |
Typestring | DescriptionVisibility: PRIVATE or PUBLIC |
Fieldobject.uploadStatus |
Typestring | DescriptionUpload status: COMPLETED |
Fieldobject.createdAt |
Typestring | DescriptionCreation date (ISO 8601) |
Fieldobject.deletedAt |
Typestring | DescriptionDeletion date or null |
Fieldobject.contentUpdatedAt |
Typestring (ISO 8601) | DescriptionWhen the content last became current: a replacement, or the first completion of the upload. Service updates do not move it. null for objects last written before this field existed |
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 |
|---|---|---|
| HTTP403 | CodeSTORAGE_SCOPE_REQUIRED |
DescriptionThe API key lacks the vibe:storage scope |
| HTTP401 | CodeSTORAGE_NO_AUTH_CONTEXT |
DescriptionThe request was made without authorization |
| HTTP400 | CodeSTORAGE_FILE_REQUIRED |
DescriptionThe file field was not provided |
| HTTP400 | CodeSTORAGE_KEY_REQUIRED |
DescriptionThe key field was not provided |
| HTTP400 | CodeSTORAGE_INVALID_KEY |
DescriptionThe key value violates the format rules |
| HTTP400 | CodeSTORAGE_INVALID_VISIBILITY |
DescriptionInvalid visibility value |
| HTTP400 | CodeSTORAGE_VISIBILITY_MISMATCH |
DescriptionReplacing content cannot change object visibility. Omit the field or pass the current value — it is named in the error message |
| HTTP409 | CodeSTORAGE_KEY_DELETED |
DescriptionThe deleted row is not eligible for Path A revival: it is not a COMPLETED object without a multipart session. An eligible deleted object returns 200 with the same id and visibility instead |
| HTTP409 | CodeSTORAGE_MULTIPART_IN_PROGRESS |
DescriptionThe object has a multipart upload in progress — complete or abort it |
| HTTP409 | CodeSTORAGE_UPLOAD_PENDING |
DescriptionA presigned URL was issued for this key and the upload is not confirmed yet |
| HTTP409 | CodeSTORAGE_KEY_OWNED_ELSEWHERE |
DescriptionThe name is taken by an object of the other ownership kind (app-shared vs per-employee). Another employee does not block the same name |
| HTTP409 | CodeSTORAGE_KEY_CONFLICT |
DescriptionThe object state changed, or a concurrent direct upload (Path A) did not obtain write ownership within 60 seconds or the concurrency limit. Object storage is untouched until confirmation; retry the entire request. Serialization also covers a personal key (appId = null). Path C serializes every key, but replaces a live object only for an app-bound key; it accepts a personal key after explicit DELETE. Path B is excluded |
| HTTP400 | CodeSTORAGE_MULTIPART_PARSE_FAILED |
DescriptionFailed to parse the request body as multipart/form-data |
| HTTP413 | CodeSTORAGE_UPLOAD_TOO_LARGE |
DescriptionThe file exceeds 10 MB — use multipart upload (Path B is temporarily disabled) |
| HTTP415 | CodeSTORAGE_FORBIDDEN_CONTENT_TYPE |
DescriptionFor PUBLIC objects the types text/html, application/javascript, application/x-javascript, image/svg+xml are forbidden |
| HTTP402 | CodeBILLING_INSUFFICIENT |
DescriptionInsufficient balance |
| HTTP507 | CodeSTORAGE_QUOTA_EXCEEDED |
DescriptionThe file size does not fit the remaining portal storage volume cap. The cap is optional, is switched on by the platform, and applies only to portals that have no commercial Bitrix24 plan and never had one. Usage is counted across the whole portal, not per app |
| HTTP503 | CodeSTORAGE_FEATURE_DISABLED |
DescriptionStorage is disabled for the portal |
| HTTP502 | CodeSTORAGE_BUCKET_ERROR |
DescriptionError while interacting with storage |
Full list of common API errors — Errors.
Known specifics
Files larger than 10 MB. Path B is temporarily disabled and answers 503 STORAGE_PRESIGNED_UPLOAD_DISABLED, so upload anything above 10 MB with 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.