Upload videos
The Partner API exposes one canonical upload flow. It is a two-step request: POST creates the video record and returns a time-limited upload target, then PUT sends the bytes to that target. The same target also accepts chunked PUTs with Content-Range for large files.
307 and the body MUST be re-sent. The upload target hands off to the worker that will store the file via an HTTP 307 Temporary Redirect. Your client must follow the redirect AND re-send the request body on the redirected request. With curl that means curl -L (curl re-sends the body on a 307; a plain PUT without-L stops at the 307 and uploads nothing). axios, fetch, and Pythonrequests follow PUT 307s and re-send the body by default. If your HTTP client drops the body on redirect (some do for 301/302), either switch to a client that preserves it on 307 or use the HEAD probe below to learn the worker URL first and PUT directly.Quickstart (curl, single PUT, ≤ 500 MB)
# 1. Create the video record + obtain the upload target.
curl -sS -X POST "https://api.dcast.pro/api/v1/videos/upload" \
-H "Authorization: Bearer {api_key}" \
-H "Content-Type: application/json" \
-d '{
"title": "My Video",
"fileName": "video.mp4",
"fileSize": 104857600,
"visibility": "PRIVATE"
}'
# Response:
{
"success": true,
"data": {
"video": { "id": "<videoId>", "status": "PREPARING", ... },
"upload": {
"url": "https://api.dcast.pro/api/v1/uploads/<token>",
"method": "PUT",
"expiresAt": "<ISO-8601 UTC>",
"maxFileSize": 115343360.00000001, // fileSize x 1.1, not rounded
"chunked": false,
"chunkSize": 99614720
},
"statusUrl": "/api/v1/videos/<videoId>/status"
}
}
# 2. PUT the bytes to data.upload.url. Workers are discovered via 307
# redirect — curl follows it with -L; axios, fetch, Python requests
# follow PUT redirects by default.
curl -sS -L -X PUT --data-binary @video.mp4 \
-H "Content-Type: video/mp4" \
"<data.upload.url>"
# Response (on success):
{
"success": true,
"data": {
"videoId": "<videoId>",
"fileSize": 104857600,
"worker": "worker-720845-de",
"status": "UPLOADED",
"complete": true
}
}
# 3. Poll processing status:
curl -sS -H "Authorization: Bearer {api_key}" \
"https://api.dcast.pro/api/v1/videos/<videoId>/status"Chunked uploads (large files)
For files larger than upload.chunkSize (95 MB by default), the same upload.url accepts standard HTTP Content-Range PUTs. Send each chunk with the byte range it covers; the server stitches them in order.
# Chunk 1 of N (bytes 0 – 99,614,719 of a 250 MB file):
curl -sS -L -X PUT \
-H "Content-Range: bytes 0-99614719/262144000" \
-H "Content-Type: video/mp4" \
--data-binary @chunk1.bin \
"<data.upload.url>"
# Continue with chunks 2..N. Each chunk's Content-Range must be contiguous;
# total size in the trailing /<total> must match the original fileSize.
# The final chunk's response carries "complete": true and the worker
# advances the video to PROCESSING.HEAD probe to skip the redirect re-send
Clients that prefer to know the worker URL up front (to avoid the body re-send cost of the 307) can issue a HEAD request to data.upload.url. The response is 307 with a Location header pointing at the actual worker; the client can then PUT directly to that URL without re-sending the body.
curl -sI "<data.upload.url>" # → 307 + Location: <worker-url>
curl -X PUT --data-binary @video.mp4 -H "Content-Type: video/mp4" "<worker-url>"Status + processing lifecycle
After the bytes land, the video moves through UPLOADED → PROCESSING → READY. Poll GET /v1/videos/{videoId}/status, or subscribe to your partner webhook for the video.upload.completed and video.processing.completed events to avoid polling.
Quota + size limits
POST /v1/videos/upload rejects with 403 QUOTA_EXCEEDED if the partner's plan is over its storage limit. fileSize in the init request must be exact; the worker enforces it on the body PUT and returns413 FILE_TOO_LARGE if exceeded. See limits for plan-by-plan caps.
Removed endpoints (2026-05-28)
The following alternative endpoints used to exist and now respond 410 Gone with a redirect note pointing here. Existing integrations using either path will start to see 410 — switch to the canonical flow above.
POST /v1/videos/{videoId}/upload(the multipart-to-API alias)POST /v1/upload/{token}(the worker-fallback alias)
For partner integrations, the canonical upload is the two-step flow above (POST /v1/videos/upload → PUT the bytes, chunked Content-Range supported, resumable by re-issuing the PUT from the last confirmed byte).
