Skip to content
Create a key

Paste a key to use it in the examples on these pages. The key stays in this browser tab. These pages never send it anywhere.

Send a part of an upload

upload_partPUT/v1/uploads/{uploadId}/parts/{partNumber}Beta

Sends one part of an upload as raw bytes, and returns the parts received so far.

Beta. This endpoint is supported and can gain new fields. If a change would break your code, we tell you before it takes effect and list it in the changelog.

About

Send the bytes of the part as the body, with Content-Type: application/octet-stream and no JSON around them. Every part is exactly partSizeBytes long except the last one, which holds the rest of the file. Parts are numbered from 1 to partCount and can be sent in any order and in parallel; sending a part again replaces it. When receivedParts lists every part, call complete_upload (POST /v1/uploads/{uploadId}/complete). A part sent while the upload is being completed is refused, and so is a part that was still arriving when complete_upload started: send it again, then complete the upload again.

Example use

A worker that uploads a large recording sends several parts at the same time. If one part fails, it sends that part again and leaves the others as they are.

Endpoint

Code
PUT https://api.gpt-video.com/v1/uploads/{uploadId}/parts/{partNumber}
  • Scope clips:write.
  • Rate limit 60 requests a minute for each key and 120 for each account, shared by every write call. See rate limits.
  • No Idempotency-Key.

Parameters

Path

NameTypeRequiredDescription
uploadIdstringRequiredThe id of the upload, as create_upload (POST /v1/uploads) returned it. Matches ^upl_[0-9a-f]{20}$.
partNumberintegerRequiredThe number of the part, from 1 to the partCount of the upload. From 1 to 1024.

Body

The raw bytes of the part, sent with Content-Type: application/octet-stream. At most 8388608 bytes.

Request

Send the first part.

Request example
curl -X PUT "https://api.gpt-video.com/v1/uploads/upl_5d2a8f1e6c3b4079e0a1/parts/1" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @part-1.bin
import { readFile } from "node:fs/promises";

const res = await fetch("https://api.gpt-video.com/v1/uploads/upl_5d2a8f1e6c3b4079e0a1/parts/1", {
  method: "PUT",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Content-Type": "application/octet-stream",
  },
  body: await readFile("part-1.bin"),
});
const data = await res.json();
console.log(data);
import os

import requests

r = requests.put(
    "https://api.gpt-video.com/v1/uploads/upl_5d2a8f1e6c3b4079e0a1/parts/1",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
        "Content-Type": "application/octet-stream",
    },
    data=open("part-1.bin", "rb").read(),
)
data = r.json()
print(data)

Response

A successful call answers HTTP 200. Returns a Upload object in upload.

Fields to check

NameTypeDescription
upload.idstringThe upload id. It starts with upl_.

Response example

HTTP 200
{
  "upload": {
    "id": "upl_5d2a8f1e6c3b4079e0a1",
    "filename": "keynote.mp4",
    "contentType": "video/mp4",
    "sizeBytes": 20971520,
    "partSizeBytes": 8388608,
    "partCount": 3,
    "receivedParts": [
      1
    ],
    "createdAt": "2026-09-01T10:30:00.000Z",
    "expiresAt": "2026-09-01T16:31:00.000Z"
  }
}
All response fields
NameTypeRequiredDescription
uploadUpload objectRequiredDescribed in Upload object.
More examples

Send a part the upload does not have

PUT /v1/uploads/upl_5d2a8f1e6c3b4079e0a1/parts/4

A body of 1024 bytes.

HTTP 400
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Part 4 does not exist: this upload has 3 parts, numbered 1 to 3.",
    "hint": "Fix the request as the message says, then send it again.",
    "requestId": "req_7c1e5a3b9d0f2e8c4a6b1d5f"
  }
}

Send the last part with the wrong size

PUT /v1/uploads/upl_5d2a8f1e6c3b4079e0a1/parts/3

A body of 8388608 bytes.

HTTP 400
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Part 3 must be 4194304 bytes, and the request declares 8388608.",
    "hint": "Fix the request as the message says, then send it again.",
    "requestId": "req_3f8a0c6e2b9d5a1f7c4e0b3a"
  }
}

Send a part of an upload that does not exist

PUT /v1/uploads/upl_3b6f9e2d7c0a4e51a8d9/parts/1

A body of 1024 bytes.

HTTP 404
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Upload upl_3b6f9e2d7c0a4e51a8d9 not found",
    "hint": "Check the id. An id that belongs to another account is not found either.",
    "requestId": "req_9b2d6f0a4e8c1b5d3f7a2e6c"
  }
}

Errors

CodeStatusWhenWhat to do
NOT_FOUND404Send a part of an upload that does not existChange the request, then send it again.
CONFLICT409A part arrives while complete_upload (POST /v1/uploads/{uploadId}/complete) is running, or it was still arriving when complete_upload started. Send it again if the upload is still open after that.Read the resource again, then decide. Do not send the same request again.

Every call can also answer these errors. VALIDATION_FAILED, UNKNOWN_PARAMETER, UNAUTHORIZED, SCOPE_MISSING, PAYLOAD_TOO_LARGE, RATE_LIMITED, INTERNAL, UNAVAILABLE.

Cost

No credits are used.

Questions

Can I send the parts in parallel?

Yes. Parts can arrive in any order and at the same time; each one is written in its own place in the file.

What do I do when a part fails?

Send the same part again. A part that did not arrive whole is not in receivedParts, and sending it again replaces whatever arrived before.

How do I know the size of the last part?

It is sizeBytes minus partSizeBytes times (partCount minus 1): the bytes left after the full parts.

View as Markdown