# Video Generation

> Generate videos from text or images asynchronously, with optional audio, resolution and aspect-ratio control.

- Canonical: https://tchavi.com/en/docs/video-generation

---


<Endpoint method="POST" path="/v1/videos/generations" />

Video generation runs asynchronously: the endpoint returns a `202` with a `job.id` immediately, and the video renders in the background. Poll `GET /v1/jobs/:id` (see [Async Jobs](/en/docs/jobs)) until `status` becomes `completed` or `failed`. The SDK's `createAndWait(...)` helper does both in one call.

Billing is per second of output, resolution-dependent: **480p = 260 cr/sec** · **720p = 580 cr/sec**. A typical 10-second 480p clip costs 2,600 credits. If a job fails after billing (upstream error, timeout), the charged credits are automatically refunded.

## Parameters

| Parameter              | Type     | Required | Description                                                                                              |
| ---------------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------- |
| `model`                | string   | Yes      | `seedance-2` (ByteDance Seedance 2.0) or `kling-v3` (Kuaishou Kling V3).                                 |
| `prompt`               | string   | Yes      | Text description of the scene and motion.                                                                |
| `duration`             | integer  | No       | Seconds, 1–15. Use `-1` for auto (billed at 10s). Default `5`.                                           |
| `resolution`           | string   | No       | `"480p"` or `"720p"`. Default `"480p"`.                                                                  |
| `aspect_ratio`         | string   | No       | `16:9`, `9:16`, `1:1`, `4:3`, `3:4`, or `adaptive`. Default `"16:9"`.                                    |
| `generate_audio`       | boolean  | No       | Synthesize a soundtrack (dialogue, SFX, music). Default `true`.                                          |
| `seed`                 | integer  | No       | Fixes output for reproducibility.                                                                        |
| `image_url`            | string   | No       | First-frame reference (HTTP URL). Enables image-to-video.                                                |
| `last_frame_image_url` | string   | No       | Last-frame target. Requires `image_url`.                                                                 |
| `reference_images`     | string[] | No       | Up to 9 URLs. Mutually exclusive with `image_url`. Referenced in the prompt as `[Image1]`, `[Image2]`, … |
| `reference_videos`     | string[] | No       | Up to 3 URLs (combined ≤ 15 s). Referenced as `[Video1]`, …                                              |
| `reference_audios`     | string[] | No       | Up to 3 URLs. Requires `image_url` or `reference_images`. Referenced as `[Audio1]`, …                    |

## Example

<CodeTabs>

```tchavi
import Tchavi from '@tchavi/sdk';

const client = new Tchavi({ apiKey: 'YOUR_API_KEY' });

// One-liner: submit + poll until completed/failed
const job = await client.videos.generations.createAndWait({
  model: 'seedance-2',
  prompt: 'A cinematic shot of the Cotonou Amazone statue at golden hour',
  duration: 5,
  resolution: '480p',
  aspect_ratio: '9:16',
  generate_audio: true,
});

if (job.status === 'completed') {
  console.log('Video URL:', job.output?.video_url);
  console.log('Credits used:', job.tchavi?.credits_used);
} else {
  console.error('Failed:', job.error?.message);
}
```

```javascript
// 1. Submit — returns { id, status: 'processing', ... }
const submission = await fetch('https://tchavi.com/api/v1/videos/generations', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer YOUR_API_KEY',
  },
  body: JSON.stringify({
    model: 'seedance-2',
    prompt: 'A cinematic shot of the Cotonou Amazone statue at golden hour',
    duration: 5,
    resolution: '480p',
    aspect_ratio: '9:16',
  }),
}).then((r) => r.json());

// 2. Poll every 5s until the job is done
let job;
do {
  await new Promise((r) => setTimeout(r, 5000));
  job = await fetch(`https://tchavi.com/api/v1/jobs/${submission.id}`, {
    headers: { Authorization: 'Bearer YOUR_API_KEY' },
  }).then((r) => r.json());
} while (job.status === 'pending' || job.status === 'processing');

console.log(job.status, job.output?.video_url);
```

```python
import requests, time

submission = requests.post(
    "https://tchavi.com/api/v1/videos/generations",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer YOUR_API_KEY",
    },
    json={
        "model": "seedance-2",
        "prompt": "A cinematic shot of the Cotonou Amazone statue at golden hour",
        "duration": 5,
        "resolution": "480p",
    },
).json()

while True:
    time.sleep(5)
    job = requests.get(
        f"https://tchavi.com/api/v1/jobs/{submission['id']}",
        headers={"Authorization": "Bearer YOUR_API_KEY"},
    ).json()
    if job["status"] in ("completed", "failed"):
        break

print(job["status"], job.get("output", {}).get("video_url"))
```

```curl
# Submit
curl -X POST https://tchavi.com/api/v1/videos/generations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "model": "seedance-2",
    "prompt": "A cinematic shot at golden hour",
    "duration": 5,
    "resolution": "480p"
  }'

# Poll (replace JOB_ID with the id from the submission response)
curl https://tchavi.com/api/v1/jobs/JOB_ID \
  -H "Authorization: Bearer YOUR_API_KEY"
```

</CodeTabs>

