API Authentication, Errors and Status Codes

3.Visitor Passes and Delivery Notes

A

In this chapter

We'll learn how APIs know who's calling and what they may do — API keys, tokens, scopes — and how they report problems: status codes, error bodies, timeouts, retries with backoff and idempotency keys, explained as a building's visitor passes and a delivery company's return notes.

14–16 min

The Problem in Real Life

Anna reads the payment provider's documentation about callbacks for the first time. One paragraph stands out: "Your endpoint must respond with a 2xx status within 10 seconds. Otherwise the delivery is treated as failed and retried up to 3 times over the next hour."

She checks the logs: BlueTicket's handler took about 14 seconds on Friday. It created the order, generated the ticket PDF and sent the email — all before replying. Each of the three retries took just as long. After the third, the provider gave up. "It wasn't an error," she says slowly. "We just answered too late — four times."

J

Read the API's rules before you write a single line against it.

John

"It Either Works or It Doesn't" vs. Clear Rules for Every Kind of Failure

Who's calling?

An API must know which program is calling, and what that program is allowed to do.

Many kinds of failure

Bad input, no permission, overloaded server, timeout — each needs a different reaction.

Retries can duplicate

Retrying a request that actually succeeded can charge a card twice.

API Authentication, Authorization, Errors and Status Codes

The office building analogy: visitors to an office building get a visitor pass at reception — it says who they are and which floors they may visit. And when a delivery can't be completed, the courier leaves a note saying exactly why: "wrong address", "nobody home — we'll try again tomorrow", "refused". APIs need both: passes and clear notes.

  • API authentication — the visitor pass: APIs check who is calling, usually with one of: an API key (a secret string for a program, Act 22), a bearer token such as a JWT for a logged-in user (Act 22), or OAuth client credentials — a program logs in with its own ID and secret and gets a short-lived token, the standard for machine-to-machine calls. Webhooks are usually authenticated with a signature (chapter five).
  • API authorization — which floors: the pass also limits what the caller may do, often with scopes: a venue's API token has the scope sales:read for its own venue only — it can't read other venues or issue refunds (least privilege, Act 22).
  • Status codes — the note's headline: 2xx = it worked: 200 OK, 201 Created, 202 Accepted ("got it, will do it later"), 204 No Content. 4xx = the caller did something wrong — don't retry the same request: 400 Bad Request, 401 Unauthorized (who are you?), 403 Forbidden (not allowed), 404 Not Found, 409 Conflict (the seat is already taken), 422 Unprocessable (valid JSON, invalid values), 429 Too Many Requests (slow down). 5xx = the server had a problem — trying again later may work: 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout.
  • Error bodies — the note's details: a good API returns a consistent JSON error with a machine-readable code, a human message, which field was wrong, and the request ID for support. Never include stack traces or secrets (Act 17, Act 22).
  • Timeouts — how long to wait: every API call needs a timeout: the longest the caller will wait. Without one, a slow provider can freeze your whole app. The payment provider waits 10 seconds for BlueTicket; BlueTicket waits 5 seconds for the SMS provider.
  • Retries with backoff — try again, politely: for timeouts, 429 and 5xx, retrying often works. But retry with exponential backoff — wait 1 second, then 2, then 4, then 8 — plus a little randomness, so thousands of clients don't all retry at the same instant. Don't retry most 4xx errors: the same wrong request will fail the same way.
  • Idempotency keys — retries without double charges: a POST that timed out might have worked — the answer just got lost. Retrying could create a second charge. So payment APIs accept an idempotency key (Act 12's idempotency): a unique ID sent with the request. If the same key arrives twice, the provider returns the first result instead of doing it again.
Table — Status codes as delivery notes
CodeDelivery-note versionShould the caller retry?
200 / 201DeliveredNo — done
202 AcceptedReceived, will deliver laterNo — wait for the result
400 / 422Address incomplete or wrongNo — fix the request
401No valid ID shownNo — get valid credentials
403Not allowed in this buildingNo
404No such addressNo
409Someone else got it firstNo — choose again
429Too many deliveries — slow downYes, after waiting
500 / 502 / 503 / 504Problem at the depotYes, with backoff
Timeout (no answer)Nobody came to the doorYes, with backoff + idempotency key
Table — Ways to authenticate API calls
MethodWho uses itBlueTicket example
API keyA program, simple setupsBlueTicket → SMS provider
Bearer token (JWT)A logged-in user's appMobile app → BlueTicket
OAuth client credentialsProgram to program, short-lived tokensVenue systems → BlueTicket venue API
Signature (HMAC)Callbacks / webhooksPayment provider → BlueTicket
A consistent error body
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"error": {
"code": "seat_unavailable",
"message": "Seat C14 is no longer available.",
"field": "seatIds",
"requestId": "req_9f2a71"
}
}
Calling the payment API with a timeout, retries and an idempotency key
const idempotencyKey = `order-${order.id}`; // same key on every retry
for (let attempt = 1; attempt <= 4; attempt++) {
try {
return await payments.createPayment(
{ amount: order.total, orderId: order.id },
{ idempotencyKey, timeoutMs: 5000 }
);
} catch (err) {
const retryable = err.isTimeout || err.status === 429 || err.status >= 500;
if (!retryable || attempt === 4) throw err;
await sleep(2 ** attempt * 500 + Math.random() * 250); // 1s, 2s, 4s... + jitter
}
}

What went wrong, in these words: BlueTicket was the provider of the callback endpoint, and broke the caller's rule: reply with 2xx within 10 seconds. To the payment provider, our slow handler looked like a timeout, so it retried with backoff three times — exactly as documented — and gave up. And Anna spots a second problem in the code: if a retry ever had arrived while the first attempt was still running, both could have created an order. Two bugs, one handler. Chapter five fixes both.

Key Takeaway

APIs authenticate callers with API keys, bearer tokens or OAuth client credentials, and authorize them with scopes. Status codes say what happened: 2xx success, 4xx the caller's mistake (don't retry blindly), 5xx the server's problem (retry later). Good errors have a consistent JSON body with a code, message and request ID. Every call needs a timeout; retries use exponential backoff; and idempotency keys make retried POSTs safe from duplicate charges.

Why This Matters

Choosing the right status code, writing clear errors and handling other APIs' failures correctly are everyday backend skills — and the difference between a system that recovers by itself and one that charges customers twice. Timeouts, retries with backoff and idempotency come up in almost every system-design interview.

Meanwhile, Riverside Arena's accounts team reports another problem with BlueTicket's own API: when their system asks for "all orders", the request takes a minute and sometimes fails. There are 48,000 of them.

Next