24. APIs and Idempotency
1
The picture to keep in your head2
24.1 What is an API contract?3
24.2 What are the main API styles?4
24.3 How do you version an API?5
24.4 How does pagination work (offset vs cursor)?6
24.5 How should errors and status codes work?7
24.6 How does API auth work, in one page?8
24.7 What is the double-charge problem?9
24.8 How do idempotency keys work?10
24.9 How do you retry safely?11
24.10 How do webhooks work?12
Memory card and where the analogy breaks13
Practice: five levels14
Interview questions15
Solutions16
Sources17
Code lab24. APIs and Idempotency
Practice: five levels
3 min read+10 XP
Assignments
Five levels. Do them in order. Answers are in "Solutions" at the end, so try first.
Level 1: Think (no code)
A. Which status code? One line each.
- The request body is missing the required
amountfield. - The access token has expired.
- User 7 asks for user 9's order.
- The order was already paid by another request.
- The client has sent 200 requests in the last minute and the limit is 100.
- The payment service can't reach the bank right now.
B. Safe to retry automatically? One line each.
GET /orders/881timed out.POST /chargestimed out, with no idempotency key.POST /chargesreturned 503, with an idempotency key.PUT /books/42returned 502.POST /ordersreturned 422.
Level 2: Calculate
- Checkout makes 1,000 payment calls a minute; 0.5% of replies are lost and the client retries once without an idempotency key. How many double charges a day?
- A client pages through orders with offset pagination, 50 per page. How many rows does the database read and discard to serve page 2,000?
- The payment API stores each idempotency key with a 1 KB response for 24 hours, at 2 million payments a day. Roughly how much storage?
- Retries use full-jitter backoff capped at 0.5, 1, 2, 4 and 8 seconds. What's the longest a client could wait in total across those five retries?
- Four layers each retry a failing call 3 times (4 attempts each). How many calls reach the bottom service for one user action?
Level 3: Build
In Python:
- A
PaymentsAPI withcharge(no key) andcharge_with_keythat claims a key first, replays stored responses, returns 409 while in progress and 422 on a mismatched body, and expires keys after 24 hours. offset_pageandcursor_page, and a test that inserts a new row between pages.problem(status, title, detail)returning an RFC 9457-style body, andshould_retry(method, status, has_key).issue_key()andcheck_key()that store only a hash and compare in constant time.- A webhook
sign/verifywith a timestamp tolerance, and a receiver that de-duplicates by event ID.
Level 4: Debug
Despite idempotency keys, a few customers were still charged twice, always when the mobile app retried quickly after a slow network. The payment service:
python
- Explain exactly how two requests with the same key both charge.
- Fix it.
Level 5: Design
Design the bookstore's public Orders API for partner apps and the bookstore's own mobile app: list a user's orders, get one order, create an order (which charges the card), and notify partners when an order ships.
Deliver:
- The endpoints, methods and main fields, and which style (REST, gRPC, GraphQL) for which client.
- Pagination for "list orders".
- Error format and the main status codes.
- How "create order" is made safe to retry end to end (app → bookstore → payment provider).
- How partners are notified of shipments, and how they verify and de-duplicate those notifications.