Idempotency keys
Attach idempotency keys to writes so safe retries don't duplicate side effects.
Make retries on writes safe, so a replayed write settles once and never becomes
a duplicate. Add idempotency to a write stitch and each logical call carries a
stable Idempotency-Key header — when a retry replays the same write, the server
sees the same key and dedupes the side effect instead of running it twice. Reach
for it on POST/PUT where a duplicate would double-charge, double-ship, or
double-create.
Example
import { } from 'stitchapi';
// Default: a fresh random key per call, sent as 'Idempotency-Key'.
const = ({
: 'POST',
: 'https://api.example.com',
: '/charges',
: true,
});
// Custom: derive a stable key from the input. `body` is `unknown`, so narrow it.
const = ({
: 'POST',
: 'https://api.example.com',
: '/orders',
: {
: () => `order-${(. as { : string }).}`,
},
});A single charge() call generates one key and reuses it across every retry of
that call, so a network blip that triggers a retry settles a single charge.
Anti-pattern: don't lean on the default random key to dedupe two
separate submissions — a double-clicked "Pay" fires two distinct charge()
calls, each with a fresh key, so the server sees two writes and charges
twice; derive a stable keyOf from something the duplicate submissions
share (an order reference, or an id your client mints once per intent) so
both map to one key. See Reference → Config
types.
Options
header is the header name the key rides on, default 'Idempotency-Key'. Set
it when the API expects a different name ('Idempotency-Token', a vendor-prefixed
'X-Idempotency-Key'). It renames the idempotency key — the value the server
dedupes on — not a correlation or trace header like traceparent/X-Request-Id,
which identify a request for logs and spans and belong to tracing, not dedupe.
keyOf builds the key from the call's StitchInput
(params, query, body, headers, variables). The default is a random
uuid generated once per logical call; a custom keyOf lets you derive a stable
key from the request — for example an order reference — so the same logical
write maps to the same key. body is typed unknown, so narrow or cast it
before reading a property, as the createOrder example does.
Why it matters: idempotency pairs most naturally with retries —
a retried write replays the same key, so the server recognizes the duplicate and
skips the side effect, and safe retries don't double-charge. It isn't only for
retries, though: the same key also covers a duplicate the stitch never issued (a
proxy or the transport resending the request), and a derived keyOf dedupes two
separate submissions with no retry at all.
Because the random default key mostly earns its keep alongside a retry, declaring
it on a write with no retry logs a one-time construction nudge pointing you
at retry (or a derived keyOf). It's a hint, not an error — set warn: false
to silence it when the keyless-retry case (a proxy dedupe, say) is deliberate.
A custom keyOf derived from body must be stable for a given logical call
and unique across distinct ones — colliding keys make the server dedupe two
different writes into one.
See Reference → Config types for the full
IdempotencyOptions shape.