Skip to content

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.

Interview time allocation


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
Instagram 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:

/events
/venues
/tickets
/bookings

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:

GET /events?limit=20&cursor=abc123

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:

  1. "I'll use REST APIs for the user-facing interface."
  2. "My core resources are [X, Y, Z]."
  3. "List endpoints will be paginated with cursor-based pagination."
  4. "User identity comes from the JWT, not the request body."
  5. "These endpoints require authentication: [list them]."
  6. "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 as POST /bookings/{id}:cancel using 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}/bookings makes 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-Key header 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.