# Queued jobs

> Which endpoints answer 202 with a gen_… id, how to poll them, what each status means, and when a job is charged or refunded.

Work that takes longer than a request should wait is queued. The request answers **`202 Accepted`** at once with a `gen_…` id, and you poll that id until the job finishes.

```bash title="curl"
curl https://api.lumavox.ai/v1/images \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "A paper boat on a rain-soaked street"}'
```

```json title="Response — 202 (abridged)"
{
  "id": "gen_a1B2c3D4e5F6g7H8",
  "status": "queued",
  "capability": "image",
  "prompt": "A paper boat on a rain-soaked street",
  "credits_micros": 4000000,
  "image": null,
  "error": null,
  "created_at": "2026-10-24T09:30:00.000Z",
  "finished_at": null
}
```

## The queued endpoints

| Submit | Poll | Scope | Result on success |
|---|---|---|---|
| `POST /v1/images` | `GET /v1/images/{generation_id}` | `image` | `image` |
| `POST /v1/videos` | `GET /v1/videos/{generation_id}` | `video` | `video` |
| `POST /v1/audio` | `GET /v1/audio/{generation_id}` | `tts` | `audio` |
| `POST /v1/skybox` | `GET /v1/skybox/{generation_id}` | `skybox` | `skybox` |
| `POST /v1/transcriptions` | `GET /v1/transcriptions/{generation_id}` | `stt` | `transcript` |
| `POST /v1/templates/{template_id}/generate` | the poll for the template's `capability` | the template's capability | as that capability |

Every poll answers the same shape — the job, with its parameters, its `status`, and the result once there is one. The [API reference](https://docs.lumavox.ai/reference/generations.md) has every field.

## Statuses

| `status` | Means | What to do |
|---|---|---|
| `queued` | accepted, waiting to start | keep polling |
| `submitted` | handed to the provider | keep polling |
| `running` | being generated | keep polling |
| `succeeded` | finished — the result is on the response | stop; download it |
| `failed` | it did not produce anything; `error` says why | stop; it was refunded |
| `moderated` | refused by the provider's safety filter | stop; it was refunded |

`succeeded`, `failed` and `moderated` are terminal: a job never leaves them.

## Polling

Poll every couple of seconds for images and transcriptions. A video takes minutes, so poll it less often. Polls do not count against your [rate limits](https://docs.lumavox.ai/errors.md#rate-limits) — submits do.

```js title="JavaScript"
const headers = { Authorization: `Bearer ${process.env.API_KEY}` };
const RUNNING = ["queued", "submitted", "running"];

async function waitFor(capability, id, everyMs = 2000) {
  for (;;) {
    const job = await fetch(`https://api.lumavox.ai/v1/${capability}/${id}`, {
      headers,
    }).then((r) => r.json());
    if (!RUNNING.includes(job.status)) return job;
    await new Promise((resolve) => setTimeout(resolve, everyMs));
  }
}

const job = await waitFor("images", "gen_a1B2c3D4e5F6g7H8");
```

An id from another capability, or from another organisation, is a **404** — each poll reads only its own capability's jobs. `GET /v1/generations/{generation_id}` reads any of them.

## The result

On `succeeded`, the result is under the capability's name — `image`, `video`, `audio`, `skybox` or `transcript`. Each carries:

- **`url`** — a short-lived link to the file, made fresh on every response and never stored. Download it promptly; read the job or the asset again for a new one.
- **`asset_id`** — the same file in your [library](https://docs.lumavox.ai/library/assets.md), kept until you delete it. Fetch it from there later.

The capability's own page says what else its result holds — a video's duration, a skybox's preview, a transcript's text.

## Charged when accepted, refunded on failure

A queued job is **charged when it is accepted**, not when it finishes: the `202` response's `credits_micros` is what was debited, in micro-credits ([Conventions](https://docs.lumavox.ai/conventions.md#credits)). Each capability's endpoint says what its price depends on — megapixels for an image and each of its references, seconds and resolution for a video, characters for stored audio, one flat price for a skybox.

- **A job that fails, or is refused by the safety filter, is refunded in full.**
- **A transcription is charged an estimate, then corrected** to the audio's measured length when it finishes.
- **A job that stops reporting is settled for you.** It ends `failed`, is refunded, and its `error` says it was not charged — within about six hours of when you submitted it.

Checking your balance before a batch is cheaper than learning from a `402`: see [credits and usage](https://docs.lumavox.ai/usage.md).

Some capabilities limit how much may be in flight. You may only have so many unfinished videos at once; over that, `POST /v1/videos` answers **429** and charges nothing.

## Finding jobs again

`GET /v1/generations` lists every job your organisation has submitted, newest first, in flight or finished — filtered to the capabilities your key holds. It is how you get back an id you lost: a submit that timed out on your side may still have been accepted.

```bash title="curl"
curl "https://api.lumavox.ai/v1/generations?status=running&limit=50" \
  -H "Authorization: Bearer $API_KEY"
```

| Query | What it does |
|---|---|
| `capability` | one of `image`, `video`, `tts`, `stt`, `skybox` |
| `status` | one of the statuses above |
| `limit` | 1 to 100 a page; 30 by default |
| `cursor` | the previous page's `next_cursor` |

The answer is a page — `data`, and `next_cursor`, which is `null` on the last page ([Conventions](https://docs.lumavox.ai/conventions.md#lists-and-pages)). [Generations](https://docs.lumavox.ai/library/generations.md) covers the listing in full.

## Related

- [Images](https://docs.lumavox.ai/media/images.md), [Video](https://docs.lumavox.ai/media/videos.md), [Skyboxes](https://docs.lumavox.ai/media/skyboxes.md), [Templates](https://docs.lumavox.ai/media/templates.md)
- [Stored audio](https://docs.lumavox.ai/speech/stored-audio.md), [Transcription](https://docs.lumavox.ai/speech/transcription.md)
- [Errors and limits](https://docs.lumavox.ai/errors.md)
