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

# Async Jobs & Polling

> Create asynchronous media jobs, poll public TokenLab task status, and reconcile final results without provider-specific IDs.

Many media endpoints are asynchronous. A create request starts work and returns a public TokenLab task identity; your application polls until that task reaches a terminal status. Do not build customer workflows around upstream task URLs, routing IDs, or provider callback behavior.

## Public Task Contract

Create responses can include:

| Field      | Meaning                                               | What to do                                      |
| ---------- | ----------------------------------------------------- | ----------------------------------------------- |
| `id`       | Public TokenLab task ID                               | Store it with your own job record               |
| `task_id`  | Compatibility alias for the same public task identity | Treat it as equivalent to `id`                  |
| `status`   | Current public task status                            | Start polling when it is not terminal           |
| `poll_url` | Preferred status URL                                  | Use this first when present                     |
| `model`    | Model requested or resolved by the endpoint           | Store it for support and billing reconciliation |

`/v1/tasks/{id}` is the canonical fixed status endpoint for public async media jobs. Media-specific status routes may exist for compatibility, but new integrations should prefer `poll_url` or `/v1/tasks/{id}`.

## Recommended Flow

1. Validate the user request and send the create call with an explicit `model`.
2. Persist `id` / `task_id`, `poll_url`, endpoint, model, user ID, and your own job ID before returning control to the UI.
3. Poll every `5-10s` for long-running media tasks.
4. Stop only when the task is `completed` or `failed`.
5. On `completed`, read the media-specific result fields and store final URLs or metadata.
6. On `failed`, store the public error and offer retry only as a new user-visible job.

```json theme={null}
{
  "id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "task_id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "status": "pending",
  "poll_url": "/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "model": "veo3.1"
}
```

## Polling Example

```bash theme={null}
curl "https://api.tokenlab.sh/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
  -H "Authorization: Bearer sk-your-api-key"
```

Expected public statuses are `pending`, `processing`, `completed`, and `failed`. Cancelled tasks are represented as `failed` with `cancelled: true` and `cancellation_status: "cancelled"` so older status handling keeps working.

## Client Retry Rules

Network timeouts are the most common source of duplicate jobs. Use this rule:

| Where timeout happens                         | Safer behavior                                                        |
| --------------------------------------------- | --------------------------------------------------------------------- |
| Before your server receives a create response | Check server logs for `request_id`; retry only if no task was created |
| After a create response was stored            | Resume polling the stored `task_id`                                   |
| During polling                                | Retry the status request with backoff                                 |
| After terminal status                         | Do not poll again unless the user explicitly refreshes the record     |

Do not send a second create request just because the browser refreshed or a status poll failed.

## Billing And Settlement

Async jobs can reserve an estimated amount when the create request is accepted. Final settlement happens after terminal status. When available, task status responses can expose `billing_transaction_id` and the `X-Billing-Transaction-ID` header.

For reconciliation, join these identifiers in your logs:

* `request_id` from the create request.
* `task_id` / `id` from the task.
* `billing_transaction_id` when present.
* Your own user ID, project ID, or job ID.

## Cancellation

`DELETE /v1/tasks/{id}` is intentionally narrow. It currently supports queued Volcengine Seedance video tasks such as `seedance-1.5-pro`, `seedance-2.0`, and `seedance-2.0-fast`.

Unsupported tasks return `400 unsupported_task_cancel`. Tasks that are already running or terminal return `409 task_not_cancellable`. Build cancellation UI as "request cancellation" rather than a guaranteed stop button.

## Troubleshooting

| Symptom                      | Likely cause                                                                       | What to check                                                     |
| ---------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `async_task_not_found`       | Task is unknown, expired, inaccessible to this API key, or not a public async task | Confirm API key ownership and the stored public `task_id`         |
| Task never appears to finish | Client keeps polling the wrong URL or stopped before terminal status               | Use `poll_url` or `/v1/tasks/{id}` and inspect the latest status  |
| Final media URL missing      | Task is not completed, or the upstream job completed without usable output         | Keep polling until terminal, then handle missing output as failed |
| User sees duplicates         | Retry path created a new task after timeout or refresh                             | Deduplicate by your own job ID and stored `task_id`               |
| Billing mismatch             | Settlement is async or client is comparing provider IDs                            | Compare `request_id`, `task_id`, and `billing_transaction_id`     |

## Support Packet

When contacting support, include `request_id`, `task_id`, `billing_transaction_id` when present, endpoint, model, timestamp, and a sanitized request shape. Do not include API keys, private media, signed URLs, or full prompts unless support asks for a redacted sample.

## API Reference

| Topic             | Reference                                               |
| ----------------- | ------------------------------------------------------- |
| Get Task Status   | [Get Task Status](/api-reference/tasks/get-task-status) |
| Cancel Task       | [Cancel Task](/api-reference/tasks/cancel-task)         |
| Image Generation  | [Image Generation](/guides/image-generation)            |
| Video Generation  | [Video Generation](/guides/video-generation)            |
| Music Generation  | [Music Generation](/guides/music-generation)            |
| 3D Generation     | [3D Generation](/guides/3d-generation)                  |
| Billing & Pricing | [Billing & Pricing](/guides/billing)                    |
