5. Big files (> 100 MB)
POST /jobs/upload sends the file through the CDN, which caps request bodies at
~100 MB. Anything larger goes straight to storage first, and then you submit
the job by URL instead of by file — two steps instead of one:
# 1. get the file into storage (one of the two ways below) → you get a `url`
# 2. submit it by URL:
curl -s https://mp.dvocorp.com/api/v1/jobs/api \
-H 'X-Api-Key: ca_live_...' -H 'Content-Type: application/json' \
-d '{"service_slug":"clipconvert","operation_key":"compress",
"params":{"file_url":"<url from step 1>","level":"medium"}}'
Then poll GET /jobs/{id} exactly as before.
Both upload methods return { url, name, content_type, kind }; url is what
goes in params.file_url.
Option A — single presigned PUT (simplest):
curl -s https://mp.dvocorp.com/api/v1/uploads/presign \
-H 'X-Api-Key: ca_live_...' -H 'Content-Type: application/json' \
-d '{"filename":"clip.mp4","content_type":"video/mp4"}'
# -> {"put_url":"https://...signed...","url":"https://.../clip.mp4", ...}
curl -X PUT "<put_url>" -H 'Content-Type: video/mp4' --data-binary @clip.mp4
Option B — multipart (adds per-part retry and parallelism; what the web UI
uses). Hard cap: MAX_UPLOAD_GB, default 3 GB. Part size 64 MB, up to
10 000 parts.
# 1. create
curl -s https://mp.dvocorp.com/api/v1/uploads/multipart/create \
-H 'X-Api-Key: ca_live_...' -H 'Content-Type: application/json' \
-d '{"filename":"movie.mp4","size":2147483648,"content_type":"video/mp4"}'
# -> {"key":"tmp/<token>/movie.mp4","upload_id":"...","part_size":67108864}
# 2. sign one URL per part (1..10000)
curl -s https://mp.dvocorp.com/api/v1/uploads/multipart/sign-part \
-H 'X-Api-Key: ca_live_...' -H 'Content-Type: application/json' \
-d '{"key":"tmp/<token>/movie.mp4","upload_id":"...","part_number":1}'
# 3. PUT each slice and KEEP the ETag response header
curl -si -X PUT "<url>" --data-binary @part-0001.bin | grep -i etag
# 4. complete
curl -s https://mp.dvocorp.com/api/v1/uploads/multipart/complete \
-H 'X-Api-Key: ca_live_...' -H 'Content-Type: application/json' \
-d '{"key":"tmp/<token>/movie.mp4","upload_id":"...","content_type":"video/mp4",
"parts":[{"part_number":1,"etag":"\"<etag1>\""}]}'
# on failure — free the stored parts (204)
curl -s -X POST https://mp.dvocorp.com/api/v1/uploads/multipart/abort \
-H 'X-Api-Key: ca_live_...' -H 'Content-Type: application/json' \
-d '{"key":"tmp/<token>/movie.mp4","upload_id":"..."}'
Both presigned modes need S3/R2 storage. On local-disk deployments
multipart/create returns 501 — fall back to POST /uploads.
R2 bucket CORS (needed for browser uploads): allow
PUTandGETfrom your site origins and exposeETag—AllowedMethods: ["PUT","GET"],AllowedHeaders: ["*"],ExposeHeaders: ["ETag"]. WithoutExposeHeadersthe browser cannot read each part's ETag and the upload aborts.