Partner API base path is /api/v1 on https://api.dcast.pro. This site documents the live surface; use the Quickstart QA curls to validate keys and routes.

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.

Gotcha — the PUT step returns 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).

Upload videos — dcast.pro API docs