Erros
Todos os erros da API Ozzie seguem um formato consistente. Quando uma requisição falha, o corpo da resposta sempre contém um objeto error com um code legível por máquina, uma message legível por humano e um array details opcional com contexto adicional.
Formato da resposta de erro
{
"error": {
"code": "ERROR_CODE",
"message": "Uma descrição legível do que deu errado.",
"details": []
}
}
| Campo | Tipo | Descrição |
|---|---|---|
error.code | string | Código de erro legível por máquina — use para tratamento programático |
error.message | string | Descrição legível do erro |
error.details | array | Contexto adicional opcional, como quais campos falharam na validação |
Códigos de erro
INVALID_JSON
| Status HTTP | 400 Bad Request |
|---|---|
| Quando ocorre | O corpo da requisição não pôde ser analisado como JSON |
| Como resolver | Verifique se o header Content-Type é application/json e que o corpo é JSON válido. Problemas comuns: vírgulas no final, chaves sem aspas, aspas simples ao invés de duplas. |
VALIDATION_ERROR
| Status HTTP | 422 Unprocessable Entity |
|---|---|
| Quando ocorre | O corpo da requisição é JSON válido mas contém valores de campo inválidos |
| Como resolver | Verifique o array details — cada entrada identifica o campo específico e a falha de validação. |
UNAUTHORIZED
| Status HTTP | 401 Unauthorized |
|---|---|
| Quando ocorre | O header Authorization está ausente, malformado ou contém credenciais inválidas |
| Como resolver | Verifique se o token está codificado corretamente como base64(client_id:client_secret). |
FORBIDDEN
| Status HTTP | 403 Forbidden |
|---|---|
| Quando ocorre | Suas credenciais são válidas, mas você está tentando acessar um recurso que pertence ao usuário de outro cliente |
| Como resolver | Verifique se o user_id no caminho pertence a um usuário que você criou sob seu client_id. |
NOT_FOUND
| Status HTTP | 404 Not Found |
|---|---|
| Quando ocorre | O recurso solicitado não existe |
| Como resolver | Verifique se o ID na URL está correto e que o recurso foi criado antes de tentar recuperá-lo. |
CONFLICT
| Status HTTP | 409 Conflict |
|---|---|
| Quando ocorre | A requisição conflita com o estado atual de um recurso. Mais comumente: tentar criar um usuário com um external_user_id que já existe. |
| Como resolver | Use GET /users?external_user_id=... para verificar se já existe antes de criar. |
INTAKE_REQUIRED
| Status HTTP | 422 Unprocessable Entity |
|---|---|
| Quando ocorre | Você chamou um endpoint que requer um intake financeiro (ex: POST /plan), mas nenhum intake foi enviado. |
| Como resolver | Chame POST /users/{user_id}/financial-intake primeiro. |
PLAN_REQUIRED
| Status HTTP | 422 Unprocessable Entity |
|---|---|
| Quando ocorre | Você chamou um endpoint que requer um plano (ex: POST /money-moves/generate), mas nenhum plano foi gerado. |
| Como resolver | Chame POST /users/{user_id}/plan primeiro. |
PERSONALITY_REQUIRED
| Status HTTP | 422 Unprocessable Entity |
|---|---|
| Quando ocorre | POST /plan/personalize foi chamado sem o campo personality_type no corpo. |
| Como resolver | Inclua personality_type no corpo da requisição. Valores válidos: "optimizer", "planner", "avoider", "spender". |
RATE_LIMIT_EXCEEDED
| Status HTTP | 429 Too Many Requests |
|---|---|
| Quando ocorre | Seu cliente enviou mais requisições do que o limite de taxa permite. |
| Como resolver | Aguarde até o tempo especificado no header X-RateLimit-Reset, depois tente novamente. Implemente backoff exponencial. |
INTERNAL_ERROR
| Status HTTP | 500 Internal Server Error |
|---|---|
| Quando ocorre | Ocorreu um erro inesperado nos servidores do Ozzie. |
| Como resolver | Tente novamente após um breve delay. Se o erro persistir, verifique a página de status do Ozzie. |
Estratégia de retentativa
| Código de erro | Tentar novamente? | Estratégia |
|---|---|---|
INVALID_JSON | Não | Corrija a requisição |
VALIDATION_ERROR | Não | Corrija os campos inválidos |
UNAUTHORIZED | Não | Corrija as credenciais |
FORBIDDEN | Não | Você está acessando o recurso errado |
NOT_FOUND | Não | O recurso não existe |
CONFLICT | Não | O recurso já existe |
INTAKE_REQUIRED | Não | Redirecione o usuário para completar o intake |
PLAN_REQUIRED | Não | Chame POST /plan primeiro |
RATE_LIMIT_EXCEEDED | Sim | Aguarde X-RateLimit-Reset, depois tente novamente |
INTERNAL_ERROR | Sim | Tente novamente com backoff exponencial |
Exemplo de backoff exponencial
async function retryableRequest(method, path, body, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await ozzieRequest(method, path, body);
} catch (err) {
const isRetryable =
err.message.includes('RATE_LIMIT_EXCEEDED') ||
err.message.includes('INTERNAL_ERROR');
if (!isRetryable || attempt === maxRetries) throw err;
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
await new Promise(r => setTimeout(r, delay));
}
}
}