Pular para o conteúdo principal

Errors

A API usa um formato uniforme de erro para todas as respostas não-2xx.


Formato

{
"error": {
"code": "PHONE_NOT_FOUND",
"message": "Phone not found",
"details": { "phoneId": "5f7b2e1c-..." }
}
}

O corpo do erro é sempre envelopado em error — leia response.error.code, não response.code.

CampoTipoDescrição
error.codestringIdentificador estável da causa (use no seu código)
error.messagestringDescrição human-readable (em inglês ou português; não dependa do conteúdo)
error.detailsobject | undefinedContexto adicional (varia por erro)

HTTP status code segue convenções REST. Você pode confiar no code antes do message.

Erros de validação Zod retornam (o details é o flatten() do Zod — formErrors + fieldErrors):

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"formErrors": [],
"fieldErrors": { "secret": ["String must contain at least 16 character(s)"] }
}
}
}

Catálogo completo

4xx — erros do cliente

400 Bad Request

CodeOrigemDescrição
VALIDATION_ERRORZodBody/query/params não passou no schema
WABA_CREDENTIALS_REQUIREDPOST /v1/phonestype=WABA sem credentials
WABA_CREDS_INCOMPLETETemplatesPhone WABA sem wabaPhoneNumberId/accessToken/businessAccountId
WABA_CREDS_MISSINGTemplatesToken decryptado vazio
WABA_TOKEN_MISSINGVáriosToken WABA não decifrável
QR_NOT_APPLICABLEGET /:id/qrcodePhone não é BAILEYS
PAIRING_NOT_APPLICABLEPOST /:id/pairing-codePhone não é BAILEYS
LOOKUP_UNSUPPORTED_CHANNELPOST /v1/lookupPhone não é BAILEYS
MISSING_PHONE_IDMedia uploadHeader X-Phone-Id ausente
RECORDING_EMPTYPOST /v1/calls/:id/recordingBody não é Buffer ou tamanho 0
INVALID_TOSendto malformado
INVALID_JIDBaileys sendJID inválido após normalização
INVALID_TOKENPOST /:id/rotate-tokenNovo token não passou na validação Meta
UNSUPPORTED_TYPESendtype não suportado no canal
TEMPLATE_NOT_SUPPORTED_BAILEYSSendtype=template enviado para phone BAILEYS (templates são WABA-only)
CAPTION_TOO_LARGESendLegenda/texto excede o limite de bytes do WhatsApp (details: { bytes, maxBytes, field })
IG_CREDS_MISSINGSend InstagramPhone sem igUserId/igAccessToken
CPF_CNPJ_REQUIREDBillingAccount sem cpfCnpj ao criar customer no Asaas
EMPTY_BATCHLookup/BlockArray vazio
BATCH_TOO_LARGELookup/Block>100 itens
SCHEDULE_TOO_SOONPOST /v1/messages/scheduledscheduledAt <agora + 5s
FLOW_NOT_SYNCEDFlowsFlow ainda não tem metaFlowId

401 Unauthorized

CodeQuando
AUTH_MISSINGSem X-API-Key em endpoint protegido
AUTH_INVALIDKey inexistente
AUTH_REVOKEDKey revogada via POST /v1/admin/api-keys/:id/revoke
AUTH_EXPIREDexpiresAt passou

402 Payment Required

CodeQuando
ACCOUNT_SUSPENDEDAccount em dunning SUSPENDED (14+ dias atraso). Cliente precisa pagar (/v1/billing/invoices/:id/issue) ou contatar admin para reativar

403 Forbidden

