Designing APIs for Interviews
TL;DR
API design in system design interviews is a 5-minute step. Identify your core resources, map them to REST endpoints, add pagination and auth, and move on. Candidates fail more often by over-investing in API design than by under-investing.
The 5-Minute Rule
Here's a truth that surprises most candidates: most interviewers don't care deeply about your API design being perfect. They want to see that you can design a reasonable API and move on to the more complex parts of your system — data modeling, storage, scaling, and failure handling.
The API design step in the Delivery framework typically takes about 5 minutes. That's it. The real signal in a system design interview comes from your architecture decisions, not from whether you used the perfect URL structure.
Interview Tip
If you find yourself spending more than 5 minutes on API design, you're probably over-investing. The exception is if you're interviewing for a frontend or product role, where API design matters more since you'll work with APIs daily.

Tackling Time Limits: HLD vs LLD vs Combined Interviews
The 5-minute rule works perfectly for a standard High-Level Design (HLD) interview where architecture is the main focus. However, many candidates also face Low-Level Design (LLD) / Machine Coding rounds, and the increasingly common Combined LLD+HLD rounds.
The strategy and expectations for your API design change drastically depending on the format you're facing:
1. The HLD Strategy (45 mins total)
Time on API Design: ~5 minutes
What to focus on: Resource modeling (identifying the nouns), HTTP methods (the verbs), pagination (?limit=20&cursor=abc), and broad authentication requirements (public vs authenticated).
The goal: Prove you know REST conventions and quickly produce a contract so you can spend the next 35 minutes drawing boxes, discussing databases, scalability, and bottlenecks. Do not write out JSON payload structures unless specifically asked.
2. The LLD / Machine Coding Strategy (45-120 mins total)
Time on API Design: ~10-15 minutes
What to focus on: Code-level contracts. In LLD, you aren't just writing URLs on a whiteboard — you're usually writing actual code (or strict class diagrams). You must translate the REST contract into code interfaces.
The goal: Demonstrate object-oriented implementation of the API. You need to:
- Write the Controller interfaces (e.g., interface BookingController)
- Define strongly-typed Request/Response DTOs (Data Transfer Objects)
- Show where input validation goes
- Demonstrate how you translate domain exceptions to HTTP status codes via an Exception Handler
// LLD-level API design — you'd write something like this:
public interface BookingController {
@POST("/events/{eventId}/bookings")
BookingResponse createBooking(
@PathParam("eventId") String eventId,
@RequestBody CreateBookingRequest request,
@AuthToken UserContext user
);
}
public class CreateBookingRequest {
@NotNull List<TicketSelection> tickets;
@NotBlank String paymentMethod;
}
public class BookingResponse {
String bookingId;
String status;
BigDecimal total;
Instant createdAt;
}
3. The Combined LLD+HLD Strategy (60 mins total)
Time on API Design: ~5-7 minutes
What to focus on: The critical path only. This is the most brutal interview format because you have to jump between massive architectural abstractions and granular class-level logic in under an hour.
The goal: Brutal prioritization. Rapidly list only the top 1-2 most critical endpoints for the primary use case. Immediately bridge the gap by writing out the function signatures for those controllers, the primary request payload, and then instantly jump into the core business logic or database schema for that specific feature. Don't waste time designing edge-case endpoints (like "Update User Profile") when the core system is an event booking engine.
Quick Reference: What to Show in Each Format
| Format | Endpoints | JSON Bodies | DTOs/Classes | Validation | Architecture |
|---|---|---|---|---|---|
| HLD (45 min) | All major endpoints | No | No | No | Yes — this is the focus |
| LLD (45-120 min) | All endpoints | Yes | Yes — typed classes | Yes | Minimal |
| Combined (60 min) | Top 1-2 only | Brief | Function signatures only | No | Yes — with targeted depth |
Interview Tip
Before you start designing APIs, ask the interviewer: "Should I focus on the high-level architecture or do you want me to go deep on the API contracts and class design?" This one question saves you from spending 15 minutes on something they wanted in 5, or vice versa.
Do I Actually Need to Write the REST API in an LLD Interview?
A major point of confusion for candidates is whether they need to write the actual HTTP API layer (spinning up Spring Boot, creating @RestController classes, mapping JSON) during an LLD or Machine Coding interview, or if they just need to implement the core logic.
The answer depends on the exact format of the interview:
1. The "Pure" Machine Coding Round (Flipkart, Swiggy, Uber)
What it is: You're given 90-120 minutes to design an application (like a Parking Lot or Splitwise), write the code, and ensure it's executable.
The expectation: Do NOT write a web server. Interviewers explicitly do not want you wasting time resolving Spring Boot dependencies or debugging network ports.
How to handle "APIs" here: Your "API" is simply the public methods exposed by your core Service classes, invoked from a main() function or an interactive CLI (Command Line Interface).
// Instead of: POST /bookings
// You write: a Scanner reading terminal input
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
BookingService bookingService = new BookingService();
while (scanner.hasNextLine()) {
String[] parts = scanner.nextLine().split(" ");
switch (parts[0]) {
case "CREATE_BOOKING":
bookingService.createBooking(parts[1], parts[2]);
break;
case "CANCEL_BOOKING":
bookingService.cancelBooking(parts[1]);
break;
}
}
}
The input CREATE_BOOKING user_1 event_2 calls bookingService.createBooking(userId, eventId). No HTTP, no JSON, no framework — just clean business logic.
2. The Full-Stack / Backend Take-Home Assignment
What it is: You're given 24-48 hours to build a working backend service.
The expectation: You MUST write the full API. This is where the REST controller, HTTP status codes, JSON serialization, and framework annotations (@RestController in Java, @app.post in Python) are strictly required. Evaluators will literally run Postman or curl commands against your service.
@RestController
@RequestMapping("/api/v1")
public class BookingController {
@PostMapping("/events/{eventId}/bookings")
public ResponseEntity<BookingResponse> createBooking(
@PathVariable String eventId,
@Valid @RequestBody CreateBookingRequest request,
@AuthenticationPrincipal UserContext user) {
Booking booking = bookingService.create(eventId, request, user);
return ResponseEntity.status(201).body(BookingResponse.from(booking));
}
}
Here, everything matters: proper status codes, input validation with @Valid, extracting user from auth context (not from request body), and clean separation between controller and service.
3. The Object-Oriented Design (OOD) Whiteboard Round (Amazon, Microsoft)
What it is: A 45-minute whiteboard or shared-doc session where you design the classes (UML) for a system.
The expectation: You just define the Interface. The interviewer wants to see how you structure the boundaries of your system. You don't write the web framework code, but you should define the entry point.
// Show the Application Layer boundary:
public interface BookingController {
BookingResponse createBooking(String eventId, CreateBookingRequest request);
BookingResponse getBooking(String bookingId);
void cancelBooking(String bookingId);
}
// Then show it delegates to the Business Logic layer:
public class BookingService {
private final BookingRepository repository;
private final PaymentGateway paymentGateway;
public Booking create(String eventId, CreateBookingRequest req) {
// Domain logic here — validation, payment, state transitions
}
}
This demonstrates that the Application Layer (controllers) is kept strictly separate from the Business Logic layer (services) — which is exactly what the interviewer is looking for.
The Golden Rule
Always ask the interviewer at the start of an LLD round: "Do you want me to spin up a working HTTP server with REST endpoints, or should I drive the application logic using a local
main()function and CLI inputs?" 90% of the time in a standard 1-hour interview, they will ask for the CLI approach to save time.
Quick Reference: What to Write in Each LLD Format
| Format | HTTP Server? | REST Controllers? | Service Classes? | DTOs? | Tests? |
|---|---|---|---|---|---|
| Machine Coding (90-120 min) | No | No — use CLI/main() | Yes — this is the focus | Optional | If time permits |
| Take-Home (24-48 hrs) | Yes | Yes — full REST + validation | Yes | Yes — typed request/response | Yes — expected |
| OOD Whiteboard (45 min) | No | Interface only | Yes — show boundaries | Sketch only | No |
The 6-Step API Design Recipe
When the interviewer says "let's define the API," follow this recipe:
Step 1: Identify Core Entities from Requirements
Listen to the problem statement and pull out the nouns. These become your resources.
| System | Core Entities |
|---|---|
| Ticketmaster | Events, Venues, Tickets, Bookings |
| Tinder | Users, Swipes, Matches, Messages |
| Users, Posts, Comments, Likes, Follows | |
| Uber | Riders, Drivers, Rides, Locations |
| Twitter/X | Users, Tweets, Follows, Timelines |
Step 2: Map Entities to REST Resources
Turn each entity into a REST endpoint with plural nouns:
Step 3: Define CRUD Endpoints with HTTP Methods
For each resource, decide which operations users need:
GET /events # List events
GET /events/{id} # Get event details
POST /events/{id}/bookings # Create a booking
GET /bookings/{id} # Get booking details
DELETE /bookings/{id} # Cancel a booking
Step 4: Add Pagination for List Endpoints
Any endpoint that returns a list should be paginated:
Just mentioning pagination shows awareness. You don't need to debate offset vs cursor unless asked.
Step 5: Call Out Authentication Requirements
Quickly note which endpoints need auth:
- Public:
GET /events(anyone can browse) - Authenticated:
POST /events/{id}/bookings(must be logged in) - Authorized:
DELETE /bookings/{id}(must own the booking or be admin)
Step 6: Move On
Say something like: "That covers the main API surface. I'll add more endpoints as needed during the design. Let me move on to the high-level architecture."
This shows confidence and good time management.
Complete Walkthrough: Ticketmaster
Here's a complete example — the kind of thing you'd actually say in an interview.
Requirements
- Users search and browse events
- Users can view event details and available tickets
- Users can book tickets
- Users can view and cancel their bookings
API Design (What You'd Say)
"I'll design a REST API. My core resources are events, venues, tickets, and bookings."
# Browsing
GET /events?city=NYC&category=music&limit=20&cursor=abc
GET /events/{eventId}
GET /venues/{venueId}
# Tickets
GET /events/{eventId}/tickets?section=VIP&status=available
# Bookings (authenticated)
POST /events/{eventId}/bookings # Body: { ticketIds: [...], paymentMethod: "..." }
GET /bookings/{bookingId}
DELETE /bookings/{bookingId} # Cancel
# User's bookings
GET /users/me/bookings?limit=20&cursor=abc
"I'm using nested resources for tickets under events since tickets always belong to an event. Bookings are also created under events, but can be accessed directly by ID. The user identity comes from the JWT token, not the URL."
That's it. About 2-3 minutes of talking. Move on.
Complete Walkthrough: Tinder
Requirements
- Users browse other users' profiles
- Users swipe left (pass) or right (like)
- Mutual likes create a match
- Matched users can message each other
API Design
# Discovery
GET /discovery?limit=10 # Get batch of potential matches
# Swipes
POST /swipes # Body: { targetUserId: "456", decision: "like" }
# Response: { matchCreated: true/false }
# Matches
GET /matches?limit=20&cursor=abc
GET /matches/{matchId}
# Messages
GET /matches/{matchId}/messages?limit=50&cursor=abc
POST /matches/{matchId}/messages # Body: { text: "Hey!" }
Notice the design decisions:
- The swipe is the resource, not an action on a user. POST /swipes creates a new swipe resource.
- The decision field is an enum ("like" or "pass"), not a boolean. This is forward-compatible — you can add "super_like" later without breaking the API.
- Messages are nested under matches because messages only exist within a match context.
- Real-time messaging would use WebSockets, but the REST API handles history.
Complete Walkthrough: Instagram
Requirements
- Users create posts with images and captions
- Users can follow other users
- Users have a feed of posts from people they follow
- Users can like and comment on posts
API Design
# Posts
POST /posts # Body: { imageUrl: "...", caption: "..." }
GET /posts/{postId}
DELETE /posts/{postId}
# Feed
GET /feed?limit=20&cursor=abc # Personalized feed (authenticated)
# Social
POST /follows # Body: { followedId: "789" }
DELETE /follows/{followId}
# Engagement
POST /posts/{postId}/likes
DELETE /posts/{postId}/likes # Unlike (user from JWT)
POST /posts/{postId}/comments # Body: { text: "Great shot!" }
GET /posts/{postId}/comments?limit=20&cursor=abc
# User profiles
GET /users/{userId}
GET /users/{userId}/posts?limit=20&cursor=abc
Key decisions:
- Follow is a resource (POST /follows), not an action on a user
- Likes are sub-resources of posts. Only one like per user (enforced server-side via JWT identity)
- Feed is its own endpoint, not a filtered list of posts — it involves algorithmic ranking
- User identity always from JWT, never from request body
The POST /bookings/:eventId Debate
A common interview discussion: should booking creation be POST /bookings/:eventId or POST /events/:eventId/bookings?
POST /events/:eventId/bookings is the correct answer. Here's why:
| Approach | Problem |
|---|---|
POST /bookings/:eventId |
The path says "bookings" is the collection, but :eventId is someone else's ID — confusing |
POST /events/:eventId/bookings |
Clear hierarchy: you're creating a booking within an event's booking collection |
The rule is simple: a resource's path should contain its own ID, not another resource's ID. The path /bookings/:bookingId makes sense. The path /bookings/:eventId does not.
Interview Tip
If this comes up, explain the parent-child relationship reasoning. It shows you think about API design from the consumer's perspective, not just the implementation.
When Interviewers Go Deeper
Frontend and Product Roles
If you're interviewing for a frontend or product engineering role, expect more time on API design. You might be asked:
- What exact fields does each endpoint return?
- How do you handle optimistic UI updates?
- What's your caching strategy for API responses?
- How do you handle offline mode?
The Atlassian Deep-Dive
Some companies (notably Atlassian) are known to spend significant time — even up to an hour — on API design in their system design rounds. If you know this going in, prepare to discuss:
- Pagination strategy in detail
- Error response formats
- Versioning approach
- Idempotency for write operations
- Rate limiting
Machine Coding Interviews
Some interviews (especially at Indian tech companies) involve a "machine coding" round where you actually implement an API. This is different from system design — you're judged on:
- Clean code and SOLID principles
- Proper separation of concerns (controller → service → repository)
- Input validation
- Error handling
- Test coverage
Junior vs Senior Expectations
| Level | What's Expected |
|---|---|
| Junior | List the main endpoints, use correct HTTP methods |
| Mid | Add pagination, authentication, proper status codes |
| Senior | Discuss idempotency, versioning, rate limiting, nested vs flat resources |
| Staff+ | Consider API evolution, backward compatibility, multi-tenant concerns |
Quick Reference: What to Say
Keep these phrases ready for your interview:
- "I'll use REST APIs for the user-facing interface."
- "My core resources are [X, Y, Z]."
- "List endpoints will be paginated with cursor-based pagination."
- "User identity comes from the JWT, not the request body."
- "These endpoints require authentication: [list them]."
- "For internal service communication, I'd use gRPC, but I'll focus on the user-facing API here."
Each of these signals senior-level thinking in about 5 seconds.
The API Design Rescue Guide: What Can Go Wrong and How to Save It
Even strong candidates stumble during the API design step. The difference between a hire and a rejection isn't whether you make mistakes — it's how you recover.
1. The "API Rabbit Hole" Trap
What goes wrong: You spend 12 minutes perfecting the exact JSON response shape, debating field names, and designing edge-case endpoints like "Update User Notification Preferences" — while the core booking flow still has no endpoints defined.
Why it's fatal: You've burned your 5-minute API budget on a side feature. The interviewer has zero signal on your core system design.
The rescue script: "I realize I've been going deep on the response payloads. Let me step back — the core user-facing operations are browsing events, booking tickets, and viewing bookings. Let me sketch those three endpoints and we can refine the details later if needed."
2. The "Verb URL" Freeze
What goes wrong: The interviewer asks you to design an endpoint for "cancelling a booking." You instinctively write POST /cancelBooking and the interviewer raises an eyebrow.
How to save it: Catch it, correct it, and explain why.
The rescue script: "Actually, let me rethink that. In REST, the URL should be the resource, not the action. Cancelling is just deleting a booking — so
DELETE /bookings/{id}is more RESTful. Or if cancellation has side effects like refunds, I could model it asPOST /bookings/{id}:cancelusing Google's custom method pattern."
3. The "Which Endpoint Structure?" Debate
What goes wrong: You write POST /bookings/:eventId and the interviewer asks, "Is there a more RESTful way to structure that?" You're not sure.
How to save it: Reason through it out loud using the parent-child rule.
The rescue script: "Good question. The booking is a sub-resource of the event — you can't book without specifying which event. So
POST /events/{eventId}/bookingsmakes the hierarchy clearer. The path should contain the resource's own ID, not another resource's ID./bookings/{bookingId}makes sense,/bookings/{eventId}does not."
4. The "User ID in the Body" Catch
What goes wrong: You design a booking endpoint with { "user_id": "123", "event_id": "456" } in the request body. The interviewer asks, "Where should the user ID actually come from?"
How to save it: This is a security question in disguise. Pivot immediately.
The rescue script: "You're right — the user ID should never come from the request body because any client could spoof it. The server should extract the user's identity from the verified JWT token in the Authorization header. Let me remove user_id from the payload."
5. The "Idempotency" Curveball
What goes wrong: The interviewer asks, "What happens if the client's network drops after clicking 'Book' and they retry? Won't that create a duplicate booking?" You didn't think about this.
How to save it: This is a common and expected follow-up. Show you know the pattern.
The rescue script: "Great point — POST isn't idempotent, so a retry would create a second booking. To prevent that, I'd have the client generate a unique
Idempotency-Keyheader with each request. The server checks if it's seen that key before — if yes, it returns the cached response without creating another booking. This is the same pattern Stripe uses for payments."
6. The "No Pagination" Oversight
What goes wrong: You list GET /events as an endpoint and the interviewer asks, "What if there are 2 million events?"
How to save it: Quick fix — show you understand why it matters.
The rescue script: "Right, I need pagination on all list endpoints. I'll use cursor-based pagination:
GET /events?limit=20&cursor=abc123. Cursor-based is better here since events are frequently added, and offset-based pagination would cause items to shift between pages."
7. The "Wrong Protocol" Choice
What goes wrong: You say "I'll use GraphQL for everything" for a standard CRUD booking system. The interviewer pushes back: "Why not REST?"
How to save it: Don't double down. Acknowledge the mismatch and pivot.
The rescue script: "Actually, you're right — for a standard CRUD system with well-defined resources, REST is simpler and more appropriate. GraphQL shines when different clients need very different data shapes, like a mobile app vs a web dashboard. Since we have one primary client here, REST is the better default. I'll save GraphQL for cases where we're seeing clear over-fetching problems."
API Rescue Quick Reference
| Trap | Signal You're In It | The Save |
|---|---|---|
| API Rabbit Hole | 8+ minutes and still on endpoints | Sketch core endpoints, defer edge cases |
| Verb in URL | Writing /getX or /createY |
Restructure as noun + HTTP method |
| Wrong nesting | /bookings/:eventId |
Apply parent-child sub-resource rule |
| User ID in body | Identity in request payload | Extract from JWT server-side |
| No idempotency | POST retries create duplicates | Idempotency-Key header pattern |
| No pagination | Unbounded list endpoint | Add ?limit=N&cursor=X |
| Wrong protocol | GraphQL for simple CRUD | Default to REST, justify deviations |
The meta-lesson: Interviewers don't expect perfect API designs on the first pass. They want to see you recognize a flaw, explain why it's a problem, and fix it — because that's exactly what senior engineers do in code reviews every day.