Idempotency
POST /v1/scans and POST /v1/exports do real, billable work — a duplicated request is a duplicated scan or export. The Idempotency-Key header makes retries safe: the first request with a given key executes; any replay of the same key with the same body returns the original response instead of running again.
curl https://api.regsn.app/v1/scans \
-H "Authorization: Bearer $REGSN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5f2b7c1e-0a44-4c5b-9d3e-8a1f2b3c4d5e" \
-d '{ "jurisdictions": ["UK"], "areas": ["Payments"], "horizon": 6 }'Rules
| Property | Value |
|---|---|
| Header | Idempotency-Key |
| Format | 1–255 printable ASCII characters (a UUID is the sensible choice) |
| Endpoints | POST /v1/scans, POST /v1/exports (ignored elsewhere) |
| Scope | Per API key and per endpoint — the same string used on /v1/scans and on /v1/exports names two unrelated records |
| Window | 24 hours |
| Cached | Successful (2xx) responses only |
| Optional | Yes — omit the header and the request executes normally |
The request body is fingerprinted (top-level key order does not matter). Replay behaviour depends on what matches:
| Situation | Result |
|---|---|
| Same key, same body, original succeeded | Original response replayed, with header Idempotency-Replayed: true |
| Same key, same body, original still running | 409 · idempotency_in_progress — wait and retry the same key |
| Same key, different body | 409 · idempotency_key_in_use — use a fresh key for a new request |
| Same key, original failed (non-2xx) | Not cached — the retry executes normally |
| Malformed header | 422 · invalid_idempotency_key |
Failures are not cached — by design. If your scan hit 402 budget_exhausted or a 503, retrying with the same key re-executes rather than replaying the error. You only ever “lock in” a success.
Replay in practice
# First call: executes, returns 202
curl -s -D - https://api.regsn.app/v1/exports \
-H "Authorization: Bearer $REGSN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: export-a1b2-pdf-v1" \
-d '{ "snapshot_id": "a1b2…", "provider": "internal-pdf", "artifact_type": "pdf" }'
# Identical retry (e.g. after a client timeout): same 202 body, no new job
# Response now includes:
# Idempotency-Replayed: trueCheck for the Idempotency-Replayed: true header when it matters whether work actually ran.
Recommendations
- Generate one UUID per logical operation and reuse it across retries of that operation — not per HTTP attempt.
- Deterministic keys (e.g.
nightly-scan-2026-07-20) are useful for cron-style jobs: a rerun of the same tick can never double-scan. Keep the 24-hour window in mind for schedules longer than a day. - Both SDKs auto-generate a UUID key for every
POSTwhen you do not pass one, so their internal retries are always safe. Pass your own key when retries span process restarts.
See also
- Errors — the
409/422codes above, in context. - Rate limits — pair
Retry-Afterwaits with the same key.
Last updated on