Idempotency & Retry-Safe Systems · Idempotency Keys in Practice

Request Fingerprints and Key Misuse

Detect reuse of a key with a different request.

A client bug might reuse a key for a different operation. Store a fingerprint — a hash of method, path and a canonicalized body (sorted keys, normalized numbers) — and reject mismatches with 422 instead of replaying an unrelated response. Exclude volatile fields (timestamps, tracing headers) from the fingerprint, and document which parts are included.

Fingerprint contents

Include in fingerprint Exclude
HTTP method and path Tracing headers (traceparent)
Canonical request body Client timestamps meant to vary
Query parameters that change behavior Auth token (scope covers identity)
import hashlib, json

def fingerprint(method: str, path: str, body: dict) -> str:
    canonical = json.dumps(body, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
    return hashlib.sha256(f"{method}\n{path}\n{canonical}".encode()).hexdigest()

Common pitfalls

  • Hashing raw bytes (whitespace/key order differences create false mismatches).
  • Silently replaying responses for different requests.
  • Including volatile fields so legitimate retries fail.

Key points

  • Canonicalize then hash
  • Mismatch → 422
  • Document included fields

Further reading: IETF draft: Idempotency-Key header

Practice questions

Why canonicalize JSON before hashing?

Answer

Semantically identical bodies can differ in key order or whitespace; canonicalization ensures retries produce the same fingerprint.

What status code signals reuse of an idempotency key with a different payload?

Answer

422 Unprocessable Content, per the IETF Idempotency-Key draft.

Open in the app to mark lessons complete, take notes and track your progress.