Skip to content

DocsGet started

Files

Upload private inputs and download job outputs with expiring links.

Use publicly reachable http or https input URLs on the default port, or upload a private file first. A *.workers.dev address is not supported as an input URL. Outputs are private in storage. The API serves them through signed links; anyone holding a link can use it until expiry.

Upload an input#

Create an upload with your API key. Send the exact byte length and a plain filename:

bash
size=$(wc -c < input.mp4 | tr -d ' ')
upload=$(curl --fail-with-body "$VIDEXO_API_URL/v1/uploads" \
  -H "Authorization: Bearer $VIDEXO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"filename\":\"input.mp4\",\"size_bytes\":$size,\"content_type\":\"video/mp4\"}")
curl --fail-with-body -X PUT "$(printf '%s' "$upload" | jq -r .upload_url)" \
  -H 'Content-Type: video/mp4' --data-binary @input.mp4

POST /v1/uploads returns id, input_url, upload_url, upload_url_expires_at, expires_at and max_size_bytes. The PUT response confirms size_bytes, the computed sha256 and content_type. Wait for a successful PUT before creating a job. Use the returned input_url:

JSON
{
  "input_files": { "in_video": "videxo://uploads/up_0123456789abcdef01234567" },
  "output_files": { "out_main": "clip.mp4" },
  "command": "-i {{in_video}} -c copy {{out_main}}"
}

An app or a web page uploads without your API key through a client token.

The upload belongs to the account that created it. Another account cannot use it. The URL accepts one PUT, must be fully sent within one hour and needs no API key. After an interrupted or failed PUT, create a new upload. The same completed upload can be used by several jobs until it expires.

Uploads expire 24 hours after creation, even if a job has not started reading them. Submit jobs early enough to read the input before it expires. Missing, incomplete or expired uploads are rejected as 404 not_found (reason upload) when creating a job, or input_unreachable if they expire while the job waits.

Direct upload limits#

A direct upload is at most 100 MB (100,000,000 bytes), and no larger than your plan's total input limit. The transferred byte length must match size_bytes and fit the upload limit: a larger file returns 413 limit_exceeded (reason upload_size), and a body of another length returns 400 invalid_request (reason size_mismatch). A request body over 100 MB can also return a 413 response that is not JSON. For larger inputs, provide a publicly reachable URL.

Uploading and downloading do not spend credits. Reading an upload as a job input counts bytes exactly like fetching a URL. All inputs together must fit the plan's per-job input limit.

Download outputs#

Every job output includes download_url and download_url_expires_at, in the job API, lists, MCP job tools and webhook payloads. A link lasts up to one hour and never beyond the output's expires_at. Deleted or expired outputs have both link fields set to null.

Use a valid API key to get a fresh link and follow its redirect:

bash
location=$(curl --fail-with-body -sS -D - -o /dev/null \
  "$VIDEXO_API_URL/v1/jobs/$job_id/outputs/out_main" \
  -H "Authorization: Bearer $VIDEXO_API_KEY" | sed -n 's/^[Ll]ocation: //p' | tr -d '\r')
curl --fail-with-body "$location" -o clip.mp4

Or read the job again and use outputs[].download_url without sending your API key. Signed links support a single HTTP byte range (Range: bytes=0-1023, open-ended and suffix ranges), ETag, If-None-Match and If-Range. Files download as attachments with their original filename and content type. Responses use private, no-store caching so deletion is checked on each request.

A bad signature is 403 permission_denied (reason link_invalid), an expired link or retention is 410 resource_expired (link_expired or file_expired), a missing or deleted object is 404 not_found (file), and an invalid range is 416 invalid_request (range_not_satisfiable). Refreshing a link does not restore a deleted or expired file. DELETE /v1/jobs/{id}/files invalidates the job's output links immediately and deletes its objects.

Signed PUT URLs support browser CORS without credentials. Reserve the upload on your backend, then give only its one-time URL to the browser. Keep the API key on your backend.