Genace

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

ModelCredits per clipDurationResolution
Seedance253–15s720p, 1080p
Kling355 or 10s1080p
Veo 31008s fixed720p, 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.

Continue with api fundamentals

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