API generate video: the full request and response, end to end
The request
curl -X POST https://genace.ai/api/v1/video/generations \
-H "Authorization: Bearer $GENACE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.0-fast",
"prompt": "a cyclist on a coastal road at golden hour, camera tracking alongside",
"duration_sec": 3
}'
Both snake_case and camelCase are accepted for field names.
The response is a job
{
"job_id": "abc123",
"state": "queued",
"model": "seedance-2.0-fast",
"credits_held": 25
}
202 Accepted. The render takes minutes; credits_held is what was reserved
and comes back in full if the job fails or you cancel it.
Collecting the output
curl "https://genace.ai/api/v1/jobs/abc123?wait=30" \
-H "Authorization: Bearer $GENACE_API_KEY"
On success:
{
"job_id": "abc123",
"state": "succeeded",
"outputs": [{ "url": "https://...", "type": "video" }]
}
The two that surprise people
A failed job is a 200. It describes a failure in the body, so
raise_for_status() and equivalents will not fire. Check state.
Both 429s need opposite handling. Rate limiting clears with time;
concurrency clears only when one of your own jobs finishes. Retrying blindly
helps in one case and spins in the other. Branch on error.code.
Choosing a model
| Model | Credits per clip | Duration | Resolution |
|---|---|---|---|
| Seedance | 25 | 3–15s | 720p, 1080p |
| Kling | 35 | 5 or 10s | 1080p |
| Veo 3 | 100 | 8s fixed | 720p, 1080p |
Duration control usually decides this more than price does — AI video API duration limits.
A working Python implementation with the polling loop is in how to generate video with an API in Python.
Models covered on this page
Where these facts come from
- codebase: src/ai/providers/*.ts — every pricing() and paramsSchema
- codebase: src/ai/api/quota.ts — per-tier ceilings
- codebase: src/app/api/v1/video/generations/route.ts — request and response shape