> ## Documentation Index
> Fetch the complete documentation index at: https://docs.routerbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Async Tasks

> Video and audio generations are asynchronous. Here's how to retrieve results.

## Sync vs Async

| Endpoint                      | Mode                                                                    |
| ----------------------------- | ----------------------------------------------------------------------- |
| `POST /v1/chat/completions`   | **Sync** — response contains the result.                                |
| `POST /v1/images/generations` | **Sync** — connection held until the image is ready (typically 5–30 s). |
| `POST /v1/videos/generations` | **Async** — returns `{id, status:"pending"}`; poll or use a callback.   |
| `POST /v1/audio/speech`       | **Async** — same shape as video.                                        |
| `POST /v1/audio/generations`  | **Async** — same shape as video.                                        |

This page covers the **async flow** used by video and audio.

## Submit → Poll Pattern

1. `POST /v1/videos/generations` (or `/v1/audio/*`) returns `{ id, status: "pending" }` immediately.
2. `GET /v1/videos/generations/{id}` (or `/v1/audio/generations/{id}`) returns the same object with an updated `status`. When `status == "success"`, `data[].url` is populated.

```
pending  ──►  success
         ╲
          ╲►  failed
```

| `status`  | Meaning                                        |
| --------- | ---------------------------------------------- |
| `pending` | Task is queued or generating                   |
| `success` | Generation complete; `data[].url` is populated |
| `failed`  | Generation failed                              |

## Option 1 — Polling

Call the GET endpoint repeatedly until status is terminal.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://routerbase.com/v1/videos/generations/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
    -H "Authorization: Bearer sk-rb-xxxxxxxxxxxx"
  ```

  ```python Python theme={null}
  import time, requests

  def wait_for_video(gen_id, api_key, interval=3, timeout=600):
      headers = {"Authorization": f"Bearer {api_key}"}
      url = f"https://routerbase.com/v1/videos/generations/{gen_id}"
      elapsed = 0
      while elapsed < timeout:
          s = requests.get(url, headers=headers).json()
          if s["status"] == "success":
              return s["data"][0]["url"]
          if s["status"] == "failed":
              raise RuntimeError("Generation failed")
          time.sleep(interval)
          elapsed += interval
      raise TimeoutError("Generation timed out")
  ```

  ```javascript JavaScript theme={null}
  async function waitForVideo(genId, apiKey, { interval = 3000, timeout = 600000 } = {}) {
    const url = `https://routerbase.com/v1/videos/generations/${genId}`;
    const start = Date.now();
    while (Date.now() - start < timeout) {
      const r = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
      const s = await r.json();
      if (s.status === "success") return s.data[0].url;
      if (s.status === "failed") throw new Error("Generation failed");
      await new Promise((r) => setTimeout(r, interval));
    }
    throw new Error("Generation timed out");
  }
  ```
</CodeGroup>

**Recommended polling cadence:** every 3–5 seconds. Most video generations complete in 1–5 minutes.

## Option 2 — Callback URL

Skip polling by including `callback_url` in your `POST`. RouterBase will `POST` the final result to that URL when the task completes.

```bash theme={null}
curl -X POST https://routerbase.com/v1/videos/generations \
  -H "Authorization: Bearer sk-rb-xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bytedance/seedance-2-0",
    "prompt": "A sunset over the ocean",
    "callback_url": "https://your-app.example.com/webhooks/routerbase"
  }'
```

### Callback request body

Success:

```json theme={null}
{
  "task_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "success",
  "result_urls": ["https://media.routerbase.com/media/<user>/<gen>/0.mp4"],
  "error_message": null
}
```

Failure:

```json theme={null}
{
  "task_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "fail",
  "result_urls": [],
  "error_message": "Generation failed: …"
}
```

### Callback security

* Your `callback_url` **must be HTTPS in production**.
* Internal / private network URLs (`localhost`, `127.0.0.1`, `10.0.0.0/8`, `192.168.0.0/16`, `172.16.0.0/12`, cloud-metadata IPs) are blocked to prevent SSRF.
* The callback is fire-and-forget: there are no automatic retries today, so make your webhook handler idempotent.

<Tip>
  Callbacks eliminate the need for polling and reduce latency for long-running tasks like video generation (typically 1–5 minutes).
</Tip>

## Result URLs

When R2 storage is configured, RouterBase rehosts upstream provider URLs on its own CDN — links don't expire. When R2 is not configured, you receive the upstream provider's temporary URL directly (these expire, typically within 24 hours).

## Typical Generation Times

| Modality         | Typical Time         |
| ---------------- | -------------------- |
| Chat / LLM       | 2–30 seconds (sync)  |
| Image generation | 10–60 seconds (sync) |
| Video generation | 1–5 minutes (async)  |
| Audio TTS        | 5–30 seconds (async) |

Times vary by model and provider load.

## Dropped connections

If your connection drops before the POST response delivers the generation
`id`, the task may still exist (and complete) server-side. Supply an
`Idempotency-Key` so you can recover it or retry safely — see
[Idempotency](/essentials/idempotency).
