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)"}} |
| 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)
These codes are reserved in the OpenAPI spec for the upcoming authentication work. No endpoint returns them today.
| Status | Code | Reserved meaning |
|---|---|---|
| 401 | unauthenticated |
Missing or malformed Authorization header |
| 401 | invalid_token |
Token format is wrong |
| 403 | expired_token |
Token has passed its expiration |
| 403 | revoked_token |
Token has been explicitly revoked |
| 429 | quota_exceeded |
Account has hit rate or usage limits |
See Authentication for the rollout plan.
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.