Skip to main content

Video API solution

Turn a prompt or a still frame into finished video.

Video is the most expensive thing most products generate and the slowest to come back. Three fields in the body decide both numbers, and the job keeps running long after the request that started it has gone.

The challenge

What makes video different from every other task

A video request is not a slower image request. Duration, resolution and the audio switch set what you pay and how long you wait, and they do it before a single frame exists.

01

Duration and resolution are price dials, not presets

Most video endpoints bill per output second at the selected resolution. Moving duration_seconds from 5 to 10 roughly doubles the charge, and a resolution step does it again. Both are marked as price-affecting in the endpoint schema, so the estimate belongs next to the control, not on the invoice.

02

Generated audio is a different rate

Where generate_audio exists it is a boolean that moves the request onto another rate. A form that hides it will quietly ship the more expensive version of every request.

03

The HTTP response is not the video

createTask answers 202 Accepted with a taskId in queued state. Generation continues server-side for minutes. Anything waiting on the original socket times out while the task, and the charge, carry on.

The approach

Price the request first, then submit it once

Quote the exact body with POST /api/v1/jobs/quote, show the returned estimate, then send the same body to createTask with quoteId, expectedCost and a stored Idempotency-Key. A price that moved between the two calls fails with business code 40901 instead of turning up later as a surprise.

One create call carries the model, the validated input and an optional callback. HTTP 202 means accepted, not finished.

POST /api/v1/jobs/createTask

POST /api/v1/jobs/createTask
Authorization: Bearer $SPICY_API_KEY
Idempotency-Key: 7b1f0c2e-9a4d-4f31-8c67-2b5e0d9a1c44
Content-Type: application/json
{
  "model": "<publisher>/<model>/text-to-video",
  "input": {
    "prompt": "A slow aerial drift over a misty pine forest at sunrise",
    "duration_seconds": 5,
    "resolution": "1080p",
    "generate_audio": true
  },
  "callBackUrl": "https://example.com/hooks/spicyapi"
}

202 Accepted

HTTP/1.1 202 Accepted
Location: /api/v1/jobs/recordInfo?taskId=job_01k3m8x9q2z4v7n5p6r8s0t1w3

{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_create",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "state": "queued",
    "estimatedCost": "0.750000"
  }
}

Contract

The parts worth pinning down

Generative video API: compare, test, integrate — The parts worth pinning down
Field or headerValue or limit
POST /api/v1/jobs/createTask202 Accepted · state queued
duration_seconds · resolution · generate_audioprice-affecting fields
Idempotency-Key24 h · scoped to one API key
output.assets[].expiresAtsigned URL · results kept 14 days

Swipe horizontally to see all columns.

Integration

From first call to production

  1. 01Pick the endpoint on its model page and copy the exact model value; the task suffix is part of it.
  2. 02Quote the body you intend to send, and render estimatedCost, quantity and unit next to the submit control.
  3. 03Submit from your backend with an Idempotency-Key, store data.taskId with your own record, and answer your client immediately.
  4. 04Finish on the signed callback, fall back to recordInfo with exponential backoff, and download the asset before its URL expires.

Fit

When this path is the right one

Choose this when

  • You need finished video files — ads, trailers, loops, social cuts — and can accept minutes of latency per clip.
  • Duration, resolution and audio have to be user-controlled, and every combination has to be priced before the user commits.

Look elsewhere when

  • You need an answer inside one request cycle. Text models stream; video does not.
  • You expect to cancel mid-generation. An accepted task runs to a terminal state and only the unused hold comes back.

Evidence

What you can verify yourself

Every field comes from the published schema

The form on each model page is generated from that endpoint's input_schema, and the server validates against the same document. A field the model does not declare returns 400 rather than being dropped.

The estimate is a cap, not a guess

createTask reserves the estimate and returns it as cost with settled: false. The final charge never exceeds the hold, and a failed or expired task releases it in full.

Every key carries its own spending ceiling

Cap a key by day, by month and for its lifetime, restrict it to named models and source IPs, and send every write with the same idempotency key.

Before launch

Platform behaviour to confirm

  • Confirm the endpoint is callable today; availability is published per endpoint, not per family.
  • Store taskId and the Idempotency-Key together, outside the browser session.
  • Verify the callback signature before reading the body, and treat deliveries as repeatable.
  • Copy finished media into your own storage; generated results are retained for 14 days.

FAQ

Questions this page gets asked

It depends on the endpoint, the requested duration and the current queue, which is why the API is asynchronous. Treat the 202 as the end of your request, and the callback or a bounded poll as the end of the job. There is no synchronous video endpoint.