Error codes
Every error response uses the envelope documented in Error handling. This page is the canonical reference.
HTTP status × code matrix
| Status | Code | Endpoints | Cause | Example body |
|---|---|---|---|---|
| 400 | invalid_json |
both | Request body could not be parsed (malformed JSON for /v1/calculate; unparseable CSV or empty body for /v1/calculate/bulk) |
{"error": {"code": "invalid_json", "message": "Expecting value: line 1 column 1 (char 0)"}} |
| 401 | unauthenticated |
both | Missing or malformed Authorization header |
{"error": {"code": "unauthenticated", "message": "Authorization header is required"}} |
| 401 | invalid_token |
both | Token format is wrong | {"error": {"code": "invalid_token", "message": "Token format is invalid"}} |
| 403 | expired_token |
both | Token has passed its expiration | {"error": {"code": "expired_token", "message": "Token has expired"}} |
| 403 | revoked_token |
both | Token has been explicitly revoked | {"error": {"code": "revoked_token", "message": "Token has been revoked"}} |
| 406 | unsupported_media_type |
bulk | Accept header lists no supported response type |
{"error": {"code": "unsupported_media_type", "message": "Accept header lists no supported response type. Supported: text/csv"}} |
| 415 | unsupported_media_type |
both | Content-Type header is missing or not in the endpoint's accepted set |
{"error": {"code": "unsupported_media_type", "message": "Use application/json"}} |
| 422 | validation_error |
single | Pydantic body validation failed (missing required field, wrong type, unknown enum) | {"error": {"code": "validation_error", "message": "Invalid request", "details": [...]}} |
| 422 | field_validation |
single | Engine-level field validation failed (typically a prior_disbursement_* exceeding the pre-drop max) |
{"error": {"code": "field_validation", "field_errors": {"terms_0_priorDisbursementSub": "Cannot exceed $4,500"}}} |
| 500 | internal_error |
both | Unexpected server-side failure; sanitized message | {"error": {"code": "internal_error", "message": "Unable to calculate. Please check your inputs and try again."}} |
Reserved (not yet returned)
One code is reserved in the OpenAPI spec for upcoming rate-limiting work and is not yet returned by any endpoint.
| Status | Code | Reserved meaning |
|---|---|---|
| 429 | quota_exceeded |
Account has hit rate or usage limits |
See Authentication for details on rate limits.
Match on code, not message
The code value is part of the v1 stability contract and will not change. The message text may be improved over time. Match on code.