33. Design a Notification System
1
The interview prompt2
33.1 What do you ask first?3
33.2 How big is this, really?4
33.3 What are the doors?5
33.4 What do we store?6
33.5 What does the whole system look like?7
33.6 Why one queue per channel?8
33.7 How do retries and de-duplication work?9
33.8 How do user preferences work?10
33.9 What makes OTPs special?11
33.10 What would you say in the last five minutes?12
Score yourself13
Variations to practise14
Sources15
Code lab33. Design a Notification System
33.3 What are the doors?
3 min read+10 XP
Step 3: API and data model (10 minutes)
POST /v1/notifications
body: { "idempotency_key": "order-881-shipped",
"user_id": 42, "type": "order_shipped",
"data": { "order_id": 881, "eta": "Friday" } }
returns: 202 Accepted { "notification_id": "n_9f2..." }
POST /v1/otp/send { "phone": "+91...", "purpose": "login" } → 202 { "request_id": "otp_77" }
POST /v1/otp/verify { "phone": "+91...", "code": "482913" } → 200 { "ok": true } | 400 / 429
GET /v1/notifications/{id} → { "status": "delivered", "channel": "push", ... }
PUT /v1/users/{id}/preferences → opt-ins, quiet hours, language
POST /v1/campaigns → template, audience, schedule (marketing only)
202 Accepted, not 200: the API queues the work and returns; delivery happens asynchronously (Chapter 22). The caller passes an idempotency key so a retried API call doesn't create a second notification (Chapter 24).
The OTP API is separate on purpose: callers never see the code. The notification system generates, stores (hashed) and verifies it, so the code never sits in another team's logs.