Pular para o conteúdo principal

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": []
}
}
CampoTipoDescrição
error.codestringCódigo de erro legível por máquina — use para tratamento programático
error.messagestringDescrição legível do erro
error.detailsarrayContexto adicional opcional, como quais campos falharam na validação

Códigos de erro

INVALID_JSON

Status HTTP400 Bad Request
Quando ocorreO corpo da requisição não pôde ser analisado como JSON
Como resolverVerifique 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 HTTP422 Unprocessable Entity
Quando ocorreO corpo da requisição é JSON válido mas contém valores de campo inválidos
Como resolverVerifique o array details — cada entrada identifica o campo específico e a falha de validação.

UNAUTHORIZED

Status HTTP401 Unauthorized
Quando ocorreO header Authorization está ausente, malformado ou contém credenciais inválidas
Como resolverVerifique se o token está codificado corretamente como base64(client_id:client_secret).

FORBIDDEN

Status HTTP403 Forbidden
Quando ocorreSuas credenciais são válidas, mas você está tentando acessar um recurso que pertence ao usuário de outro cliente
Como resolverVerifique se o user_id no caminho pertence a um usuário que você criou sob seu client_id.

NOT_FOUND

Status HTTP404 Not Found
Quando ocorreO recurso solicitado não existe
Como resolverVerifique se o ID na URL está correto e que o recurso foi criado antes de tentar recuperá-lo.

CONFLICT

Status HTTP409 Conflict
Quando ocorreA 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 resolverUse GET /users?external_user_id=... para verificar se já existe antes de criar.

INTAKE_REQUIRED

Status HTTP422 Unprocessable Entity
Quando ocorreVocê chamou um endpoint que requer um intake financeiro (ex: POST /plan), mas nenhum intake foi enviado.
Como resolverChame POST /users/{user_id}/financial-intake primeiro.

PLAN_REQUIRED

Status HTTP422 Unprocessable Entity
Quando ocorreVocê chamou um endpoint que requer um plano (ex: POST /money-moves/generate), mas nenhum plano foi gerado.
Como resolverChame POST /users/{user_id}/plan primeiro.

PERSONALITY_REQUIRED

Status HTTP422 Unprocessable Entity
Quando ocorrePOST /plan/personalize foi chamado sem o campo personality_type no corpo.
Como resolverInclua personality_type no corpo da requisição. Valores válidos: "optimizer", "planner", "avoider", "spender".

RATE_LIMIT_EXCEEDED

Status HTTP429 Too Many Requests
Quando ocorreSeu cliente enviou mais requisições do que o limite de taxa permite.
Como resolverAguarde até o tempo especificado no header X-RateLimit-Reset, depois tente novamente. Implemente backoff exponencial.

INTERNAL_ERROR

Status HTTP500 Internal Server Error
Quando ocorreOcorreu um erro inesperado nos servidores do Ozzie.
Como resolverTente 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 erroTentar novamente?Estratégia
INVALID_JSONNãoCorrija a requisição
VALIDATION_ERRORNãoCorrija os campos inválidos
UNAUTHORIZEDNãoCorrija as credenciais
FORBIDDENNãoVocê está acessando o recurso errado
NOT_FOUNDNãoO recurso não existe
CONFLICTNãoO recurso já existe
INTAKE_REQUIREDNãoRedirecione o usuário para completar o intake
PLAN_REQUIREDNãoChame POST /plan primeiro
RATE_LIMIT_EXCEEDEDSimAguarde X-RateLimit-Reset, depois tente novamente
INTERNAL_ERRORSimTente 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));
}
}
}