Skip to main content

Idempotency and retries

Networks fail mid-request. The dangerous case is a timeout: you don't know whether the server rendered the document. Retry blindly and you may issue it twice; give up and you may not have issued it at all. Idempotency keys remove the dilemma.

How it works

Send an Idempotency-Key header (1–128 printable characters, unique per logical operation) on any POST:

curl -o notice.pdf "https://api.pdfs.ecourtdate.com/v1/templates/$TEMPLATE_ID/generate" \
-H "x-api-key: $API_KEY" \
-H "Idempotency-Key: notice-2026-CV-1042-r1" \
-H "Content-Type: application/json" \
-d '{ "data": { "client_name": "Jordan Smith", "hearing_date": "2026-08-15" } }'
  • Same key, same body → replay. The original result returns with the Idempotent-Replay: true header. Nothing re-executes.
  • On generation endpoints, a replay returns the originally generated document: a retried timeout can never produce a duplicate.
  • Keys are remembered for 24 hours.

Key reuse with a different body

Reusing a key with a different body is rejected with 409 IDEMPOTENCY_KEY_REUSED, a guardrail that catches bugs where a key is accidentally shared across distinct operations. Derive keys from the logical operation, not the wall clock:

notice-<case_number>-<hearing_date> good: retries share it, distinct notices don't
notice-<timestamp> bad: every retry is a "new" operation

A retry recipe

  1. Generate one idempotency key per logical document and persist it with the work item before the first attempt.
  2. On timeout or 5xx: retry with the same key using exponential backoff with jitter (for example 1 s, 2 s, 4 s, … capped at 60 s).
  3. On 429: same, back off and retry with the same key.
  4. On 4xx other than 429: stop; the request itself is wrong (Errors).
  5. Treat Idempotent-Replay: true as success: it is the same result the original request would have returned.

Where to send it

Idempotency-Key is honored on the creating POSTs (templates, versions, copies, assets) and on every generation endpoint: generate, /v1/documents, and generate-batch (where one key protects the entire 200-item job from double submission).

Reads (GETs) and DELETE /v1/jobs/{jobId} are naturally idempotent: no key needed.