Errors
Every error has the same shape and a stable code your code can branch on.
When a request fails, the status code says what kind of failure it is and the body says exactly which:
{
"statusCode": 404,
"code": "lead.notFound",
"message": "Lead 0192f0c1-7a3e-7c51-9d2e-4b7f0a1c2d3e not found",
"params": { "id": "0192f0c1-7a3e-7c51-9d2e-4b7f0a1c2d3e" }
}codeis the contract. It never changes meaning, so branch on it.messageis English for you, the developer. Don't show it to your users or parse it.paramsholds the values the code refers to, such as the id that wasn't found.
Validation errors
A request whose body or query doesn't validate gets 400 request.invalid, with one entry per failing field:
{
"statusCode": 400,
"code": "request.invalid",
"message": "Request validation failed",
"params": {},
"issues": [{ "field": "companyName", "constraints": ["isLength"] }]
}Codes you will meet
| Status | Code | What to do |
|---|---|---|
| 400 | request.invalid | Fix the fields listed in issues. |
| 401 | auth.unauthenticated | Check the credential: missing, mistyped, revoked or expired. |
| 403 | auth.forbidden | The credential lacks params.permission. |
| 404 | lead.notFound | The lead doesn't exist in your organization. |
| 409 | resource.conflict | The change conflicts with the current state; read it again and retry. |
| 413 | request.tooLarge | Send a smaller body. |
| 429 | request.rateLimited | Wait for Retry-After seconds, then retry. |
| 500 | server.internal | Retry later. If it persists, the problem is ours. |
| 503 | server.unavailable | Retry with backoff. |
New codes may be added at any time; treat an unknown code by its status.
Was this page helpful?