VOD Upload

How do I offer my customers the ability to upload a video?

This guide covers the upload flows the Dacast API supports today. For a single file, pick ajax, cURL, or multipart, request credentials from the API, then push the file to storage. To import many objects already in your own S3 bucket, use bulk upload from S3. Encoding is asynchronous: the file is not playable the moment the upload HTTP call returns.

📘

All examples use https://developer.dacast.com as the API host. Authenticate with X-Api-Key and send X-Format: default. JSON request bodies must include Content-Type: application/json.

Which upload method should I use?

Methodupload_type / endpointsBest forHow you get the VOD id
AjaxPOST /v2/vod with "upload_type": "ajax"Browser file picker; signature and list/poll on your serverNot in the init response. Find the VOD in the list (see below).
cURLPOST /v2/vod with "upload_type": "curl"Server-side uploads of typical file sizesInit returns an id and a signed curl-command. Do not treat the init id as the final VOD id - resolve it from the list after the PUT.
Multipart/v2/vod/upload/init-multipart, /signatures/multipart, /complete-multipartLarge files (including > 5 GB)complete-multipart returns vod_id.
Bulk from S3POST /v2/bulk-uploadsMany files already in your S3 bucketPoll the job; each success becomes a VOD (see below).

Ajax and cURL go through Create Video. Multipart is a separate three-endpoint flow: Initiate, Get presigned URLs, Complete. Bulk from S3: Bulk upload, Lookup, List.

For a browser upload product you typically need a file selector in the page, a backend route that calls POST /v2/vod and returns the signature JSON, and browser code that POSTs the file to S3. Title, description, splashscreen, and thumbnail can be set after the VOD exists.


Ajax: browser upload to storage

Use ajax when the file picker lives in the browser, but every call to developer.dacast.com runs on your server. The browser never sends X-Api-Key: anything in front-end JavaScript can be read from the page (view source, DevTools, browser extensions), so a key there could be copied and used outside your app. Keep the key on your server only. Your backend requests the S3 form signature, returns that JSON to the page, and the browser POSTs the file to storage.

🚧

Do not call POST /v2/vod from client-side JavaScript with your API key. See Common Issues - Call developer.dacast.com from your server.

1. Request an upload signature (your server)

From your backend - not the browser page:

curl -X POST "https://developer.dacast.com/v2/vod" \
  -H "X-Api-Key: insertYourApiKeyHere" \
  -H "X-Format: default" \
  -H "Content-Type: application/json" \
  -d "{\"source\":\"yourFileNameHere.mp4\",\"upload_type\":\"ajax\",\"auto_encoding\":true}"

Return the JSON response to your front end (for example from your own /upload/init route as { "fields": { … } }).

Useful body fields (see Create Video):

  • source - the filename being uploaded (required).
  • upload_type - "ajax".
  • auto_encoding - start encoding after the file lands in storage.
  • callback_url - optional. If set, Dacast POSTs file_id and title to that URL when processing finishes. A callback is not required; you can poll the API instead.

A successful response looks like:

{
  "acl": "private",
  "bucket": "upload.dacast.com",
  "key": "vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748",
  "policy": "…",
  "success_action_status": "201",
  "x-amz-algorithm": "AWS4-HMAC-SHA256",
  "x-amz-credential": "AKIA…/20211104/us-east-1/s3/aws4_request",
  "x-amz-date": "20211104T102930Z",
  "x-amz-signature": "ad538afc…"
}
🚧

This response is not a VOD record. There is no usable video id here. The last segment of key is also not the final VOD id.

2. POST the file from the browser to storage

In the browser - no API key on this step. Use the signature fields your server returned in step 1.

Host is https://{bucket} from those fields. Do not send bucket as a form field.

Send every other signature field, then file last. Include x-amz-algorithm. A successful upload typically returns 201 (success_action_status).

curl -X POST "https://{bucket}" \
  --form "key=vod/b21c25ef-1d75-9789-6a92-d8ba13c53a86/none/9f5becc4-7db9-e49f-646a-14e198ddd748" \
  --form "acl=private" \
  --form "success_action_status=201" \
  --form "policy=…" \
  --form "x-amz-algorithm=AWS4-HMAC-SHA256" \
  --form "x-amz-credential=AKIA…/20211104/us-east-1/s3/aws4_request" \
  --form "x-amz-date=20211104T102930Z" \
  --form "x-amz-signature=ad538afc…" \
  --form "file=@localfilename"
// `fields` is the signature JSON from your server (step 1)
const formdata = new FormData();
formdata.append('key', fields.key);
formdata.append('acl', fields.acl);
formdata.append('success_action_status', fields.success_action_status);
formdata.append('policy', fields.policy);
formdata.append('x-amz-algorithm', fields['x-amz-algorithm']);
formdata.append('x-amz-credential', fields['x-amz-credential']);
formdata.append('x-amz-date', fields['x-amz-date']);
formdata.append('x-amz-signature', fields['x-amz-signature']);
formdata.append('file', fileInput.files[0]); // must be last

