# Task lifecycle and recovery

[HTML](https://pdfcraft.ai/en/docs/api/lifecycle/) · [Site index](https://pdfcraft.ai/llms.txt)

Task states, concurrency limits, expiry and recovery after interruptions.


Save the `uuid` returned when you create the task, along with the launch parameters. You will need them to recover interrupted work. Upload and download links expire and cannot replace the task ID.

## States

```text
waiting_for_upload → running → succeeded | failed | cancelled
```

| State | Meaning | Next action |
| --- | --- | --- |
| `waiting_for_upload` | Created but not launched; the file may already be uploaded | Fetch upload URLs, upload if needed, then launch |
| `running` | Launch accepted; work may still be queued | Poll with backoff |
| `succeeded` | Result is available while the task remains accessible | Request fresh download URLs |
| `failed` | Processing ended with an error | Read the task's `error.code` |
| `cancelled` | Task was cancelled | Stop polling |

The API currently has no cancel or delete endpoint.

## Recover after an interrupted request

| Interrupted operation | Recovery |
| --- | --- |
| Create, with no confirmed `uuid` | Inspect waiting tasks; check before creating another task |
| Upload | Fetch upload URLs again. `get_url` and `head_url` mean the file is uploaded; `put_url` means it still needs uploading |
| Launch | GET the task; if necessary repeat launch with the same parameters |
| Poll | Keep the `uuid` and resume GET with bounded backoff |
| Download | Request new download URLs while the task is accessible |

Uploaded files cannot be replaced. Create a new task for a different source. Repeating an accepted launch with identical normalized parameters returns the existing resource, including after failure; it never restarts failed work. Changed parameters return `409 TRANSFORM_ALREADY_LAUNCHED`.

## Concurrent conversions

Each user can have at most **3 `running` tasks**, counting PDF and EPUB together. Accepted work that is waiting for a worker still occupies a slot. Creation and file upload do not occupy a slot.

If you receive `409 TRANSFORM_CONCURRENCY_LIMIT`, the task has not started and remains `waiting_for_upload`. The uploaded file is kept, and the expiry time is unchanged.

Check the running list at intervals and retry launch when another task finishes. You can reuse the same task, provided it has not expired.

## Lists and pagination

Use the [list endpoints](https://pdfcraft.ai/en/docs/api/overview/#list-tasks) to recover work across sessions. Waiting includes uploaded files that have not been launched. Running includes queued tasks. Finished includes successful, failed and cancelled tasks.

The response contains `transforms` and, when another page exists, `next_cursor`. Pass that value unchanged as `cursor` to the same list. Lists are not snapshots: tasks can move between lists while you paginate. There is no total count.

## Retention and expiry

The service sets task expiry. Use the returned `expires_at`; timestamps in documentation examples are illustrative.

Accepting a launch request clears the upload deadline. A request rejected because of the concurrency limit keeps its original deadline. Recently finished tasks may initially have no `expires_at`; the service can set one later as more tasks finish.

Polling does not extend retention. Once a task expires, queries return `404` and it disappears from lists, even if the files have not yet been deleted.

Download and save your results promptly, including when `expires_at` is absent.

## Failed work

Read `GET /transforms/{uuid}` for `error.code` and `error.message`. Observation only supplies the status and optional progress/preview. Correct the cause before creating a new task; see [errors and retry decisions](https://pdfcraft.ai/en/docs/api/error-handling/).
