Skip to main content

Documentation

Jobs and results

Create a job

POST /v1/generations
Authorization: Bearer cv_live_YOUR_KEY
Content-Type: application/json
Idempotency-Key: 7d1c0f6e-5b0a-4a33-9f2e-0c1b2a3d4e5f

{
  "plan": "credits",
  "model": "veo-3.1",
  "params": { "prompt": "A paper boat on a rainy street", "aspect_ratio": "16:9", "duration": 8 }
}

The response is 201 with the job. A replayed request (same Idempotency-Key and body) returns 200 and the header Idempotent-Replayed: true. See Idempotency.

params takes the prompt and the options of the model (aspect_ratio, duration, resolution). Input images go in params.images as base64 (data) with the MIME type; the request body can be up to 45 MiB. GET /v1/models lists the parameters and the price table of every model.

Job states

StatusMeaningCan be cancelled
pendingAccepted and waiting in the CheapVids queue (your limit of parallel jobs is used up)Yes, refunded in full
queuedSent to the generator, waiting for a slotYes if the generator accepts, refunded in full
processingBeing generatedNo (409 not_cancellable)
completedDone, the result can be downloadedNo
failedFailed, refundedNo
cancelledCancelled, refundedNo

Each job produces exactly one result. For several variants of a prompt, create several jobs, each with its own Idempotency-Key.

While a job is not finished the response has next: { "action": "poll", "after_seconds": 5 }. Use GET /v1/generations/{id}?wait=60 (Long polling) or a webhook instead of polling in a tight loop. POST /v1/generations/{id}/cancel cancels a job that has not started running.

Download the result

CheapVids does not store the results of API jobs. It relays the file from the generator while you download, for a limited window after the job finishes.

  • output.url of a completed job is a CheapVids URL: https://api.cheapvids.com/v1/generations/{id}/content?exp=...&sig=.... It works without an API key (for example in a <video> tag) for one hour. Call GET /v1/generations/{id} again to get a fresh URL.
  • You can also call GET /v1/generations/{id}/content with your API key. Add ?download=1 for a Content-Disposition: attachment response.
  • Range is supported, one range per request (Range: bytes=0-1048575), so video players can seek. HEAD returns the total size in Content-Length.
  • The window is results.api_ttl_hours in GET /v1/account (24 hours by default) after completion, and result_expires_at on the job. After it, the endpoint answers 410 result_expired. Download as soon as the job is done.
  • If the generator no longer serves the file, you get 502 result_unavailable (retry after the Retry-After seconds).

Download limits

To keep the service fast for everyone, downloads are limited per account:

  • a few streams at the same time (429 with Retry-After: 5 when you are over),
  • a daily amount of bytes (results.download.user_gib_per_day, with used_bytes_today in GET /v1/account),
  • a number of downloads per result (results.download.job_download_multiple times the file size per day),
  • for signed URLs, a limit of requests per minute per IP address.

A download that hits a limit answers 429 rate_limited with Retry-After and details.scope set to bandwidth, job or ip. The bytes of one download count when the transfer runs, so a transfer that already started is never cut.