Skip to content

Uploads

The Uploads API lets you push large files (multi-hundred-MB videos, multi-GB clips) by splitting them into ≤ 64 MB parts. Each part is uploaded against an upload session; calling complete assembles them into a regular File object you can reference in inference requests via file_id.

Fully compatible with the OpenAI Uploads API — the official openai SDK’s client.uploads.upload(...) helper drives the entire sequence in one call.

POST /v1/uploads
POST /v1/uploads/{upload_id}/parts
POST /v1/uploads/{upload_id}/complete
POST /v1/uploads/{upload_id}/cancel
ConstraintValue
Total file size8 GB
Per-part size≤ 64 MB
Session lifetime1 hour from creation
Allowed purposesvideo (recommended). vision works but rarely needed at this size.

Sessions that aren’t completed within 1 hour are automatically cancelled. The completed file inherits the standard 30-day expiry from the Files API.

The easiest path is the OpenAI SDK’s high-level helper, which handles chunking for you:

from openai import OpenAI
client = OpenAI(
api_key="sk-your-api-key",
base_url="https://api.aiand.com/v1",
)
with open("clip.mp4", "rb") as f:
upload = client.uploads.upload(
file=f,
purpose="video",
filename="clip.mp4",
mime_type="video/mp4",
)
print(upload.file.id) # → file-vid789...

The SDK splits your file into parts, opens a session, uploads each part, and calls complete. The returned upload.file.id is a regular file-... id you can use in chat completions exactly like any other file.

If you’re not using the SDK, here’s the same flow against the raw HTTP endpoints.

POST /v1/uploads
FieldTypeRequiredDescription
filenamestringYesOriginal filename
purposestringYesvision or video
bytesintegerYesTotal declared size of the file
mime_typestringYesMime type; checked against the purpose’s allowlist
Terminal window
curl https://api.aiand.com/v1/uploads \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"filename": "clip.mp4",
"purpose": "video",
"bytes": 524288000,
"mime_type": "video/mp4"
}'
{
"id": "upload-abc123",
"object": "upload",
"bytes": 524288000,
"purpose": "video",
"filename": "clip.mp4",
"status": "pending",
"created_at": 1719450000,
"expires_at": 1719453600,
"file": null
}
POST /v1/uploads/{upload_id}/parts

Multipart form upload with a single data field. Each part must be ≤ 64 MB. Parts are submitted in the order returned to the client; out-of-order completion is not supported.

Terminal window
curl https://api.aiand.com/v1/uploads/upload-abc123/parts \
-H "Authorization: Bearer sk-your-api-key" \
-F "data=@clip.part1.bin"
{
"id": "part-xyz789",
"object": "upload.part",
"upload_id": "upload-abc123",
"created_at": 1719450010
}

Repeat until every chunk of the source file has been submitted, capturing each part.id in order.

POST /v1/uploads/{upload_id}/complete
FieldTypeRequiredDescription
part_idsstring[]YesOrdered list of part.ids from step 2
md5stringNoOptional MD5 of the assembled file
Terminal window
curl https://api.aiand.com/v1/uploads/upload-abc123/complete \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{ "part_ids": ["part-xyz789", "part-uvw456", "part-rst123"] }'
{
"id": "upload-abc123",
"object": "upload",
"bytes": 524288000,
"purpose": "video",
"filename": "clip.mp4",
"status": "completed",
"created_at": 1719450000,
"expires_at": 1719453600,
"file": {
"id": "file-vid789",
"object": "file",
"bytes": 524288000,
"purpose": "video",
"filename": "clip.mp4",
"created_at": 1719450090,
"expires_at": 1722042090
}
}

The file.id is now a regular file you can reference in chat completions.

POST /v1/uploads/{upload_id}/cancel

Aborts a pending session. Idempotent — already-completed or already-cancelled sessions return 404.

Terminal window
curl -X POST https://api.aiand.com/v1/uploads/upload-abc123/cancel \
-H "Authorization: Bearer sk-your-api-key"

Once complete returns a file.id, use it like any other file:

{
"model": "<video-capable-model>",
"messages": [{
"role": "user",
"content": [
{ "type": "text", "text": "Describe what happens in this clip." },
{ "type": "file", "file": { "file_id": "file-vid789" } }
]
}]
}

See Files → Reference a file in chat completions for full examples.

Statuserror.codeWhen
400invalid_request_errorMissing field, unknown purpose, mime not in allowlist, declared bytes exceeds the per-purpose cap, part body > 64 MB, part_ids empty or contains an id from a different upload
400invalid_request_errorAdding a part to an upload that’s no longer pending, or whose session has expired
401invalid_api_keyMissing or invalid Authorization header
404not_foundUnknown upload_id, or id belongs to a different organization
500server_errorInternal failure
  • Upload sessions and resulting files are scoped to the organization that created them.
  • Each part is durably stored as soon as it’s accepted — if your client crashes mid-upload, you can resume by listing your existing part_ids (kept until session expiry) and continuing.
  • The model must have a matching capability for the file’s purpose. purpose: "video" requires a video-capable model — see GET /v1/models.