
Ask a candidate to design an API and within five minutes you are in a conversation about plurals, about which status code a soft delete returns, and about whether the version belongs in the path or a header. Everyone has an opinion, the opinions are mostly interchangeable, and none of them has ever caused an outage.
The API decisions that cost money are different. What happens when a client retries. What breaks for the mobile app that cannot ship an update this week. How a caller reads a list that is changing while they page through it. What an error tells the person who has to act on it at 3am.
All four are testable on a service that already exists, with a change request rather than a blank page.
Because naming is visible and consequences are not. A reviewer can see a plural; they cannot see the duplicate charge that happens eight months later when a client times out and retries a payment.
And because most API interviews are conducted on a whiteboard, where nothing has clients, nothing has history, and the cost of a decision never arrives. Give the candidate a service with existing callers and the conversation changes immediately.
The setup. An endpoint that creates something with a side effect: a charge, an email, an order. The client has a timeout. Occasionally the request succeeds and the response is lost, so the client retries and the thing happens twice.
Ask: a customer was charged twice. Design the fix.
Strong looks like: they reach for idempotency as a property of the endpoint rather than a patch in the caller. A client-supplied key, stored with the result, returning the original response on a repeat. They talk about how long keys are kept and what happens when the same key arrives with a different body, which is the part people forget.
Weak looks like: telling the client not to retry. Clients retry. Networks make them.
Why it works: it is the most common expensive API bug, it is invisible in review, and the fix is a design decision rather than a code change.
The setup. A live endpoint with three known consumers, one of which is a mobile app with users on old versions. The request: add a field, rename another, and remove something that should not be there.
Ask: ship this without breaking anyone.
Strong looks like: they ask who the callers are before touching anything, and they sort the changes by whether they are additive or breaking. Adding is safe. Renaming is two deploys: serve both, migrate callers, remove later. They know a mobile client is never fully migrated, so removal has a date far in the future or never.
Weak looks like: a new version for every change, which sounds disciplined and quietly doubles the surface area you maintain forever.
Why it works: compatibility thinking is the clearest line between somebody who has owned an API and somebody who has only written one.
The setup. A list endpoint with offset-based paging over data that is being written continuously. A consumer reading page by page silently misses records and sees others twice.
Ask: our export is missing rows and nobody can reproduce it. Explain, then fix.
Strong looks like: they connect the shifting offsets to the symptom without needing the hint, and they propose a cursor based on a stable ordering. They also say what the guarantee now is, because "no duplicates" and "nothing missed" are different promises and the caller needs to know which one they have.
Weak looks like: increasing the page size. It makes the problem rarer, which is worse than making it common.
Why it works: it is a real bug with a quiet failure mode, and it tests whether somebody reasons about data changing underneath an operation.
The setup. An endpoint that returns a generic failure for several different causes: invalid input, missing permission, a downstream service being down, a rate limit.
Ask: rewrite these responses for the engineer on the other side who is awake at 3am.
Strong looks like: they separate what the caller can fix from what they cannot, and the status codes follow that split rather than a table they memorised. The body says which field was wrong, or how long to wait, or that this is ours and retrying will not help. They mention a correlation id, so a support conversation can be about one specific request.
Weak looks like: a longer human-readable message with the same information. Errors are consumed by code first and people second.
Why it works: error design is where API empathy is visible, and it is almost never interviewed for, despite being the part callers meet on their worst days.
Four rows, the same for every candidate:
Nothing about naming. Naming is a code review conversation, and it is settled in a minute by whatever the rest of the API already does.
These tasks need a service with real callers, a client that can time out, a list that is being written to, and the ability to actually make the change and run the consumers against it.
EasyEnv gives the candidate a box with the service running, the three consumers present, the duplicate-charge scenario reproducible and the export job already missing rows. The recipe is identical for every candidate, so the same bug behaves the same way for everyone and the comparison is fair. The box is disposable and the session is recorded, so you can see whether they looked at the consumers before editing the schema.
The limits, plainly. Building the service with its three callers is a day of setup the first time. Reviewing takes an engineer who has maintained a public interface, not just consumed one. And for an internal API with one caller in the same repository, this is more interview than the role needs: compatibility is cheap when you own both ends.
Stop debating plurals. Hand the candidate a double charge, a rename with a mobile client in the field, a paging bug on moving data and a set of errors that say nothing.
If you only run one, run the retry. Whether somebody makes an endpoint safe to call twice tells you whether they have ever been on the other side of a network that drops responses.
Run live coding sessions and take-home challenges in real production environments. Watch sessions back, score consistently, and hire with confidence.
More posts you might like
Substitution is rare, real, and concentrated at the volume end of hiring where nobody meets anybody before the offer. ID uploads and webcam checks mostly inconvenience honest candidates. Here is what actually makes a stand-in impossible, and what it costs.
A week inside the team answers nearly everything an interview is guessing at, and rules out most of the people worth hiring. Here is when a trial earns its cost, how to structure one that is fair, and what to run instead when it is the wrong tool.
Read moreContract hiring skips the loop, which is the point, and then the work arrives and nobody can say whether it will survive the handover. Here is a single session that tests what actually matters for short engagements, and the four things to watch while it runs.
Read more