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 structure, candidates follow whatever the latest question asks about. They spend ten minutes naming endpoints, remember authentication, return to requirements, mention errors, and discover that no operation has been completed.
The solution is a fixed sequence.
Every complete answer in this course follows six steps, in this exact order:
- Identify the consumers and the jobs they need to finish.
- 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.
The sequence is more than a memory aid. Each step gives the next step the information it needs. Consumers reveal jobs. Jobs reveal resources. Resources reveal operations. Operations give you one contract to examine deeply. That complete operation exposes the hard parts. The final trade-offs show the cost of the decisions you made.
1. The 45-Minute Framework
Use this budget when the entire 45-minute session is available for API design.
The total is 45 minutes.
This is a target, not a stopwatch. An interviewer may interrupt after three minutes or spend fifteen minutes on one operation. Follow the same sequence even when the timing changes. If the discussion jumps to retries during Step 3, answer the question and then return to the unfinished step.
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
Your goal is not to collect every possible requirement. It is to gather enough context to prevent the wrong contract, which is a much smaller job.
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 go there."
One sentence like that prevents a silent disagreement about what the answer is even trying to optimize.
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
With the sketch on the board, ask whether each resource has earned its 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."
Scope control is part of the skill. A candidate who designs a small contract completely demonstrates better judgment than one who produces a large unfinished surface.
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.
Use task creation as the deep operation.
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.
You do not need to design the idempotency storage during an API round unless somebody asks, because the caller-visible promise is the part being graded.
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.
Do not recite all of them. Choose the ones your own requirements and your deep operation actually created.
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 make your judgment visible to somebody who has to score it.
Walk back through the important decisions and name what each one gave up.
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 gave up some payload efficiency and surface minimalism 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
In 30 minutes you identify one primary caller rather than every consumer, model only the resources the selected flow needs, list three to five operations rather than the full surface, discuss two or three hard parts rather than a checklist, and state two precise trade-offs. Step 4 is untouched.
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.
When a round is unexpectedly shortened, protect depth by cutting breadth instead.
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
That is not a script to follow mechanically. It is a reference that stops one interruption from becoming the rest of the interview.
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 you lose time, reduce breadth before depth.
You now have the structure for a complete answer. The next lesson goes deeper into Step 1: how to identify the caller, ask requirements that settle real API decisions, and derive a contract by writing the client code you wish existed.
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