Errors
Stable string codes you can branch on. HTTP status carries the severity; code carries the contract.
Error envelope
{
"code": "validation.invalid_value",
"message": "place_of_supply must be a valid GST state code.",
"field": "place_of_supply",
"details": { "received": "INKA" }
}Errors are flat — no nested error wrapper. Branch on code, show message to humans, use field + details for form validation.
Auth errors
| Code | HTTP | Meaning |
|---|---|---|
auth.missing_token | 401 | No Authorization header. |
auth.invalid_token | 401 | Token unknown or malformed. |
auth.revoked_token | 401 | Token was explicitly revoked. |
auth.expired_token | 401 | Token past its expires_at. |
auth.insufficient_scope | 403 | Token lacks the required scope. |
auth.org_mismatch | 403 | ?organization_id disagrees with single-org token. |
auth.missing_organization_id | 400 | Multi-org token needs ?organization_id. |
auth.no_membership | 403 | User has no active membership in that org. |
Validation errors
| Code | HTTP | Meaning |
|---|---|---|
validation.required_field | 400 | A required field is missing. |
validation.invalid_value | 400 | Wrong type or out of range. |
validation.failed | 422 | Body or query parameters failed schema. |
Resource errors
| Code | HTTP | Meaning |
|---|---|---|
not_found.resource | 404 | Resource doesn't exist in this org. |
conflict.duplicate | 409 | Anti-duplicate guard rejected the create. |
rate_limit.exceeded | 429 | Per-token rate limit hit. Retry-After header set. |