Your API's Error Messages Are the Documentation Developers Actually Read
A developer integrating with your API sends a request and gets this back:
{ "error": "Invalid request" }
Nothing else. No hint about which field was wrong or what "valid" would have looked like. So they start guessing. They reorder the JSON, try a different date format, and regenerate their API key. Half an hour later they open a support ticket, and one of your engineers pulls the server logs to find the one line that says the currency field must be lowercase.
That engineer knew the answer the whole time. So did the server. It just didn't tell anyone.
Most teams think of documentation as something developers go and read. During an integration, though, the docs developers spend the most time with are your error responses. They show up exactly when someone is stuck, inside the terminal or log they're already looking at. If those responses are vague, your docs site can be excellent, and the integration still ends up in your support queue.
Error responses are part of your documentation
In an earlier post, I argued that a generated reference is not enough, and that developers need guides, tutorials, and troubleshooting content built around their goals. Error responses are where those layers either connect or fall apart. A developer who hits a clear error can fix it in seconds. A developer who hits a vague one has to stop, leave their work, and go searching, and your docs are only one of the places they'll look.
As an engineer, I know how messages like "Something went wrong" get written. They're rarely laziness. They're a matter of perspective. When you're the one who wrote the validation code, the meaning of a failure seems obvious. You know what the check does. The developer on the other end of the wire doesn't, and the response body is the only thing they get to see.
What a helpful error response contains
A useful error response answers four questions, in roughly this order:
- What went wrong, specifically? Not "invalid request," but "
currencymust be a three-letter lowercase ISO code." - Where? Which parameter, field, or header caused the failure, so the developer doesn't have to bisect their payload.
- What should I do about it? Retry later, fix the input, request a different permission, or contact support. These are different actions, and the response should say which one applies.
- Where can I read more? A link to the page that explains this error in depth.
You don't need to invent a format for this. RFC 9457, Problem Details for HTTP APIs, published in 2023 to replace RFC 7807, defines a standard JSON shape served as application/problem+json. It includes a type URI that identifies the kind of problem, a short title, the status code, a detail string about this particular occurrence, and an instance identifier. The RFC also says two things that are easy to skim past. First, the detail member "ought to focus on helping the client correct the problem" rather than providing debugging information. Second, when the type is an ordinary https URL, opening it should lead to human-readable documentation for that problem type.
That second point turns every error into a link to your docs. Here is the earlier failure, rewritten:
{
"type": "https://docs.example.com/errors/invalid-currency",
"title": "Invalid currency code",
"status": 422,
"detail": "The currency 'USD' must be lowercase, for example 'usd'.",
"instance": "/requests/req_8f2c41",
"param": "currency"
}
The param member is an extension. RFC 9457 lets you add your own members to a problem type, and it requires clients to ignore members they don't recognize, so you can include the details your developers need without breaking anyone.
Stripe is a well-known example of this approach, though it uses its own error format rather than RFC 9457. Its documented error object includes a param field naming the parameter at fault, a doc_url pointing to more information about the error code, and a request_log_url linking to the request's log entry in the developer's dashboard. That is the same idea: every failure tells the developer where to look next.
An error audit you can run this week
You can improve your errors without redesigning your API. Here is how I'd start:
- Collect the errors developers actually hit. Group your API's error responses from the last month by error code and message. A handful of codes often account for most of the volume. Those are your priority list.
- Read each top error cold. Pretend you're a developer who has never seen your codebase. Could you fix the problem from the response alone? If not, write down what's missing: the field, the expected value, or the next step.
- Match errors to tickets. Find support tickets that quote an error message. Each one is a case where the response didn't do its job.
- Give every error code a page. Each documented code should have a page that explains the likely causes and the fix, and the response should link to it, whether through a
typeURI, adoc_url-style field, or both. - Separate "your fault" from "our fault." Developers need to know whether to fix their request or retry later. Make that unambiguous through the status code and the wording, and say explicitly when a retry is safe.
- Review error text the way you review UI copy. Error strings are user-facing text. Put them through the same review as anything else a customer will read, and keep internal stack traces and system names out of them.
None of this requires new infrastructure. It mostly requires someone to read your errors from the outside and care about the result.
Why this needs an engineer and a writer
Fixing error messages sits right on the boundary between code and prose. The writing has to be clear, consistent, and actionable. But you can't write a good error message without understanding the validation logic behind it, where the error is raised, and which failures share a root cause. Those messages live in your source code, so changing them means working in your repository and going through code review, not editing a docs page.
That boundary is where I do my best work. I spent decades writing software before I became a technical writer, so I can trace an error from the line that throws it to the page that explains it, and make both of them say the same thing clearly.
If your integration tickets are full of developers quoting error messages back to you, I'd be glad to look at your API's errors with you and help you decide where to start. You can reach me through the contact page.