# Video Generation

> Submit async video generation jobs via /v1/videos/generations and poll for completion. Routed through Together AI to Sora, Veo, Kling, Wan, Seedream, and Vidu.

Canonical: https://ai-gateway.sassmaker.com/docs/videos

:::caution[Beta — pending upstream stabilization]
Video submission works end-to-end, but Together's public polling endpoint for generations is currently undocumented and the gateway's `GET /v1/videos/generations/{id}` may return `404` while Together's API surface is in flux. Track `x_gateway.provider` + the returned `id` and retry polling once upstream stabilizes. Treat this endpoint as **beta**.
:::

## Endpoints

```
POST /v1/videos/generations            # submit job
GET  /v1/videos/generations/{id}       # poll status
```

Video generation is asynchronous. The submit call returns immediately with a job `id` and a `poll_url`; the client polls until `status` is `completed` (or `failed`).

## Submit Request

| Field | Type | Default | Description |
|---|---|---|---|
| `model` | string | `"auto"` | Video model (see [Providers](https://ai-gateway.sassmaker.com/docs/videos#providers)). Use `"auto"` for health-aware routing. |
| `prompt` | string | required | Text description. 1–8000 chars. |
| `duration_seconds` | number | provider default | 1–60 seconds. Most models cap at 4–10s on free tier. |
| `aspect_ratio` | string | `"16:9"` | One of `"16:9"`, `"9:16"`, `"1:1"`. |
| `image_url` | string | — | Public HTTPS image URL for image-to-video models (Wan 2.6, Wan 2.2 I2V). |
| `project_id` | string | — | Body-level project tag. Alternative to `x-gateway-project-id` header. |

### Required Header

| Header | Required | Description |
|---|---|---|
| `Authorization: Bearer <GATEWAY_API_KEY>` | yes | Gateway API key. |
| `x-gateway-project-id` | yes (or body `project_id`) | 1–64 chars `[a-zA-Z0-9._:-]`. |

## Providers

All video models currently route through **Together AI** (`TOGETHER_API_KEY` required).

| Model ID | Upstream Model | Capabilities |
|---|---|---|
| `sora-2` | `openai/sora-2` | Text-to-video |
| `veo-3-audio` | `google/veo-3.0-audio` | Text-to-video with audio |
| `veo-3-fast-audio` | `google/veo-3.0-fast-audio` | Faster Veo 3 variant with audio |
| `veo-2` | `google/veo-2.0` | Text-to-video |
| `kling-2.1-master` | `kwaivgI/kling-2.1-master` | High-quality Kling |
| `kling-2.1-pro` | `kwaivgI/kling-2.1-pro` | Kling pro tier |
| `kling-2.0-master` | `kwaivgI/kling-2.0-master` | Previous-gen Kling |
| `kling-1.6-pro` | `kwaivgI/kling-1.6-pro` | Kling 1.6 |
| `wan-2.6-image` | `Wan-AI/Wan2.6-image` | Image-to-video |
| `wan-2.2-i2v` | `Wan-AI/Wan2.2-I2V-A14B` | Image-to-video |
| `vidu-q1` | `vidu/vidu-q1` | Text-to-video |
| `seedream-3` | `ByteDance-Seed/Seedream-3.0` | ByteDance Seedream |
| `seedream-4` | `ByteDance-Seed/Seedream-4.0` | ByteDance Seedream v4 |

Daily free-tier limits are tight (typically 10–30 requests per model per day). See [`GET /v1/models`](https://ai-gateway.sassmaker.com/models) for the live enabled list.

## Submit Response

**Status `202 Accepted`** when the job is queued, or `200 OK` if the provider happens to return a finished job synchronously.

```json
{
  "id": "job_abc123",
  "status": "processing",
  "poll_url": "/v1/videos/generations/job_abc123",
  "x_gateway": {
    "provider": "together",
    "model": "openai/sora-2",
    "attempts": 1,
    "request_id": "req_xyz",
    "project_id": "my_project"
  }
}
```

## Poll Response

```json
{
  "id": "job_abc123",
  "status": "completed",
  "video_url": "https://cdn.example/video.mp4",
  "x_gateway": {
    "provider": "together",
    "model": "openai/sora-2",
    "attempts": 1,
    "request_id": "req_poll1",
    "project_id": "my_project"
  }
}
```

`status` is one of `"processing"`, `"completed"`, `"failed"`. When failed, `error` contains the upstream message.

## Examples

### Submit



### curl

```bash
curl https://ai-gateway.sassmaker.com/v1/videos/generations \
  -H "Authorization: Bearer <GATEWAY_API_KEY>" \
  -H "x-gateway-project-id: my_project" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "sora-2",
    "prompt": "A slow aerial drone shot over a misty mountain lake at dawn",
    "duration_seconds": 5,
    "aspect_ratio": "16:9"
  }'
```


### JavaScript

```js
const res = await fetch('https://ai-gateway.sassmaker.com/v1/videos/generations', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <GATEWAY_API_KEY>',
    'x-gateway-project-id': 'my_project',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'sora-2',
    prompt: 'A slow aerial drone shot over a misty mountain lake at dawn',
    duration_seconds: 5,
    aspect_ratio: '16:9',
  }),
});

const job = await res.json();
console.log('Job ID:', job.id, 'Status:', job.status);
```



### Poll until complete

```js
const BASE = 'https://ai-gateway.sassmaker.com';

async function pollUntilDone(jobId, { interval = 5000, timeout = 300_000 } = {}) {
  const deadline = Date.now() + timeout;
  while (Date.now() < deadline) {
    const res = await fetch(`${BASE}/v1/videos/generations/${jobId}`, {
      headers: { 'Authorization': 'Bearer <GATEWAY_API_KEY>' },
    });
    const body = await res.json();
    if (body.status === 'completed') return body.video_url;
    if (body.status === 'failed') throw new Error(body.error ?? 'job failed');
    await new Promise((r) => setTimeout(r, interval));
  }
  throw new Error('poll timeout');
}

const videoUrl = await pollUntilDone('job_abc123');
console.log(videoUrl);
```

### Image-to-video (Wan)

```bash
curl https://ai-gateway.sassmaker.com/v1/videos/generations \
  -H "Authorization: Bearer <GATEWAY_API_KEY>" \
  -H "x-gateway-project-id: my_project" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan-2.2-i2v",
    "prompt": "Camera pans right as clouds roll in",
    "image_url": "https://example.com/source-frame.jpg",
    "duration_seconds": 4
  }'
```

## Error Codes

| Status | `code` | Meaning |
|---|---|---|
| 400 | `invalid_project_id` | Missing/invalid `project_id`. |
| 404 | — | Job ID unknown, or upstream poll endpoint returned 404 (see beta caveat above). |
| 502 | `provider_error` | Submit or poll failed at upstream. |
| 503 | `no_video_provider` | `TOGETHER_API_KEY` not configured. |
