Erros e Limites
Códigos de erro, rate limit, limites de uso e estratégias de retry para a API da EvoluAI.
Erros e Limites
Códigos HTTP
| Código | Significado | Causa mais comum |
|---|---|---|
200 | OK | Sucesso |
400 | Bad Request | Parâmetros inválidos ou ausentes |
401 | Unauthorized | API Key inválida, expirada ou ausente |
403 | Forbidden | Sem permissão para o recurso |
404 | Not Found | Recurso não existe |
422 | Unprocessable | Áudio inválido ou transcrição falhou |
429 | Too Many Requests | Rate limit atingido |
500 | Internal Server Error | Erro interno — tente novamente |
Formato das respostas de erro
Todos os erros seguem o mesmo formato:
{
"error": {
"message": "Descrição do erro",
"code": "CODIGO_TRPC",
"data": {
"httpStatus": 400,
"issues": []
}
}
}Erros comuns
401 — Unauthorized
{
"error": {
"message": "Unauthorized",
"code": "UNAUTHORIZED"
}
}Causas:
X-API-Keyausente no header- API Key inválida ou mal formatada
- API Key revogada pelo administrador
- API Key expirada (se foi criada com data de expiração)
Solução: Verifique a chave via GET /trpc/user.me. Se retornar 401, gere uma nova chave no dashboard.
403 — Forbidden
{
"error": {
"message": "Access denied",
"code": "FORBIDDEN"
}
}Causas:
- Tentativa de acessar análises de outra empresa
- Papel (
role) sem permissão para a operação (ex:salespersontentando listar outros usuários) - Tentativa de deletar recurso de outro usuário
400 — Bad Request
{
"error": {
"message": "Invalid input",
"code": "BAD_REQUEST",
"data": {
"issues": [
{
"path": ["salespersonId"],
"message": "Required"
},
{
"path": ["audioUrl"],
"message": "Must be a valid HTTPS URL"
}
]
}
}
}Causas frequentes:
salespersonIdnão informado emanalysis.create- Nenhum dos campos
audioUrl,audioKeyoutranscriptinformado - URL de áudio usando HTTP (não HTTPS)
- Formato de data inválido em filtros
422 — Unprocessable
{
"error": {
"message": "Audio processing failed",
"code": "UNPROCESSABLE_CONTENT"
}
}Causas:
- Arquivo de áudio corrompido ou formato não suportado
- Áudio muito curto (menos de 5 segundos)
- Áudio sem voz detectável (silêncio total)
- URL do áudio inacessível no momento do processamento
Formatos aceitos: MP3, WAV, M4A, OGG, FLAC, WebM
429 — Rate Limit
{
"error": {
"message": "Rate limit exceeded",
"code": "TOO_MANY_REQUESTS"
}
}Limite: 60 requisições por minuto por API Key.
Quando atingido, aguarde 60 segundos antes de tentar novamente. Use a estratégia de retry com backoff exponencial abaixo.
Créditos insuficientes
{
"error": {
"message": "Insufficient credits to process analysis",
"code": "PAYMENT_REQUIRED"
}
}Causa: Saldo de créditos zerado ou abaixo do mínimo para processar o áudio.
Solução: Verifique o saldo com GET /trpc/credits.getSummary e adquira mais créditos pelo dashboard antes de continuar.
Créditos não são debitados em caso de erro. Se uma análise falhar (422, 500), nenhum crédito é consumido.
Limites da API
Rate limit
| Recurso | Limite |
|---|---|
| Requisições por minuto | 60 req/min por API Key |
| API Keys simultâneas | 10 por empresa |
Limites de arquivo e áudio
| Recurso | Limite |
|---|---|
| Tamanho máximo do arquivo | 40 MB |
| Duração máxima do áudio | 2 horas |
| Duração mínima do áudio | 5 segundos |
Limites de paginação
| Recurso | Padrão | Máximo |
|---|---|---|
analysis.list — itens por página | 20 | 100 |
credits.getHistory — itens por página | 20 | 20 (fixo) |
Estratégia de retry com backoff exponencial
Para erros 429 (rate limit) e 500 (erro interno), use retry com backoff exponencial para evitar sobrecarga:
async function fetchComRetry(url, options, maxTentativas = 3) {
for (let tentativa = 0; tentativa < maxTentativas; tentativa++) {
const res = await fetch(url, options);
// Sucesso
if (res.ok) return res.json();
const erro = await res.json();
// Rate limit — aguarda e tenta novamente
if (res.status === 429) {
const espera = Math.pow(2, tentativa) * 1000; // 1s, 2s, 4s
console.warn(`Rate limit atingido. Aguardando ${espera}ms...`);
await new Promise(r => setTimeout(r, espera));
continue;
}
// Erro interno — tenta novamente com backoff
if (res.status === 500) {
if (tentativa === maxTentativas - 1) throw new Error(`Erro 500 após ${maxTentativas} tentativas`);
const espera = Math.pow(2, tentativa) * 2000; // 2s, 4s, 8s
await new Promise(r => setTimeout(r, espera));
continue;
}
// Erros 4xx (exceto 429) — não tenta novamente
throw Object.assign(new Error(erro.error?.message || 'Erro na requisição'), {
status: res.status,
code: erro.error?.code
});
}
}
// Uso
const dados = await fetchComRetry(
'https://api.evolu-ai.com/trpc/analysis.create',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.EVOLUA_API_KEY
},
body: JSON.stringify({ json: { salespersonId: 'user_abc', audioUrl: '...' } })
}
);Erros de validação Zod
Para requisições POST, os erros de validação incluem detalhes por campo:
{
"error": {
"message": "Invalid input",
"code": "BAD_REQUEST",
"data": {
"issues": [
{
"path": ["audioUrl"],
"message": "Invalid url"
},
{
"path": ["clientName"],
"message": "String must contain at most 255 character(s)"
}
]
}
}
}Use o array issues para identificar exatamente qual campo está inválido e exibir mensagens de erro precisas ao usuário final.