Tatkal API architecture: every call behind one Tatkal ticket

Every call behind one Tatkal ticket: a login past the rate limit, a cached search, the Aadhaar OTP, UPI's signed callback, then berths from PRS or a waitlist.

Berths confirmed

  1. Here’s one Tatkal booking, call by call. At ten, the app sends Rajat’s login, and the load balancer hands it to Gateway 2.
  2. The gateway checks the rate limit first: a count per user, in Redis. A script past the limit gets a four twenty-nine.
  3. Then Auth checks his password and the CAPTCHA, and signs a session token.
  4. The app gets the token. Rajat is logged in.
  5. He searches for his train. This time the load balancer picks Gateway 3, which checks his token and asks Search.
  6. Search answers from the Redis cache, so PRS is asked only on a miss: 3A, twelve available.
  7. He books two berths, with an idempotency key. Gateway 1 passes it to Booking, which asks Identity for an Aadhaar check.
  8. UIDAI texts a code to his linked mobile, and the app is told: enter the OTP.
  9. Rajat sends the code. It lands on Gateway 3, and that’s fine: any copy can serve him.
  10. Booking has Identity check it with UIDAI, which answers only yes or no, never his Aadhaar details.
  11. Verified. Booking asks Payment to charge 6,900 rupees, under the same key, so a retry can never charge him twice.
  12. Payment sends a UPI request. Rajat approves it, and the bank’s signed callback, never the phone, says paid.
  13. Only now does Booking ask PRS for two berths. Each train has one writer, so requests for 12627 go one at a time.
  14. Berths are left, so two are his: B3, 33 and 36, with a PNR.
  15. The ticket goes back to the app, and Booking publishes Ticket Booked to Kafka, so the SMS follows.
  16. Twenty-six calls: a rate limit, a token any copy can trust, a cached search, and one writer per train.

Every call, in order

  1. Rajat → API Gateway: POST /login — { user: rajat_k91, password, captcha } · 10:00:00 · bot manager → LB → Gateway 2 (REST · HTTPS)
  2. API Gateway → API Gateway: rate limit — Redis INCR rl:rajat_k91 → 1 this minute · past the limit: 429 (Internal RPC)
  3. API Gateway → Auth: check password + CAPTCHA — rajat_k91 (Internal RPC)
  4. Auth → API Gateway: token tk_9f — signed · any gateway copy can check it (reply, Internal RPC)
  5. API Gateway → Rajat: 200 · logged in — { token: tk_9f } (reply, REST · HTTPS)
  6. Rajat → API Gateway: GET /trains?from=SBC&to=NDLS — tomorrow · TATKAL · Bearer tk_9f · LB → Gateway 3 (REST · HTTPS)
  7. API Gateway → Search: availability · 12627 — token checked · Gateway 3 keeps no session (Internal RPC)
  8. Search → API Gateway: 3A · AVL 12 — Redis cache hit · PRS only on a miss (reply, Internal RPC)
  9. API Gateway → Rajat: 200 · 3A AVL 12 — { 12627 KARNATAKA EXP · 3A: AVL 12 · 2A: WL 9 } (reply, REST · HTTPS)
  10. Rajat → API Gateway: POST /bookings — { 12627, 3A, TATKAL, Rajat + DK } · Idempotency-Key: bk_51 · LB → Gateway 1 (REST · HTTPS)
  11. API Gateway → Booking: start bk_51 — token checked (Internal RPC)
  12. Booking → Identity: send Aadhaar OTP — UIDAI texts a code to ••••4821 (Internal RPC)
  13. Identity → Booking: otp sent — { txn: ua_77 } (reply, Internal RPC)
  14. Booking → API Gateway: enter OTP — { booking: bk_51, txn: ua_77 } (reply, Internal RPC)
  15. API Gateway → Rajat: 202 · enter OTP — the code comes by SMS (reply, REST · HTTPS)
  16. Rajat → API Gateway: POST /bookings/bk_51/otp — { txn: ua_77, otp: •••••• } · LB → Gateway 3 (REST · HTTPS)
  17. API Gateway → Booking: verify OTP — bk_51 (Internal RPC)
  18. Booking → Identity: check OTP — { txn: ua_77 } → UIDAI (Internal RPC)
  19. Identity → Booking: verified — UIDAI: yes · no Aadhaar details shared (reply, Internal RPC)
  20. Booking → Payment: charge ₹6,900 — Idempotency-Key: bk_51 · a retry never charges twice (Internal RPC)
  21. Payment → Payment: UPI collect → approved — rajat@okicici approves in his UPI app · the bank’s signed callback, verified (Internal RPC)
  22. Payment → Booking: paid — pay_51 · ₹6,900 captured (reply, Internal RPC)
  23. Booking → PRS: allocate 2 berths — one writer · 12627 · tomorrow · 3A (Internal RPC)
  24. PRS → Booking: CNF B3 33, 36 — 12 left → 10 · PNR 4521876390 (reply, Internal RPC)
  25. Booking → API Gateway: PNR 4521876390 — + TicketBooked → Kafka → Notification → SMS (reply, Internal RPC)
  26. API Gateway → Rajat: 200 · CNF B3 33, 36 — { PNR: 4521876390 } · the SMS follows (reply, REST · HTTPS)

