Writing a client
Retries, backoff, pagination and the four failures worth handling separately.
The API is small enough that a client is a hundred lines. Most of the work is in handling the four failures differently, because retrying the wrong one wastes time and retrying another makes things worse.
| Status | Retry? | Because |
|---|---|---|
| 401 | No | The key is wrong, absent or expired. Retrying sends the same wrong key. |
| 403 | No | The key lacks a scope. Only a new key with different scopes fixes it. |
| 404 | No | Not this key's workspace. Retrying will not change whose workspace it is. |
| 429 | Yes, after Retry-After | A limit, not a fault. The header tells you how long. |
| 503 | Yes, with backoff | Load protection or a transient read failure. Not caused by your traffic. |
Backoff
- Honour
Retry-Afterwhen present; it is computed from the window rather than guessed. - Otherwise exponential with jitter. A fixed interval across several clients reconverges into the spike that caused the limit.
- Cap the total attempts. A client that retries forever turns a five-minute provider blip into an outage of its own making.
- Never retry inside a request a person is waiting on. Queue it and answer.
Pagination
Read hasMore rather than comparing the array length against your limit, and pass nextCursor back verbatim. Do not construct a cursor: it is opaque, its contents are an implementation detail, and one you build by hand can stop working without a version bump because it was never part of the contract.
Keys in a client
- Read the key from the environment. Never from a file in the repository, and never as a default argument.
- Log the
keyIdfrom/auth, never the key. - Set a rotation reminder shorter than the expiry. Nothing warns you.
- One key per integration. A shared key means a rotation takes down everything at once and you cannot tell which caller hit a limit.