Errors
Error body, `ERROR_*` codes, status codes and retry guidance.
Fields not declared in the DTOs are rejected, including inside nested objects. Every REST failure uses the same body; there is no separate error field anymore.
Error format
json
{
"statusCode": 400,
"code": "ERROR_VALIDATION",
"message": "Request validation failed",
"details": [
{
"field": "customer.taxId",
"code": "ERROR_INVALID_TAX_ID",
"message": "Invalid tax ID"
}
],
"requestId": "9f1fc995-4ee4-4a92-b285-cf8dff227a97"
}Decide by code and HTTP status. message is always an English string (never an array) meant for diagnostics. details is optional: for validation it is an array of { field, code, message }; for application errors it holds typed public objects. requestId matches the X-Request-Id header and can be quoted to support. 5xx failures use sanitized messages with no internal details.
HTTP status codes
| HTTP | Usage |
|---|---|
| 200 / 201 / 202 | Action completed / resource created / asynchronous processing accepted. |
| 204 | Operation completed with no body. |
| 400 | Invalid DTO, parameter, JSON, UUID, limit or cursor. |
| 401 / 403 | Missing or invalid authentication / access denied (scope, endpoint not enabled for API keys, blocked company). |
| 404 | Resource not found, including resources of another tenant. |
| 409 / 410 | Conflict (duplicate CNPJ, idempotency conflict, documents not ready yet) / resource retired. |
| 413 / 415 | Payload too large / unsupported encoding. |
| 422 | Fiscal validation in the domain or a rejected business rule (readiness, certificate, quota). |
| 429 | Rate limit or cooldown; honor Retry-After. |
| 500 / 502 / 503 / 504 | Internal error / invalid dependency / unavailability / timeout. |
Common codes
| code | When it happens |
|---|---|
ERROR_VALIDATION | Invalid body or query; see details[]. |
ERROR_INVALID_LIMIT | limit outside 1–1000 or not an integer (400). |
ERROR_INVALID_CURSOR | Tampered cursor, or one from another collection, tenant or filter (400). |
ERROR_RATE_LIMIT_EXCEEDED | Request limit exceeded (429). |
ERROR_INSUFFICIENT_CREDITS / ERROR_QUOTA_EXCEEDED | Not enough credits or quota to issue. |
ERROR_COMPANY_NOT_READY / ERROR_COMPANY_BLOCKED | Company without an active certificate in live, or blocked. |
ERROR_IDEMPOTENCY_CONFLICT | Same Idempotency-Key with a different payload (409). |
ERROR_TAX_REGIME_NOT_SUPPORTED | Only MEI and Simples Nacional companies are supported (422). |
ERROR_VALIDATION with details[].code ERROR_DEDUCTION_NOT_ALLOWED_FOR_REGIME or ERROR_SIMPLES_SUBLIMIT_NOT_SUPPORTED | A deduction from the ISS base that a MEI or a Simples company cannot declare, or a Simples company above a sublimit (regApTribSN 2 or 3), which is not supported yet (422). |
ERROR_GONE | Retired operation, such as one-off credit purchases (410). |
Best practices
- For non-2xx responses, keep the status,
codeandrequestIdin diagnostics — never log the API key. - Retry with backoff on 429/503; on 429 wait for
Retry-After. On issuance, preserve the idempotency key and the payload. - Do not repeat validation errors without fixing the data listed in
details.