The trouble with API keys that never expire
A key issued years ago, never rotated, and still valid today is not a convenience. It is a liability nobody has actually looked at in years.
A failed API request is already a bad moment in someone's day. It gets worse when the error code that comes back is not explained anywhere, and the developer debugging it has to guess whether a 400 means a malformed parameter, a missing required field, or something entirely different that happens to share the same status code as three other unrelated problems. An undocumented error is not just an inconvenience. It converts a five-minute fix into an open-ended investigation, sometimes ending in a support ticket that could have been avoided by reading a page that should have existed.
We publish our error codes plainly in the errors documentation, listing what each one actually means and what commonly causes it, alongside the authentication and rate limits pages that describe the other ways a request can fail. The goal is that when something goes wrong, the answer is one page away, not a guess based on general HTTP status code conventions that may or may not map cleanly onto what our system specifically did.
Hiding error details, even unintentionally through thin documentation, sometimes comes from a reasonable-sounding instinct: exposing exactly why a request failed could theoretically help someone probing an API for weaknesses. In practice, this concern rarely holds up against the actual cost. The overwhelming majority of people encountering an error code are legitimate developers trying to fix their own integration, not adversaries mapping an attack surface. Optimizing error documentation around the rare bad actor, at the cost of clarity for everyone else, gets the tradeoff backwards.
There is also a design discipline benefit to publishing error codes clearly: it forces internal consistency. If every error code has to be documented with a plain explanation, it becomes much harder to accumulate a pile of ad hoc, overlapping error conditions that only the original engineer who wrote them fully understands. Writing the documentation is also, quietly, a form of code review on the error handling itself, because an error that is hard to explain clearly is often a sign the underlying condition was not well thought through in the first place.
Quota-related failures get a related treatment through response headers rather than error codes alone. Every response carries your quota limit, usage, remaining free allowance, network usage, remaining credit, and reset time, so a request that fails due to quota is not a mystery status code at all. It is a number you could have checked before sending the request, and one you can read directly from the response that failed.
None of this eliminates the frustration of a failed request. It just means the frustration should end at the documentation, with an actual answer, rather than continuing into a support queue or a guessing game across old forum posts about what a status code from an entirely different API might have meant in a similar-sounding situation.