Idempotency

Safely retry POSTs without duplicate renders.

A render costs a credit and produces a document, so a retry after a timeout must not charge twice or mail two copies of the same invoice. Send an Idempotency-Key and the first request under that key becomes authoritative: any retry replays its exact response without rendering again.

Using it

Generate one key per operation you want to happen at most once — your invoice id, order id or a UUID — and send it on every attempt of that operation.

bash
curl -X POST https://api.pixldocs.com/v1/render \
  -H "Authorization: Bearer pxd_YOUR_KEY" \
  -H "Idempotency-Key: invoice-2026-0042" \
  -H "Content-Type: application/json" \
  -d '{"template_id":"YOUR_TEMPLATE_ID","format":"pdf","data":{"total":"1,240.00"}}'

Supported on POST /v1/render, POST /v1/renders and POST /v1/renders/batch. Keys are scoped to your workspace and to a single endpoint, and expire 24 hours after first use. Maximum 255 characters — a longer key is refused with 400 invalid_idempotency_key before anything renders.

What each retry does

  • Same key, same body, first call finished — you get the stored response, byte for byte, with X-Pixldocs-Idempotent-Replay: true. No render runs and no credit is used. For an async call that means the same job id, so you never end up with two jobs.
  • Same key, first call still running — 409 idempotency_in_progress with a Retry-After. Wait and retry the same key.
  • Same key, different body — 422 idempotency_key_reuse. Nothing renders. Use a new key for a new request.
  • The first call failed — the key is released, so retrying it renders normally rather than replaying an error forever.
  • No key sent — nothing changes: every call renders and bills.
Replay is byte-identical

A replayed POST /v1/render returns the original file with its original Content-Type, not a JSON pointer to it, so retry paths need no separate branch in your code.

A JSON reply (async, or save_to_renders) replays with every value identical — same id, same url, same page count. The key order inside the object can differ, so compare fields rather than the raw string.

Seeing your retries

Every replay also carries X-Pixldocs-Idempotent-Replay-Count — how many times that key has been served from store, including the current call. A count climbing past what you expect means your client is retrying more than you think, not that we rendered more than once.

The key that produced a document is recorded on its archive row: open any render in Renders and the panel shows render_id, request_id and idempotency_key. A row with no key was sent without one, so a repeat of that call would render and bill again.

Reading the request id

http
X-Pixldocs-Request-Id: e7e25e2a-f090-4e98-85c5-01a08ba0fb5a

Present on every render response, success or failure. Store it against your own operation key — it is the id support needs to find a render. For anything billable, also consider save_to_renders: true: the render lands in your Renders history with a stable id and hosted URL you can look up instead of re-rendering. For a large job use POST /v1/renders/batch once rather than N calls with client-side retry loops.