Responses & Error Codes
This page is the canonical reference for the format of every API response — success and error. All examples below are real responses from the production API.
Standard error format
Every error returns Content-Type: application/json with a detail field:
- business/authorization errors →
detailis a string; - payload validation errors (
422) →detailis a list of per-field problems.
{ "detail": "API key inválida" }
Status table
| HTTP | When it happens | detail (real example) |
|---|---|---|
200 | Success | route-specific body |
401 | Missing or invalid API key | API key required |
403 | Invalid/expired key, IP not allowed, or insufficient scope | Scope insuficiente para esta API key |
404 | Resource not found (analysis, medical record) | Análise não encontrada |
409 | Conflict (resource already exists) | Prontuário já existe para este patient_reference |
422 | Invalid payload (validation) | list of per-field errors |
429 | Request rate limit exceeded | Rate limit excedido |
503 | Dependency unavailable / service busy | Serviço ocupado. Tente novamente. |
504 | Analysis exceeded the endpoint time limit | A análise excedeu o tempo limite. Tente novamente em instantes. |
401 — Not authenticated
Missing or invalid X-API-Key header.
{ "detail": "API key required" }
403 — Not authorized
Several scenarios return 403, always with a string detail:
{ "detail": "API key inválida" }
{ "detail": "API key expirada" }
{ "detail": "IP não permitido para esta API key" }
{ "detail": "Scope insuficiente para esta API key" }
On scope-named routes (e.g. medical records), the message states the required scope:
{ "detail": "Escopo insuficiente: requer prontuario:write" }
404 — Not found
{ "detail": "Análise não encontrada" }
{ "detail": "Prontuário não encontrado" }
409 — Conflict
{ "detail": "Prontuário já existe para este patient_reference" }
422 — Invalid payload
Schema validation. detail is a list: each item points to the field (loc), the
error type (type) and the message (msg).
{
"detail": [
{
"type": "missing",
"loc": ["body", "medications"],
"msg": "Field required",
"input": { "language": "pt-BR" }
}
]
}
429 — Rate limit
Returned when the organization's per-minute or monthly limit is exceeded. Honor the
Retry-After header (when present) and apply exponential backoff.
{ "detail": "Rate limit excedido" }
503 — Service unavailable
A critical dependency is temporarily unavailable (e.g. rate limiter/cache) or the service is under load protection. It is safe to retry after a short interval.
{ "detail": "Serviço ocupado. Tente novamente." }
504 — Timeout
The analysis did not finish within the endpoint time limit (load protection). Retry;
complete responses are cached and tend to return quickly on the retry.
{ "detail": "A análise excedeu o tempo limite. Tente novamente em instantes." }
Error-handling best practices
- Always treat
401/403as a credential/scope error (do not retry without fixing). - On
422, readdetail[].locto point the user to the invalid field. - On
429/503/504, use retry with backoff (e.g. 1s, 2s, 4s) with a max attempt cap. - For the interactions route, remember the fail-safe policy: a technical failure never
lowers the risk — check
analysis_status(complete | partial | failed) andsource_coverageto know how complete the analysis is.
Note:
detailmessages are returned by the API in Portuguese; the table and notes above describe their meaning in English.