Start with the caller decision
A partner system receiving a failed API request has to choose among correcting the request, obtaining authorization, waiting, seeking an operator, or stopping because a resource is absent. A bare “Something went wrong” gives none of those choices enough evidence. Begin by listing failures that can occur in the real workflow: an unknown product code, an expired credential, an unavailable stock feed, or a rejected field. For each failure, write the safe next action and whether an automatic retry could make matters worse. This exercise reveals which distinctions the API needs to communicate, before anyone selects an error format.
Keep the HTTP status meaningful. RFC 9110 defines the general semantics that generic clients and intermediaries use; RFC 9457 adds structured detail when a status alone cannot explain the application problem. A response that carries status 200 while its body says “error” can be mistaken for success by monitoring and client code. An invented status for a familiar condition forces integrations to learn a private protocol. Select the standard status whose meaning fits, then add a stable application problem type only when callers need finer distinctions. Document the mapping with examples from the partner contract.
Use structured detail consistently
RFC 9457 defines the application/problem+json representation. Its type identifies the kind of problem; a resolvable HTTPS type URI can also lead developers to documentation. The title is a short summary of that type, while detail explains this occurrence in words a person can act on. The instance can identify a particular occurrence. The optional status member should match the actual HTTP response status because generic software follows the real status line. Avoid making clients parse English or Chinese prose to discover the failure category. The type is the stable machine signal.
Use an extension member only for information a client can legitimately use. A validation response can identify rejected fields and acceptable input, provided it does not echo secrets or arbitrary customer data into logs. A support reference can connect a sanitized customer report to a server record without exposing structural internal IDs. Document each extension type, whether it is optional, and what the caller should do if it is absent. RFC 9457 requires clients to ignore extensions they do not recognize. Adding an informational member should therefore not unexpectedly change what an existing problem type means.
Make retry advice conditional
A retry instruction is a business promise as well as a technical hint. A field-validation failure needs correction, not another identical request. An authorization failure calls for credential or permission review, not rapid repeated attempts. A temporary server failure may justify a later retry, but the caller still needs a way to avoid repeating a business action. RFC 9457 says a problem type may specify Retry-After in appropriate circumstances. Use that header when the server can reasonably tell clients when to try again. It is not a generic decoration for every failure.
Suppose a supplier sends an order creation request and the connection closes before a response arrives. An error format alone cannot establish whether the order was created. The partner must check by a stable client reference or use an agreed idempotency mechanism before resubmitting. By contrast, if the server returned a clear field error before accepting the order, the partner can correct that field and send a valid request. Document these boundaries next to each problem type, including which requests are safe to repeat. Otherwise “retry” may turn an incomplete status message into two real orders.
Work through a catalogue import
Consider a partner importing a catalogue item with a required SKU and a public sale price. If SKU is missing, return a fitting client-error status and a documented validation type. The human detail can say which field needs attention, and a defined extension can point to that field for software that renders an import report. If the SKU exists but the partner lacks access to that catalogue, the response needs a permission decision rather than a validation hint. If the stock service is temporarily unavailable, the response needs server-failure semantics and recovery guidance appropriate to the operation. One workflow contains three distinct caller actions.
The import dashboard should show a short customer-safe message and the affected item reference, while engineering logs retain fuller internal diagnosis. A partner should group failures by type without depending on a localized title. A person reviewing a Chinese interface can receive a Traditional Chinese explanation if the service supports it, while the type URI remains stable. RFC 9457 allows language negotiation for human-readable strings, but the implementation must define a fallback when the requested language is unavailable. Test both languages for identical decisions rather than sentence-for-sentence matching.
Protect detail and test the contract
Review every message as if it could be shown to a partner operator, copied into a ticket, and stored in a log. RFC 9457 explicitly warns against exposing implementation details, personal data, or stack dumps through problem responses. Do not put raw SQL, access tokens, or customer records in detail or instance. Public wording can still be useful: “The item code is missing” gives a correction without disclosing a database query. If an incident needs deeper diagnosis, provide a correlation reference and use controlled server logs. Separate the audience for operational evidence from the audience for API recovery.
Run contract tests against representative errors, not only successful requests. Check that HTTP status and optional body status agree, the media type is correct, type values do not change with translated text, and each documented field has its promised type. Exercise invalid input, expired credentials, forbidden resources, missing items, temporary failure, and an interrupted request whose outcome is unknown. Ask a partner developer to explain the next safe action from the response and documentation. If they cannot tell whether to correct, wait, investigate, or stop, the problem response still needs work.
Create a small partner-facing error catalogue rather than leaving every development team to improvise wording. Each entry should name the stable type, the usual HTTP status, the business condition, what the caller may change, and whether waiting or contacting support is appropriate. Include one sanitized example request and response where the distinction is hard to understand. Record which fields are guaranteed and which are only diagnostic hints. This catalogue becomes a shared contract for application developers, support staff, and partner testers. It also makes an accidental change to a problem type visible during review, before an existing integration starts making the wrong recovery decision.
Consider what happens when an API gateway, proxy, or application framework produces an error before the business service runs. Those responses may not carry the same body as application errors, and the client must still be able to interpret the HTTP status safely. Decide which layer owns authentication failures, unavailable routes, oversized requests, and unexpected server faults. Test the actual response seen over the network, not only a service unit test that bypasses intermediaries. If a gateway rewrites the status or response body, document that behavior and fix conflicting signals. A polished application problem object cannot repair a contradictory response produced at another layer.
Finally, design for clients that cannot immediately upgrade. Adding a new problem type is easier to handle when the HTTP status remains correct and unknown types have a documented fallback, such as showing a safe message and asking an operator rather than guessing a retry rule. Retiring or redefining an existing type is more disruptive because partner software may already branch on it. Review changes as an API contract change, with examples in both supported languages. The goal is for a caller to make a conservative, correct decision even when it encounters a failure category it has never seen before.
Before you proceed
- Map each error to one safe caller action and a fitting HTTP status.
- Keep problem type stable and public detail safe to share.
- Test interrupted outcomes separately from explicit failures.


