1Show the Level 1 solution
2**A.**
31. **400** (or 422 if your API uses it for validation).
42. **401.**
53. **403** (or **404**, to avoid revealing that order exists).
64. **409.**
75. **429**, with `Retry-After`.
86. **503** (or 502/504 depending on how it fails).
9
10**B.**
111. **Yes**: GET is safe.
122. **No**: it might charge twice.
133. **Yes**: the key makes it safe.
144. **Yes**: PUT is idempotent.
155. **No**: a business-rule failure; it will fail again.
1Show the Level 2 solution
21. 1,000 × 0.005 = **5** double charges a minute; × 1,440 minutes = **7,200 a day**.
32. Page 2,000 starts at offset (2,000 − 1) × 50 = **99,950** rows skipped.
43. 2,000,000 × 1 KB = **about 2 GB** held at any time (24 hours' worth), plus index overhead.
54. 0.5 + 1 + 2 + 4 + 8 = **15.5 seconds** at most (full jitter picks a random wait up to each cap).
65. 4 attempts per layer, 4 layers: 4 × 4 × 4 × 4 = **256** calls. Retry at one layer only.
1Show the Level 3 solution
2Tested solution (Python 3), the key parts:
3
4```python
5def charge_with_key(self, key, order_id, amount, now=0, ttl=86_400):
6 body_hash = hashlib.sha256(json.dumps([order_id, amount]).encode()).hexdigest()
7 rec = self.keys.get(key)
8 if rec and now - rec["at"] > ttl:
9 rec = None # expired: treat as new
10 if rec:
11 if rec["hash"] != body_hash:
12 return 422, {"error": "idempotency key reused with different parameters"}
13 if rec["status"] == "in_progress":
14 return 409, {"error": "a request with this key is still in progress"}
15 return rec["code"], rec["response"] # replay
16 self.keys[key] = {"hash": body_hash, "status": "in_progress", "at": now} # claim first
17 code, resp = 201, self._do_charge(order_id, amount)
18 self.keys[key].update(status="done", code=code, response=resp)
19 return code, resp
20
21
22def cursor_page(rows, after_id, limit):
23 if after_id is None:
24 return rows[:limit]
25 return [r for r in rows if r < after_id][:limit]
26
27
28def should_retry(method, status, has_key):
29 if status not in {408, 429, 500, 502, 503, 504}:
30 return False
31 return method in {"GET", "PUT", "DELETE", "HEAD", "OPTIONS"} or has_key
32
33
34def verify(secret, timestamp, payload, signature, now, tolerance=300):
35 if abs(now - timestamp) > tolerance:
36 return False # too old: possible replay
37 expected = hmac.new(secret, f"{timestamp}.{payload}".encode(), hashlib.sha256).hexdigest()
38 return hmac.compare_digest(expected, signature)
39```
40
41All checks pass: two charges without a key and one with it; 422 for a reused key with a different amount; 409 while in progress; a new charge after 24 hours; the v1 client breaks on v2's price; offset pagination repeats order 91 while cursors don't; API keys verify only from their hash; POST without a key isn't retried; webhooks reject forged and stale deliveries and apply a retried one once. The full file is in `code/ch24_apis.py`.
1Show the Level 4 solution
2**The race:**
31. Request A arrives with key `checkout-883`. `db.get` finds nothing. A calls the card network (2 seconds).
42. The app times out and retries. Request B arrives with the **same key**. A hasn't saved anything yet, so `db.get` finds nothing. B calls the card network too.
53. Both charges go through. Both save the key. The customer pays twice. The tested demo reproduces this.
6
7**The fix:** **claim the key atomically before doing the work**, and make concurrent requests wait:
8
9```python
10def charge(key, order_id, amount):
11 body = fingerprint(order_id, amount)
12 try:
13 db.insert("idempotency", {"key": key, "body": body, "status": "in_progress"}) # UNIQUE(key)
14 except UniqueViolation:
15 rec = db.get("idempotency", key)
16 if rec.body != body:
17 return 422, "key reused with different parameters"
18 if rec.status == "in_progress":
19 return 409, "still processing; retry shortly"
20 return rec.code, rec.response # replay
21 code, response = card_network.charge(order_id, amount, idempotency_key=key)
22 db.update("idempotency", key, status="done", code=code, response=response)
23 return code, response
24```
25
26Also pass the key to the card network, so even a crash between charging and saving can't produce a second charge downstream.
1Show the Level 5 (sketch) solution
21. **REST + JSON** for partners and the mobile app (`/v1/...`); gRPC between the bookstore's internal services.
3 - `GET /v1/orders?limit=20&cursor=...`: list the caller's orders.
4 - `GET /v1/orders/{id}`: one order (authorised: it must be the caller's, or the partner's).
5 - `POST /v1/orders` with `Idempotency-Key`: body `{items: [{book_id, qty}], address_id, payment_method_id}`; returns `201` with `{id, status, total_paise, created_at}`.
62. **Cursor pagination**, newest first, opaque cursor of `(created_at, id)`, maximum limit 100.
73. **Problem Details** errors with machine codes: 400/422 validation, 401, 403 (or 404 for others' orders), 404, 409 (`order_already_paid`, `out_of_stock`), 429 with `Retry-After`, 503.
84. **End to end:** the app creates the key once per checkout attempt and stores it locally; the bookstore claims the key atomically, creates the order and an outbox entry in one transaction, and calls the payment provider **with the same key** (or one derived from the order ID); a retry at any point replays the stored result instead of creating a second order or charge.
95. **Shipment notifications:** an `order.shipped` webhook to each partner's registered URL, signed with HMAC-SHA256 over timestamp + body, with event IDs; partners verify, reject stale timestamps and de-duplicate by event ID. Deliveries are retried with backoff for a set period, with delivery logs and a "replay event" button; partners can also poll `GET /v1/orders/{id}`.