CodeQuando
ACCOUNT_INACTIVEAccount CANCELLED ou outro status ≠ ACTIVE
ADMIN_FORBIDDENEndpoint /v1/admin/* sem X-Admin-Token válido

404 Not Found

CodeQuando
PHONE_NOT_FOUNDPhone inexistente, não é WABA quando exigido, ou de outra account
MESSAGE_NOT_FOUNDmessageId (UUID do gateway) inexistente
MESSAGE_KEY_NOT_FOUNDmessageId fora do cache (TTL 7d) — operações react/edit/delete impossíveis
MEDIA_NOT_FOUNDMedia UUID inexistente
TEMPLATE_NOT_FOUNDTemplate inexistente
SCHEDULED_NOT_FOUNDScheduled message inexistente
IDENTITY_NOT_FOUNDKey não resolveu para nenhuma identidade no phone
TASK_NOT_FOUNDLookup task inexistente ou expirada
FLOW_NOT_FOUNDFlow inexistente
GROUP_NOT_FOUNDWABA Group inexistente
CALL_NOT_FOUNDCall inexistente
INVOICE_NOT_FOUNDInvoice inexistente
DELIVERY_NOT_FOUNDWebhook delivery inexistente
RECORDING_NOT_FOUNDCall sem recording upload
ACCOUNT_NOT_FOUNDAdmin: account inexistente
PLAN_NOT_FOUNDAdmin: billing plan code inexistente
NO_PUBLIC_KEYFlow sem keypair gerado (não é data_exchange)

409 Conflict

CodeQuando
ALREADY_CONNECTEDGET /qrcode ou POST /pairing-code em phone já CONNECTED
ALREADY_DELIVEREDPOST /v1/events/:id/replay em delivery já entregue
PHONE_NOT_CONNECTEDSend/op em phone não CONNECTED
SCHEDULED_NOT_PENDINGPATCH/DELETE em scheduled com status ≠ PENDING
TEMPLATE_NOT_SUBMITTEDPATCH /templates/:id antes do metaTemplateId
GROUP_SUSPENDEDOperação em group suspended=true

410 Gone

CodeQuando
MEDIA_EXPIREDTTL 7d passou
MEDIA_DELETEDACK explícito já fez delete

425 Too Early

CodeQuando
QR_NOT_READYQR ainda não emitido pelo Worker — tente em 1-2s
PAIRING_NOT_READYPairing code ainda não gerado

429 Too Many Requests

CodeQuando
RATE_LIMITEDExcedeu 600 req/min (300 em /v1/messages). Header Retry-After indica espera
SCHEDULE_QUOTA_EXCEEDED>10.000 scheduled messages PENDING

5xx — erros do servidor

500 Internal Server Error

CodeQuando
INTERNAL_ERRORCatch-all para exceções não mapeadas (não exposto detalhe)
BAILEYS_NO_IDBaileys não retornou ID na mensagem enviada
FORM_DATA_MISSINGUpload multipart corrompido
IG_TOKEN_BADToken Instagram falhou validação
KEYPAIR_INVALIDGeração de keypair RSA falhou
META_NO_ID / META_NO_CALL_IDMeta retornou OK sem ID na resposta
QUOTED_KEY_INVALIDMensagem citada sem whatsappMessageId rastreado — não dá pra reconstruir a citação
WABA_TOKEN_INVALIDToken armazenado falhou decrypt

503 Service Unavailable

CodeQuando
ADMIN_DISABLEDServidor sem ADMIN_TOKEN configurado
ASAAS_NOT_CONFIGUREDServidor sem ASAAS_API_KEY
ASAAS_CONNECTION_ERRORFalha de conexão com a API do Asaas (transiente — retry)
IG_NOT_CONFIGUREDServidor sem credenciais Instagram
META_APP_ID_MISSINGGET /waba/embedded-signup/config sem META_APP_ID
META_APP_NOT_CONFIGUREDPOST /waba/embedded-signup sem META_APP_ID/META_APP_SECRET

Erros transientes vs definitivos

Retry com backoff para:

  • 503/502/500
  • 425 QR_NOT_READY, 425 PAIRING_NOT_READY
  • 429 RATE_LIMITED (respeitando Retry-After)

NÃO retry para:

  • 4xx exceto os acima (corrige a request)
  • 402 ACCOUNT_SUSPENDED (até pagar)
  • 404/409/410 (semânticos, não vão mudar com retry)

Códigos Meta repassados

Algumas operações WABA propagam códigos Meta diretamente no message ou details. Os mais comuns:

Meta codeSignificado
131026Recipient not on WhatsApp
131047Re-engagement message — 24h window fechada, precisa template
131051Mensagem fora da janela 24h
131057Account spamming / restricted
132000-132099Template-related (rejected, paused, not approved)
133010Phone number not registered
133015Phone re-registration required
190Access token expirado
4 / 17 / 32Rate limit Meta (META_RATE_LIMIT em logs)

Quando estes aparecem no failedReason de messages_sent, ação típica:

  • Token expirado → POST /v1/phones/:id/rotate-token
  • Janela 24h → use template
  • Recipient not on WhatsApp → POST /v1/lookup antes (Baileys-only) ou aceite custo de FAILED

Códigos Instagram

IG codeSignificado
4 / 17Rate limit (IG_RATE_LIMIT)
190Token expirado — re-OAuth
100Parâmetro inválido (ex.: IGSID inexistente)

Boas práticas

  1. Code é estável; message não. Faça switch em code, nunca em message.
  2. Sempre logue code + details quando capturar — facilita troubleshooting.
  3. Implemente fallback para INTERNAL_ERROR — pode ser bug do gateway. Reporte com X-Request-Id (response header).
  4. Diferencie 402 de 4xx. ACCOUNT_SUSPENDED exige fluxo de cobrança UX, não pode ser tratado como "input ruim".