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

# Errors, idempotency, and retries

> Recover interrupted work without submitting a duplicate job.

Keep the HTTP status and the server's error body. The error code is useful for application handling; the message provides context. Do not assume every non-2xx response is JSON: gateways can return text errors.

| Response                   | Typical handling                                                                                        |
| -------------------------- | ------------------------------------------------------------------------------------------------------- |
| `400`                      | Correct the request or unsupported options.                                                             |
| `401`, `403`               | Check credentials and permissions.                                                                      |
| `404`, `410`               | Check the ID and whether content expired or was deleted.                                                |
| `409`                      | Inspect the code: idempotency conflict, claimed input, or pinned content may require different actions. |
| `429`, `502`, `503`, `504` | Consider a bounded retry where the operation is safe to replay. Honor `Retry-After`.                    |

See each endpoint's response schema for its documented errors.

## Idempotency

Send `Idempotency-Key` on uploads, prompt/conversion creation, webhook creation, and manual webhook-delivery retry. Repeating the same operation with the same key and body can replay it; changing the body returns a conflict. Response header `Idempotent-Replayed: true` identifies a replay.

Use nonempty printable ASCII keys without spaces. Ordinary creation keys allow up to 200 characters; webhook creation/retry keys allow 128. Keep upload and job keys distinct. New encryption public keys change the request body and therefore need a new operation key.

Do not blindly retry cancel/resume actions or generate a fresh key after an ambiguous submission failure. If you know the job ID, retrieve that job. If the submission response was lost, replay the identical request with its original key. A failed download is not a reason to create another paid job.

## TypeScript recovery

```ts theme={null}
import { ReviseClient, Source, ReviseWorkflowError } from "@reviseio/api";

const revise = new ReviseClient({ apiKey: process.env.REVISE_API_KEY! });
try {
  const pdf = await revise.convert(
    Source.fromText("# Report", { filename: "report.md" }),
    "pdf",
    { idempotencyKey: "report-42", timeoutMs: 120_000 },
  );
  const bytes = await pdf.bytes({ signal: AbortSignal.timeout(60_000) });
} catch (error) {
  if (error instanceof ReviseWorkflowError) {
    console.error(error.recovery.jobId, error.recovery.stage);
    // Persist recovery securely to resume this operation.
  }
  throw error;
}
```

Helpers derive `:upload` and `:prompt`/`:convert` keys from a base of at most 192 characters. `onProgress` provides keys, IDs, and the latest receipt synchronously; it cannot await durable storage. Use low-level methods when persistence must complete between network steps.

The client retries HTTP `429/502/503/504` on GET, DELETE, and supported keyed POST calls, with two additional attempts by default. It honors Retry-After and caps the delay at 60 seconds; longer advice is surfaced rather than retried early. Transport exceptions and body-read failures are not automatically retried.

`ReviseWorkflowError` preserves recovery plus its cause. `ReviseApiError` exposes status, code, body, and headers; `ReviseArtifactError` describes integrity failures; `SourceError` describes source resolution failures. Lazy output reads happen after the workflow: retain the returned Source and its receipt to retry reading without resubmitting.