fetch('https://' + fields.bucket, { method: 'POST', body: formdata })
  .then((response) => {
    // expect 201
  });

3. Resolve the VOD id and wait until it is online (your server)

Back on your server - list and poll with your API key. Indexing can lag (up to 60s). After upload, list title matches the source filename. Filter list by that name and pick the newest row:

curl "https://developer.dacast.com/v2/vod?page=1&per_page=25&title=yourFileNameHere.mp4" \
  -H "X-Api-Key: insertYourApiKeyHere" \
  -H "X-Format: default"

Then:

  1. Take id from the matching item (filter by creation_date if several files share the same name).
  2. Poll Lookup video until online is true and renditions are present. Encoding is not finished when the S3 POST returns.
  3. Set a display name (and other metadata) with Update video: PUT /v2/vod/{id}.

If you passed callback_url, Dacast will POST multipart/form-data with file_id and title when processing completes. Treat that as a convenience, not as the only way to learn the id.


cURL: server-side upload

Use this when the file is already on your server and you want a signed PUT.

1. Request a signed upload command

curl -X POST "https://developer.dacast.com/v2/vod" \
  -H "X-Api-Key: insertYourApiKeyHere" \
  -H "X-Format: default" \
  -H "Content-Type: application/json" \
  -d "{\"source\":\"yourFileNameHere.mp4\",\"upload_type\":\"curl\"}"

Response shape:

{
  "curl-command": "curl -T yourFileNameHere.mp4 'https://…presigned…'",
  "id": "5f62bc1f-6c9e-c9d0-b985-2ac2e8f70924",
  "url": "https://…presigned…"
}
🚧

Generate a fresh curl-command for every upload. Reusing a signed URL fails authentication.

The id in this response is not reliably the final VOD id. After the file PUT, find the asset with List videos (filter by the source filename) the same way as ajax.

2. PUT the file

Run the returned curl-command (or PUT to url) with the real file path in place of the placeholder. The signed request uses the PUT verb, not a form POST.

If the generated command omits Content-Type, add one that matches the file (for example video/quicktime for .mov).

3. Resolve the VOD id

Same as ajax: list by the source filename, then poll lookup until the video is online.


Multipart: large files

Use multipart for large videos (required above 5 GB). Storage is chosen server-side (today this may be Wasabi or AWS). Always PUT to the presigned URLs you receive - do not hardcode upload.dacast.com.

Full reference: Initiate, Get presigned URLs, Complete.

Rules

  • Each part must be at least 5 MB, except the last part.
  • At most 100 part signatures per signatures call. Request another range if the file has more parts.
  • Upload parts with PUT. Save the ETag header from each response (keep the quotes if storage returned them).

1. Initiate

curl -X POST "https://developer.dacast.com/v2/vod/upload/init-multipart" \
  -H "X-Api-Key: insertYourApiKeyHere" \
  -H "X-Format: default" \
  -H "Content-Type: application/json" \
  -d "{\"filename\":\"yourFileNameHere.mp4\"}"

You get s3_path and uploader_id. Optional: destination_folders_ids, recipe_id.

2. Request presigned URLs

curl -X POST "https://developer.dacast.com/v2/vod/upload/signatures/multipart" \
  -H "X-Api-Key: insertYourApiKeyHere" \
  -H "X-Format: default" \
  -H "Content-Type: application/json" \
  -d "{\"from_part_number\":1,\"to_part_number\":4,\"s3_path\":\"s3://…\",\"uploader_id\":\"…\"}"

Response: { "presigned_urls": [ "https://…", "https://…" ] }.

3. PUT each part and collect ETags

curl -i -X PUT --data-binary @part_1.bin "https://presigned-url-for-part-1"

Read ETag from the response headers.

4. Complete

curl -X POST "https://developer.dacast.com/v2/vod/upload/complete-multipart" \
  -H "X-Api-Key: insertYourApiKeyHere" \
  -H "X-Format: default" \
  -H "Content-Type: application/json" \
  -d "{\"s3_path\":\"s3://…\",\"uploader_id\":\"…\",\"ordered_etags\":[\"etag-part-1\",\"etag-part-2\"]}"

Response: { "vod_id": "bd91b7d4-50aa-4a20-9326-db4f21c1e77b" }.

Encoding can still take time after complete. Poll Lookup video until renditions are ready.


Bulk from S3

Use this when the files already live in an S3 bucket you control. Create a job with Bulk upload (upload_type: s3 plus bucket, region, and IAM keys with ListBucket + GetObject), then poll Lookup bulk upload until COMPLETED or FAILED.

Object keys currently imported are those ending in .mp4 or .mp3. While the job runs, status may stay STARTED with counters at "0" until it finishes - keep polling. Successful imports appear in List videos; encoding can still continue after the job completes.


After the video exists

Store the VOD id (and your end-user id, if this is a multi-tenant CMS). Then: