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

# Job lifecycle

> Track progress, retry safely, and know when your files are ready.

## Job states

A job normally moves through these states:

```text theme={"system"}
ingesting → transcribing → queued → rendering → completed
```

| State          | Meaning                                                          |
| -------------- | ---------------------------------------------------------------- |
| `ingesting`    | Downloading and inspecting the source video.                     |
| `transcribing` | Transcribing speech and preparing timed captions.                |
| `queued`       | Captions are ready; waiting for renderer capacity.               |
| `rendering`    | Rendering the prepared captions and uploading the video.         |
| `completed`    | Processing succeeded. Download the result files.                 |
| `failed`       | Processing stopped with an error. Reserved credits are released. |
| `canceled`     | The job was canceled. Reserved credits are released.             |

`completed`, `failed`, and `canceled` are terminal states. Stop polling when you receive one of them. The `progress` field is a percentage from 0 to 100, not an estimate of remaining time.

## Poll for results

Call [Get job](/api-reference/get-job) every five seconds. The response includes `Retry-After: 5`. If a request returns `429`, honor `Retry-After` before trying again.

Successful HTTP status does not imply successful processing: a `200` job response may contain `status: "failed"`. Inspect both the HTTP status and the job's `status`.

<Note>
  This release uses polling. Webhook callbacks are not currently supported.
</Note>

## Retry a submission safely

Every create request requires an `Idempotency-Key` of 8–128 letters, numbers, dots, colons, underscores, or hyphens.

* The same key and equivalent input return the original job with `replayed: true`.
* The same key and different input return `409 IDEMPOTENCY_CONFLICT`.
* Idempotency is shared across keys belonging to the same account.
* Replaying a failed or canceled job does not restart it. Submit with a new idempotency key to create a new job.

If the network drops after submission, retry the **same input with the same key**. Do not generate a new key merely because the first response was lost.

## Cancel a job

Call [Cancel job](/api-reference/cancel-job) for a queued or processing job. It changes to `canceled` and releases the reservation. If processing has already reached a terminal state, cancellation returns that existing state. Completed jobs remain billed.

## Retention and timeouts

Result files expire 24 hours after completion. Check `expires_at` and save all outputs to your own storage. Before expiry, fetch the job again to obtain current download URLs. After expiry the job can remain `completed`, but file URLs are `null`; fetching it again does not restore expired files.

Source ingestion, transcription and caption preparation have a ten-minute deadline. Prepared jobs waiting for renderer capacity time out after 30 minutes. Assigned renders have a one-hour ceiling. A processing failure or timeout releases the job's reserved credit; it does not automatically submit a replacement.
