0% completed
A Framework for API Design Answers
On This Page
- The 45-Minute Framework
- Why the Order Matters
Choice one: Start from the caller
Choice two: Design one operation completely
- Step 1: Identify the Consumers and the Jobs They Need to Finish, 5 Minutes
- Step 2: Model the Resources, 5 Minutes
Resource test
- Step 3: List the Operations, 10 Minutes
Prioritize instead of expanding
- Step 4: Design One Operation in Complete Detail, 10 Minutes
Request
Success response
Named failures
Retry behavior
- Step 5: Address the Hard Parts, 10 Minutes
Prioritize by risk
- Step 6: State the Trade-offs Taken and the Options Rejected, 5 Minutes
Trade-off 1: Expanded task response versus separate assignee reads
Trade-off 2: Explicit assign operation versus patching an ID array
Trade-off 3: Cursor versus offset pagination
Trade-off 4: Full created resource versus identifier-only response
A final summary pattern
- Compressing the Framework for a 30-Minute Round
What compression changes
What compression must not change
- Staying Oriented When the Interviewer Interrupts
A practical whiteboard layout
Key Takeaways
API design questions feel open-ended because the interviewer can ask about almost anything: resources, URLs, field types, status codes, pagination, retries, permissions, rate limits, or versions.
Without a clear structure, it is easy to move between endpoints, authentication, requirements, and errors without fully defining any operation.
The solution is a fixed sequence.
Every complete answer in this course follows six steps, in this exact order:
- Identify the consumers and the tasks they need to complete.
- Model the resources.
- List the operations.
- Design one operation in complete detail.
- Address the hard parts, such as paging, retries, versioning, authentication, and rate limits.
- State the trade-offs taken and the options rejected.
Each step provides information for the next. First identify the clients and their tasks. Then define resources and operations that support those tasks. Design one operation in detail to identify important issues such as retries and permissions. Finally, explain the advantages and disadvantages of your choices.
1. The 45-Minute Framework
Use this budget when the entire 45-minute session is available for API design.
The total is 45 minutes.
Use these times as a guide, not a strict schedule. The interviewer may ask questions or spend longer on one operation. Answer those questions, then return to the unfinished part of your plan when appropriate.
2. Why the Order Matters
The framework makes two important structural choices.
Choice one: Start from the caller
The API is a promise to the caller, so the caller should shape it.
Suppose a service stores customer information in separate profile, address, preference, and subscription tables. A mobile application may need one account-summary response. A billing partner may need only the subscription and billing contact. An internal fraud service may need a stable customer identifier and a few risk-relevant fields.
If you start from the tables, all three callers inherit the storage layout. If you start from the jobs, each contract can expose the information required for its task while storage remains free to change.
This creates a useful separation:
Caller job -> Stable API promise -> Replaceable implementation
The implementation may later denormalize data, split a service, merge tables, add a cache, or change databases. Those changes should not require every caller to rewrite its code.
Choice two: Design one operation completely
Operation names contain almost no decisions. CreateTask and ListTasks do not say what creation requires, which fields are optional, whether duplicate creation is safe, what success returns, which failures exist, or how authorization differs between reading and deleting. One complete operation forces all of those decisions, which is why Step 4 keeps its ten minutes in both the 45-minute and 30-minute versions.
3. Step 1: Identify the Consumers and the Jobs They Need to Finish, 5 Minutes
Gather enough context to choose a useful contract. You do not need to collect every possible requirement before starting the design.
Ask:
- Who calls this API?
- Is the caller first-party, internal, public, or automated?
- What are the two or three most important jobs?
- Which job should we optimize and design in depth?
- Is the API new, or do existing callers constrain us?
For a team task-management API, your visible output might be:
| Consumer | Job | Important consequence |
|---|---|---|
| First-party web and mobile clients | Create, assign, and display tasks | Common screens should require few calls; responses should be compact and predictable. |
| Internal automation | Create tasks from alerts and workflows | Writes need stable external identifiers and safe retries. |
| Public partner integration | Read and update selected tasks | Compatibility, explicit permissions, rate limits, and documentation matter. |
You do not need to design for all three equally. State the scope:
"I'll optimize the initial design for the first-party application and internal automation. I'll keep the contract compatible with a later public API, but I will not design partner onboarding in detail unless you want to discuss it."
Stating the scope gives the interviewer a chance to correct your assumptions before you continue.
4. Step 2: Model the Resources, 5 Minutes
Resources are the stable concepts a caller reads, creates, changes, or refers to later.
For the task-management example, the first model might include:
ProjectTaskUserComment
The model is not a database schema, so it needs no indexes, no partition keys, and not every field you store. It needs just enough structure to answer:
- What has a stable identity?
- What has its own lifecycle?
- Which resource contains or refers to another?
- Which relationships must the API expose?
- Which object can become large and therefore needs separate paging?
A simple relationship sketch might be:
Project contains Tasks Task references Assignees (Users) Task has Comments
Use this model to decide which resources need their own operations.
Comments can be numerous, paginated, created independently, and deleted under separate permissions. They likely deserve a resource identity. An assignee relationship can sit directly on the task, or use explicit assign and unassign actions. It does not have to appear as a storage-style join record.
Resource test
For each proposed resource, ask:
"Does the caller think in terms of this concept, or does only the database think in terms of it?"
If only the database needs it, keep it behind the contract where you can still change it.
5. Step 3: List the Operations, 10 Minutes
Now turn the caller jobs from Step 1 into operations.
Do not generate five operations per resource out of habit. Ask what the caller actually needs to do, and publish only that.
For the selected task-management scope:
That is more useful than an endpoint list, because every line is tied to a caller job and carries one design note with it.
Prioritize instead of expanding
Mark operations as:
- core: required for the primary flow;
- supporting: needed soon but not designed deeply; or
- out of scope: plausible but not required for this answer.
For example:
"Creation, retrieval, and listing are core. I'll mention update and comments for model completeness, but I'll design creation in depth. Bulk import, task templates, and full-text search are out of scope."
A smaller, complete design usually explains your decisions more clearly than a larger design with important details missing.
6. Step 4: Design One Operation in Complete Detail, 10 Minutes
This is the center of the interview, and the step most worth protecting when time runs short.
For one important operation, define the complete caller-visible contract:
- method and path;
- authentication or required permission;
- important headers;
- request fields, types, units, and validation;
- success status and headers;
- response body;
- named failure cases with status codes;
- machine-readable error body; and
- retry or idempotency behavior.
For this example, design task creation in detail.
Request
POST /v1/projects/prj_123/tasks Authorization: Bearer <token> Idempotency-Key: c990fbf6-2e5c-41b8-b983-bfe08116e91a Content-Type: application/json
{ "title": "Prepare launch checklist", "description": "Cover monitoring, rollback, and support ownership.", "assignee_ids": ["usr_17", "usr_42"], "due_at": "<RFC 3339 UTC timestamp>", "external_id": "alert-88421" }
Define the fields rather than leaving an interviewer to assume them:
| Field | Required? | Type | Rule |
|---|---|---|---|
title | Yes | String | 1 to 200 characters after trimming. |
description | No | String | Maximum 10,000 characters. Omission means no description. |
assignee_ids | No | Array of user IDs | No duplicates; every user must be assignable in the project. |
due_at | No | RFC 3339 timestamp | Must include an offset; stored and returned in UTC. |
external_id | No | String | Unique within the caller and project; useful for reconciliation. |
Notice the contract decisions contained in this table. A title is not merely "a string." It has a length rule. A timestamp includes a format and timezone expectation. An omitted description is not automatically the same as null. An external identifier has a uniqueness scope.
Success response
HTTP/1.1 201 Created Location: /v1/tasks/tsk_789
{ "id": "tsk_789", "project_id": "prj_123", "title": "Prepare launch checklist", "description": "Cover monitoring, rollback, and support ownership.", "status": "open", "assignees": [ { "id": "usr_17", "display_name": "Ari Chen" }, { "id": "usr_42", "display_name": "Sam Rivera" } ], "due_at": "<RFC 3339 UTC timestamp>", "external_id": "alert-88421", "version": 1, "created_at": "<RFC 3339 UTC timestamp>", "updated_at": "<RFC 3339 UTC timestamp>" }
201 Created states that a new resource exists. Location identifies it. The full representation lets a first-party client render the result without an immediate read. The version field can support later concurrency control.
Named failures
Every failure names what the caller should do about it, rather than only what went wrong.
A consistent error body might be:
{ "error": { "code": "invalid_assignee", "message": "User usr_42 cannot be assigned to this project.", "field": "assignee_ids[1]", "request_id": "req_91a8" } }
Retry behavior
If the caller times out it cannot know whether the task was created, and repeating an unprotected POST may create a second one.
The Idempotency-Key makes retry behavior explicit:
- same key and same request body: return the original result;
- same key and different body: return
400 idempotency_key_reused; - new key: treat as a new creation attempt.
State the idempotency key's scope and retention period, and explain what happens when two requests use the same key at the same time. You can discuss storage details if asked, but the client-visible rules must be clear. The rules above apply only while the server retains the key and result.
7. Step 5: Address the Hard Parts, 10 Minutes
The hard parts are cross-cutting decisions that affect several operations.
Common topics include:
- paging and filtering;
- retries and idempotency;
- authentication and authorization;
- rate limits;
- versioning and compatibility;
- concurrency;
- asynchronous work;
- caching;
- consistency guarantees; and
- multi-tenancy.
Choose the topics that matter to your requirements and the operation you designed. You do not need to cover every item in the list.
For the task API, five relevant decisions might be:
Then explain behavior at the contract boundary.
For example:
"Task lists use an opaque
next_cursor. Filters are repeated on every request, and the cursor is valid only for the same filter and sort. The response does not promise a total count because calculating an exact count may be expensive and can become stale immediately."
Or:
"An update carries the ETag from the last read in an
If-Matchheader. If another writer changed the task, the server returns412 Precondition Failedso the client can reload before deciding whether to retry."
Prioritize by risk
When time is short, choose the hard parts most likely to cause duplicate work, data exposure, wrong client behavior, or future incompatibility.
For a public write API, authentication, authorization, idempotency, rate limits, and versioning may dominate. For a list-heavy first-party application, paging, filtering, payload size, and caching may dominate. For long-running work, asynchronous state and completion delivery may dominate.
Name several caller-visible decisions, each connected to a requirement. "We will have rate limiting" is not enough: state who is limited, what happens at the limit, and how the caller recovers.
8. Step 6: State the Trade-offs Taken and the Options Rejected, 5 Minutes
Use the final minutes to explain the reasons for your main choices.
Review the important decisions and describe the disadvantage of each.
For the task API:
Trade-off 1: Expanded task response versus separate assignee reads
"I included compact assignee summaries in the task response so the first-party client can render the common screen without additional reads. The cost is duplicated user data and a larger payload. I accept that for item reads but would keep large task lists more compact."
Trade-off 2: Explicit assign operation versus patching an ID array
"I chose an explicit assignment operation instead of treating assignees as a generic replaceable array. This adds an operation, but it gives assignment its own permissions, duplicate behavior, audit event, and errors."
Trade-off 3: Cursor versus offset pagination
"I chose cursor pagination because tasks can be inserted and reordered while a caller is paging. The cost is that callers cannot jump to an arbitrary page number."
Trade-off 4: Full created resource versus identifier-only response
"Creation returns the full task so the client does not need an immediate read. The cost is a larger response and more fields in the compatibility surface."
A final summary pattern
Close with:
"The design optimizes the first-party task flow and safe automation writes. I accepted larger responses and more operations to reduce client calls and make state transitions explicit. If the primary consumer changed to a high-volume public integration, I would revisit the expanded representations and limits."
A statement like that reminds the interviewer the design follows your stated requirements, rather than claiming to be optimal for everybody.
9. Compressing the Framework for a 30-Minute Round
For a 30-minute round, halve every step except Step 4, which still gets its full ten minutes.
The compressed steps total 27.5 minutes, leaving 2.5 minutes for interviewer questions and transitions.
What compression changes
For a 30-minute answer, choose one main client, model only the resources its task needs, and list three to five operations. Discuss two or three difficult issues and two clear trade-offs. Keep enough time to define one complete operation.
What compression must not change
Never reduce Step 4 to a method and a path, because that is the evidence the round exists to collect.
The deep operation is where the interviewer sees field design, success behavior, failures, retries, and consistency working together. If you halve every step equally, you may finish on time but provide no strong evidence.
If you have less time than expected, cover fewer operations while keeping the important details of one operation.
Keep: one caller, one job, a small resource model, a few operations, one complete operation, the two hardest concerns, and two trade-offs.
Remove first: secondary callers, rare operations, speculative features, and long debates about naming.
10. Staying Oriented When the Interviewer Interrupts
Interviewers interrupt for good reasons: to test one decision, to redirect the scope, or to give you information you were missing.
Answer the question directly, then restore the structure:
"That covers the retry behavior. I was listing the core operations, so I'll finish that list and then design creation in detail."
Keep a small six-line checklist visible:
1. Consumers and jobs [done] 2. Resources [done] 3. Operations [in progress] 4. One operation in full 5. Hard parts 6. Trade-offs
Use this checklist to track what you have covered. Adapt it to the discussion rather than following it mechanically.
A practical whiteboard layout
Reserve the areas before you begin, as laid out in the diagram below. The layout makes progress visible and reduces rewriting.
Key Takeaways
- Every answer in the course follows six steps in this exact order: consumers and jobs, resources, operations, one complete operation, hard parts, and trade-offs.
- The 45-minute budget is
5 + 5 + 10 + 10 + 10 + 5minutes. - Starting from the caller keeps the published promise stable while storage and implementation remain free to change.
- Operation names contain almost no decisions; one complete operation exposes inputs, outputs, status codes, failures, and retry behavior.
- Step 5 should cover the hard parts created by the requirements, not every API topic you remember.
- Trade-offs should name the selected option, rejected alternative, benefit, and accepted cost.
- For a 30-minute round, halve every step except Step 4, which remains ten minutes; the resulting 27.5-minute plan leaves a 2.5-minute buffer.
- When time is limited, cover fewer operations in enough detail.
You now have a structure for a complete answer. The next lesson explains Step 1 in more detail: identify the client, ask questions that affect the API, and sketch how client code would use it.
Reading Progress
0%
On This Page
- The 45-Minute Framework
- Why the Order Matters
Choice one: Start from the caller
Choice two: Design one operation completely
- Step 1: Identify the Consumers and the Jobs They Need to Finish, 5 Minutes
- Step 2: Model the Resources, 5 Minutes
Resource test
- Step 3: List the Operations, 10 Minutes
Prioritize instead of expanding
- Step 4: Design One Operation in Complete Detail, 10 Minutes
Request
Success response
Named failures
Retry behavior
- Step 5: Address the Hard Parts, 10 Minutes
Prioritize by risk
- Step 6: State the Trade-offs Taken and the Options Rejected, 5 Minutes
Trade-off 1: Expanded task response versus separate assignee reads
Trade-off 2: Explicit assign operation versus patching an ID array
Trade-off 3: Cursor versus offset pagination
Trade-off 4: Full created resource versus identifier-only response
A final summary pattern
- Compressing the Framework for a 30-Minute Round
What compression changes
What compression must not change
- Staying Oriented When the Interviewer Interrupts
A practical whiteboard layout
Key Takeaways