For AI agents: markdown of this page — /docs-content-en/storage/upload/multipart-complete.md documentation index — /llms.txt

Complete multipart upload

POST /v1/storage/objects/multipart/complete

Finalizes a multipart upload session: assembles the uploaded parts into a single storage object and moves it to status COMPLETED. On replacement, the new bytes and metadata are published under the existing objectId; reads return the old content only until publication actually happens. A successful response confirms the new version. Retrying complete with the same parts finishes the operation when the provider response was already journalled: the server finalizes the published result locally without asking the provider to assemble it again. If complete returns 502 STORAGE_BUCKET_ERROR, publication may have happened without a journalled response: the session is retained and requires operator reconciliation, and a blind retry does not confirm the current version. Until an operator releases it, the object cannot be deleted and owner-data erasure remains pending. Returns the ready object when the result is confirmed.

Request fields (body)

The request body is JSON.

Parameter Type Required Default Description
objectId string yes Object identifier obtained from the /multipart/create response
parts array yes Non-empty array of part descriptors with numbers and ETags
parts[].partNumber number yes Part number (integer from 1 to 10,000); must match the numbers from the /multipart/create response; duplicates are not allowed
parts[].etag string yes Value of the ETag header from the response to the part's PUT request; accepted with quotes ("abc...") and without

Examples

curl — personal key

Terminal
curl -X POST https://vibecode.bitrix24.com/v1/storage/objects/multipart/complete \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "objectId": "cmpfg012a01aco510mrr6u632",
    "parts": [
      { "partNumber": 1, "etag": "b315b942673d13dbdd2d866e92b0ec13" },
      { "partNumber": 2, "etag": "a1b2c3d4e5f678901234567890abcdef" }
    ]
  }'

curl — OAuth application

Terminal
curl -X POST https://vibecode.bitrix24.com/v1/storage/objects/multipart/complete \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "objectId": "cmpfg012a01aco510mrr6u632",
    "parts": [
      { "partNumber": 1, "etag": "b315b942673d13dbdd2d866e92b0ec13" },
      { "partNumber": 2, "etag": "a1b2c3d4e5f678901234567890abcdef" }
    ]
  }'

JavaScript — personal key

javascript
// uploadedParts — an array of { partNumber, etag } collected at the part-PUT step
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/storage/objects/multipart/complete',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      objectId: 'cmpfg012a01aco510mrr6u632',
      parts: uploadedParts,
    }),
  }
)
const { object } = await res.json()
console.log('Object ID:', object.id)

JavaScript — OAuth application

javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/storage/objects/multipart/complete',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      objectId: 'cmpfg012a01aco510mrr6u632',
      parts: uploadedParts,
    }),
  }
)
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 or null
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
object.contentUpdatedAt string (ISO 8601) When 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

JSON
{
  "object": {
    "id": "cmpfg012a01aco510mrr6u632",
    "key": "videos/lecture-01.mp4",
    "contentType": "video/mp4",
    "sizeBytes": "209715200",
    "sha256": null,
    "visibility": "PRIVATE",
    "uploadStatus": "COMPLETED",
    "createdAt": "2026-05-21T12:03:56.387Z",
    "deletedAt": null
  }
}

Error response example

400 — an incorrect number of parts was passed:

JSON
{
  "success": false,
  "error": {
    "code": "STORAGE_INVALID_PARTS",
    "message": "Expected 2 parts, got 1"
  }
}

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_INVALID_PATH The caller identifier contains invalid path characters
400 STORAGE_OBJECT_ID_REQUIRED The objectId field was not provided
400 STORAGE_PARTS_REQUIRED The parts field is missing or is an empty array
400 STORAGE_INVALID_PART An element of the parts array contains an invalid partNumber (not an integer in the range 1–10,000, a duplicate) or an empty etag
404 STORAGE_OBJECT_NOT_FOUND The object with the given objectId was not found or the multipart upload session is already finalized
409 STORAGE_KEY_CONFLICT Retryable conflict: a concurrent write owns the address, or finalization state is changing. Retry complete with the same parts: if the provider response was already journalled, the server finishes the operation locally
400 STORAGE_INVALID_PARTS The number of parts does not match partCount from /create, or storage rejected the assembly due to invalid ETags
503 STORAGE_FEATURE_DISABLED Storage is disabled for the portal
503 STORAGE_STS_UNAVAILABLE The temporary credentials issuance service is unavailable
502 STORAGE_BUCKET_ERROR Provider publication may have completed, but its response was not journalled. The session is retained and requires operator reconciliation; until an operator releases it, the object cannot be deleted and owner-data erasure remains pending. Do not treat a blind retry as proof of success

Full list of common API errors — Errors.

See also