Skip to content

API design & contracts in a Senior backend interview

An API is a promise other teams build on, and the round tests whether you can keep it while the system underneath changes. Most of the interesting questions are about the second version rather than the first.

The check comes with every pass, covers all 8 competencies of a Senior backend loop, and takes 10–15 minutes. It reports each one as Ready, Borderline or a Gap for this level. It never predicts a pass.

Where this usually breaks down at Senior

These are the distinctions the questions on this axis are written to separate — our judgement from writing them and having them reviewed, not a measurement of candidates. We have run no study, so nothing here is a statistic and none of it is phrased as one.

  1. 1.

    Compatibility judged against the schema rather than the callers

    Adding an optional field is safe. Making it required, narrowing a type, changing a default or tightening validation are not — and whether they break anything depends on what clients actually send, which is a question you have to be able to answer.

  2. 2.

    Errors designed last

    A caller writes more code against your failure modes than against your success shape. Which errors are retryable, which are permanent, whether the same request may be sent again, and how a client tells the three apart is part of the contract.

  3. 3.

    Idempotency delegated to the transport

    HTTP says which methods ought to be idempotent. It does not make your handler so. Where the key comes from, how long it is remembered, and what happens when the same key arrives with a different body are API decisions with an operational cost.

  4. 4.

    Pagination that breaks while the data moves

    Offset paging over a table being written to skips and repeats rows. Cursor paging is not a stylistic preference; it is the version that stays correct under concurrent writes, and the trade it makes — no jumping to page forty — is the thing to say out loud.

What a strong answer sounds like: A strong answer talks about existing callers by what they actually send, not by what the specification permits.

How the check measures it

3 questions drawn on this axis alone — 2 medium and 1 hard for a Senior target, because the bar is the level. Hard counts for one and a half times a medium, which is what makes the verdict relative:

Medium rightHard rightVerdict
2 of 21 of 1Ready
1 of 21 of 1Ready
2 of 20 of 1Borderline
0 of 21 of 1Borderline
1 of 20 of 1Gap
0 of 20 of 1Gap

Three questions is coarse and the report says so beside every verdict. It is enough to separate this axis from the other 7, which is what the check is for — there is no total, no percentage and no single number anywhere in the report.

What there is to practise

129 questions on this axis
101 medium, 28 hard. Easy is not drawn for a Senior target.

Every answer cites the source it was checked against.

Drawn from Networking & APIs (41), TypeScript & Node (17), AWS (16), Go (15), System Design (13).

Practised in the System design round
Design a system to requirements and defend the trade-offs: storage, messaging, caching, capacity and cost. The round weighted most in 2026 loops.

Practice is arranged by interview round rather than by topic, because loops are graded that way.

Questions here most often also test reliability & failure modes, technical judgment: decisions and trade-offs, networking and code quality & design. Nothing on this axis is asked in isolation, which is why the check reports every competency separately rather than averaging them.

One of them, in full

A real question from the free demo, not written for this page. A demo quiz opens with it; the answer, the explanation and the source come when you submit — no account needed.

API design & contractshard

A TypeScript (strict) profile service on Node 24 applies partial updates:

interface Profile { name: string; phone?: string }
type ProfilePatch = Partial<Profile>;

// body.name and body.phone are string | undefined
const patch: ProfilePatch = { name: body.name, phone: body.phone };
await store.save({ ...current, ...patch }); // save(p: Profile)

A mobile client that sends only {"phone": "…"} leaves the stored profile with no name, though Profile says it always has one, and the build is clean. The team wants any code that can put undefined into a patch field to fail to compile. Which change does that?

Answer it on the demo

One axis is not the loop

A Senior backend loop tests 8 competencies, and being strong here says nothing about the other 7. The check covers all of them in one sitting and reports each separately, so what comes back is a profile rather than a score.