Error Handling
Introdução
Todos os erros retornados pela BaaS API seguem um formato padrão estruturado, permitindo tratamento consistente e automatizado pelo cliente integrador. Cada erro inclui um código único, mensagem descritiva, HTTP status code, identificador de requisição e timestamp para auditoria e troubleshooting.
Formato Padrão de Erro
{
"error": "INVALID_REQUEST",
"code": "E00001",
"message": "Missing required field: email",
"statusCode": 400,
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2024-03-15T10:30:00Z"
}Campos obrigatórios:
error— Tipo genérico do erro (INVALID_REQUEST, UNAUTHORIZED, etc)code— Código único para identifying o erro específico (E00001–E99999)message— Descrição em linguagem natural da causastatusCode— HTTP status coderequestId— UUID da requisição (incluso em logs para rastreamento)timestamp— ISO 8601 timestamp do erro
Categorias de Erro
| Categoria | HTTP | Descrição | Retryable | Ação Recomendada |
|---|---|---|---|---|
| Validação | 400 | Request inválido (schema, formato, checksum) | Não | Validar antes de enviar; revisar documentação da API |
| Autenticação | 401 | Token expirado, inválido ou revogado | Sim (refresh) | Renovar token ou re-autenticar |
| Autorização | 403 | Sem permissão para recurso (scope, tenant, etc) | Não | Verificar credenciais e permissões |
| Não encontrado | 404 | Recurso não existe ou foi deletado | Não | Verificar ID e fazer requisição novamente |
| Conflito | 409 | Duplicata, state mismatch, violação única | Não | Usar idempotência; verificar estado atual |
| Rate limit | 429 | Limite de requisições excedido | Sim (backoff) | Aguardar + respeitar header Retry-After |
| Servidor | 5xx | Erro interno, serviço temporariamente indisponível | Sim (backoff) | Retry com exponential backoff; logar e alertar |
HTTP Status Codes
| Code | Tipo | Descrição |
|---|---|---|
200 | OK | Sucesso |
202 | Accepted | Requisição aceita, processamento assíncrono (ex: antifraud, onboarding) |
400 | Bad Request | Validação falhou (formato, required field, checksum inválido) |
401 | Unauthorized | Token expirado, inválido ou credenciais rejeitadas |
402 | Payment Required | Erro de dados específico (deprecated em favor de 400/422) |
403 | Forbidden | Acesso negado por permissão, tenant bloqueado ou antifraud |
404 | Not Found | Recurso não existe ou foi removido |
405 | Method Not Allowed | Verb HTTP não suportado para endpoint |
409 | Conflict | Duplicata, inconsistência de estado ou violação de constraint única |
422 | Unprocessable Entity | Request válida, mas falha na lógica de negócio (KYC, saldo insuficiente) |
429 | Too Many Requests | Rate limit excedido; respeitar Retry-After |
500 | Internal Server Error | Erro não-esperado no servidor |
503 | Service Unavailable | Serviço temporariamente indisponível (manutenção, deps down) |
Códigos de Erro por Endpoint
Authentication & Access
| Código | Message | Status | Causa |
|---|---|---|---|
E00101 | Invalid client credentials | 401 | Client ID ou Secret incorrect; tenant desativado |
E00102 | Token expired | 401 | Bearer token expirou (TTL padrão: 1h) |
E00103 | Invalid token format | 401 | Token malformado, assinatura inválida ou não-JWT |
E00104 | Token revoked | 401 | Token foi explicitamente revogado (logout, password reset) |
E00105 | Insufficient scope | 403 | Token válido mas sem scope necessário para operação |
E00106 | Tenant suspended | 403 | Tenant bloqueado por issue de billing ou compliance |
Bank Accounts & Onboarding
| Código | Message | Status | Causa |
|---|---|---|---|
E00201 | Invalid CPF/CNPJ | 400 | Documento inválido (checksum, formato ou blacklist) |
E00202 | Email already registered | 409 | Email duplicado no sistema (constraint única) |
E00203 | Missing required address field | 400 | Address (street, number, city, state, zip) incompleto |
E00204 | Onboarding failed | 422 | KYC rejeitado (documentos inválidos, PEP, sanção, liveness fail) |
E00205 | Account creation timeout | 504 | Provider BaaS demorou > 10s |
E00206 | Account already exists | 409 | Cliente já possui conta ativa neste tenant |
E00207 | Identity verification failed | 422 | Biometria, selfie ou OTP não validado |
PIX & Transfers
| Código | Message | Status | Causa |
|---|---|---|---|
E00301 | Invalid PIX key format | 400 | Email, telefone, CPF ou chave aleatória malformados |
E00302 | PIX key already registered | 409 | Chave PIX já existe para esta conta ou outro usuário |
E00303 | Insufficient balance | 422 | Saldo insuficiente para transferência ou taxa |
E00304 | PIX receiver not found | 404 | Chave PIX não existe (dict lookup falhou ou receiver não possui conta) |
E00305 | PIX reversal not allowed | 422 | Reversão só permitida dentro de 1h após transação |
E00306 | PIX key limit reached | 429 | Máximo de chaves PIX por conta atingido |
E00307 | Transfer in progress | 409 | Já existe transferência pendente com mesma chave/valor |
Billing & Charges
| Código | Message | Status | Causa |
|---|---|---|---|
E00401 | Invalid boleto amount | 400 | Valor < R$ 0.01 ou > R$ 999.999,99 |
E00402 | Recurring charge limit reached | 429 | Máximo de cobranças recorrentes por conta atingido |
E00403 | Charge already paid | 409 | Boleto já foi pago ou processado |
E00404 | Charge not found | 404 | Boleto não existe ou foi cancelado |
E00405 | Charge expiration invalid | 400 | Data de vencimento inválida (passada ou > 120 dias) |
Cards & Payments
| Código | Message | Status | Causa |
|---|---|---|---|
E00501 | Invalid card | 400 | Cartão malformado (número, CVC, data de validade) |
E00502 | Card expired | 422 | Data de validade expirada |
E00503 | Card blocked | 403 | Cartão bloqueado por fraude, antifraud ou solicitação do cliente |
E00504 | Card limit exceeded | 422 | Limite de crédito/débito excedido |
E00505 | Payment declined | 422 | Banco recusou transação (motivo não-específico da Axia) |
Tratamento por Tipo
4.1 Validação (400)
Característica: Erro do lado cliente; nunca retryar.
Ação:
- Validar input ANTES de enviar para API
- Usar biblioteca de validação (ex: Joi, Yup, Zod)
- Exibir mensagem clara ao usuário
- Logar para auditoria
Exemplos:
// Validar antes de enviar
if (!isValidCPF(cpf)) {
throw new ValidationError('Invalid CPF format');
}
if (!email.includes('@') || !email.includes('.')) {
throw new ValidationError('Invalid email format');
}
if (amount <= 0 || amount > 999999.99) {
throw new ValidationError('Amount must be between 0.01 and 999999.99');
}
// Request com erro de validação
const response = await fetch('/api/v1/accounts', {
method: 'POST',
body: JSON.stringify({ email: 'invalid-email', cpf: '12345' })
});
// Esperado: 400 Bad Request
// {
// "error": "INVALID_REQUEST",
// "code": "E00201",
// "message": "Invalid CPF format",
// "statusCode": 400
// }4.2 Rate Limit (429)
Característica: Retryável; respeitar backoff exponencial.
Ação:
- Extrair header
Retry-After(segundos) - Aguardar + retry automático
- Implementar circuit breaker após 5+ retries
- Logar para alertar DevOps se persistir
Exemplo:
async function requestWithBackoff(url: string, options: RequestInit, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60') * 1000;
console.warn(`Rate limited. Retrying after ${retryAfter}ms`);
await new Promise(r => setTimeout(r, retryAfter));
continue;
}
if (response.ok) return response;
if (response.status >= 500) {
// Exponential backoff para 5xx
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
await new Promise(r => setTimeout(r, delay));
continue;
}
return response; // 4xx não-retry
}
throw new Error('Max retries exceeded');
}4.3 Autenticação (401)
Característica: Retryável via refresh token.
Ação:
- Se
Token expired: usar refresh token para renovar - Se
Invalid client credentials: erro crítico (revisar .env) - Implementar refresh automático antes de expiração (TTL - 5 min)
Exemplo:
async function authenticatedRequest(endpoint: string, options: RequestInit) {
let token = getStoredToken();
let response = await fetch(endpoint, {
...options,
headers: { ...options.headers, 'Authorization': `Bearer ${token}` }
});
if (response.status === 401) {
const errorBody = await response.json();
if (errorBody.code === 'E00102') { // Token expired
token = await refreshAccessToken();
response = await fetch(endpoint, {
...options,
headers: { ...options.headers, 'Authorization': `Bearer ${token}` }
});
} else if (errorBody.code === 'E00101') { // Invalid credentials
throw new Error('Invalid client credentials — check .env');
}
}
return response;
}4.4 Servidor (5xx)
Característica: Retryável com backoff exponencial; alerta DevOps se persistir.
Ação:
- Retry com exponential backoff (1s, 2s, 4s, 8s, 16s, max 30s)
- Logar requestId para correlação com servidor
- Alertar após 3 falhas consecutivas
- Contatar suporte se > 5 min persistindo
Exemplo:
async function robustRequest(url: string, options: RequestInit) {
const maxRetries = 5;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status < 500) return response;
const error = await response.json();
const requestId = error.requestId;
if (attempt < maxRetries - 1) {
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
console.error(
`Server error (attempt ${attempt + 1}). RequestId: ${requestId}. ` +
`Retrying in ${delay}ms`
);
await new Promise(r => setTimeout(r, delay));
continue;
} else {
console.error(
`Request failed after ${maxRetries} attempts. RequestId: ${requestId}. ` +
`Contact support.`
);
throw new Error(`Server error: ${error.code}`);
}
} catch (err) {
if (attempt < maxRetries - 1) {
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
await new Promise(r => setTimeout(r, delay));
} else {
throw err;
}
}
}
}Troubleshooting por Cenário
"Account creation stuck in PROCESSING"
Causa: KYC lento, documento rejeitado ou provider BaaS indisponível.
Ação:
- Polling GET
/checkOnboardinga cada 30s (máximo 5 min) - Verificar no BackOffice > Auditoria > Onboarding se há rejection_reason
- Se timeout após 5 min: webhook deveria ter chegado; verificar logs do cliente
Exemplo:
async function waitForOnboarding(accountId: string, maxWaitMs = 300000) {
const pollInterval = 30000;
const startTime = Date.now();
while (Date.now() - startTime < maxWaitMs) {
const response = await fetch(`/api/v1/accounts/${accountId}/onboarding`);
const data = await response.json();
if (data.status === 'APPROVED') {
console.log('Account onboarded successfully');
return data;
}
if (data.status === 'REJECTED') {
throw new Error(`KYC rejected: ${data.rejectionReason}`);
}
await new Promise(r => setTimeout(r, pollInterval));
}
throw new Error('Onboarding timeout after 5 min');
}"PIX payment rejected: E00304 (PIX receiver not found)"
Causa: Chave PIX inválida no DICT (Directório de Identificadores de Transações PIX do Banco Central).
Ação:
- Verificar se chave PIX é válida no banco do destinatário
- Tentar novamente após 5 min (geralmente delay de replicação)
- Se persistir, contatar receiver para confirmar chave
Nota: Receiver precisa estar cadastrado no banco e ter chave ativa no DICT.
"Webhook não chegando"
Causa: HTTPS inválido, firewall, ou endpoint retornando erro.
Ação:
- Verificar se URL é HTTPS com certificado válido
- Verificar se endpoint está respondendo 200–299
- Logar headers recebidos em Axia (BackOffice > Auditoria > Webhooks)
- Se 5 falhas consecutivas: evento movido para DLQ (Dead Letter Queue)
- Usar endpoint de replay para reprocessar
Configuração de Webhook:
// Seu endpoint deve:
app.post('/webhook/axia', (req, res) => {
const event = req.body; // { type, data, timestamp, signature }
// Validar assinatura (HMAC-SHA256)
const isValid = validateWebhookSignature(event, WEBHOOK_SECRET);
if (!isValid) return res.status(401).send('Unauthorized');
// Responder 200 IMEDIATAMENTE (não processar de forma síncrona)
res.status(200).send('OK');
// Processar de forma assíncrona + idempotência por event_id
processEventAsync(event);
});Common Errors (Referência Rápida)
| Erro | Código | Causa | Solução |
|---|---|---|---|
| Token inválido | E00101–E00106 | Credenciais erradas ou token expirado | Re-autenticar ou renovar token |
| Conta não encontrada | E00206 | Account ID inválido | Verificar ID e fazer requisição novamente |
| Saldo insuficiente | E00303 | Balance < transfer amount | Verificar saldo antes de enviar |
| Transação duplicada | E00202–E00206 | Idempotência-Key reutilizada | Gerar nova Idempotency-Key (UUID) |
| Rate limit excedido | E00302, E00306, E00402, E00429 | Muitas requisições | Aguardar + implementar backoff |
| Serviço indisponível | 503 | Manutenção ou dependency down | Retry com backoff; contatar suporte |