Sold out · waitlist

  1. Here’s a Tatkal booking that comes too late. Keep an eye on the berths. Rajat searches for his train.
  2. Search answers from the Redis cache: 3A, two available.
  3. He books both of them, and passes the Aadhaar check.
  4. Booking asks Payment to charge 6,900 rupees. He approves it, and the bank’s signed callback says paid.
  5. Only now does Booking ask PRS. Its one writer takes requests in order, and the two just ahead of his took the last two berths.
  6. The cache said available; PRS decides. He gets the Tatkal waitlist: seven and eight.
  7. The app gets his ticket, waitlisted. If it’s still waitlisted when the chart is prepared, it’s cancelled and refunded on its own.
  8. Fourteen calls, and no berth sold twice.

Every call, in order

  1. Rajat → API Gateway: GET /trains?from=SBC&to=NDLS — logged in · Bearer tk_9f · LB → Gateway 3 (REST · HTTPS)
  2. API Gateway → Search: availability · 12627 — token checked (Internal RPC)
  3. Search → API Gateway: 3A · AVL 2 — Redis cache · seconds old (reply, Internal RPC)
  4. API Gateway → Rajat: 200 · 3A AVL 2 — { 12627 KARNATAKA EXP · 3A: AVL 2 } (reply, REST · HTTPS)
  5. Rajat → API Gateway: POST /bookings + OTP — Rajat + DK · Aadhaar verified by UIDAI · Idempotency-Key: bk_51 (REST · HTTPS)
  6. API Gateway → Booking: book bk_51 — Aadhaar verified (Internal RPC)
  7. Booking → Payment: charge ₹6,900 — Idempotency-Key: bk_51 (Internal RPC)
  8. Payment → Payment: UPI collect → approved — rajat@okicici · the bank’s signed callback, verified (Internal RPC)
  9. Payment → Booking: paid — pay_51 · ₹6,900 captured (reply, Internal RPC)
  10. Booking → PRS: allocate 2 berths — one writer · 12627 · tomorrow · 3A (Internal RPC)
  11. PRS → PRS: two requests ahead of his — in order · the last 2 berths go to others · 2 → 0 (Internal RPC)
  12. PRS → Booking: 0 left · TQWL 7, 8 — PNR 4521876390 · the Tatkal waitlist (reply, Internal RPC)
  13. Booking → API Gateway: PNR · TQWL 7, 8 — + TicketBooked → Kafka → Notification → SMS (reply, Internal RPC)
  14. API Gateway → Rajat: 200 · TQWL 7, 8 — { PNR: 4521876390 } · cancelled and refunded at chart time if still waitlisted (reply, REST · HTTPS)