Idempotency
Network retries are inevitable. Patomic accepts an Idempotency-Key header on any non-safe request (POST, PUT, PATCH, DELETE); duplicate requests with the same key return the original response byte-for-byte within 24 hours.
Sending the header
Section titled “Sending the header”POST /v1/keys HTTP/1.1Authorization: Bearer ptmc_…Idempotency-Key: 6c1f1a8e-3a1f-4f17-9c7b-8e3a1f4f17cfContent-Type: application/json
{"name": "CI integration", "rate_limit_rpm": 1000}A good idempotency key is:
- Per-request, not per-attempt. All retries of the same logical request share one key.
- Random and unique. A UUIDv4 is the safe default. Anything 1-255 ASCII characters is accepted.
- Stored alongside your client’s intent. If your client crashes mid-call, restart with the same key on retry.
What happens on retry
Section titled “What happens on retry”- Within 24 hours, same key, any caller using the same API key: Patomic returns the original response. The header
idempotency-replayed: trueindicates a replay. - After 24 hours: the cache has expired. The same key is treated as new — your retry proceeds and may succeed.
- 5xx responses are not cached. A transient server failure won’t sticky-fail your retries.
Constraints
Section titled “Constraints”- Header name: exactly
Idempotency-Key(case-insensitive per HTTP). - Length: 1-255 ASCII characters. Longer keys return a 400 with
code: "invalid_idempotency_key". See Errors → invalid-idempotency-key. - Scope: per-API-key. Two different
ptmc_keys using the same idempotency value never collide.
Best practice
Section titled “Best practice”import { randomUUID } from "node:crypto";
async function safeMintKey(name: string): Promise<unknown> { const idempotencyKey = randomUUID(); // Persist this BEFORE the call so a crash mid-flight is replayable. await db.put({ idempotencyKey, intent: "mint_key", name });
const res = await fetch("https://patomic-api.pedrotengelmann.workers.dev/v1/keys", { method: "POST", headers: { Authorization: `Bearer ${process.env.PATOMIC_KEY}`, "Idempotency-Key": idempotencyKey, "Content-Type": "application/json", }, body: JSON.stringify({ name }), }); return res.json();}