Formato e catálogo de erros
Envelope {error, code}, catálogo completo de status codes / error codes da API WaBlast.
Envelope de erro
Toda resposta de erro (4xx/5xx) usa o mesmo envelope:
{
"error": "Mensagem legível (pt-BR)",
"code": "MACHINE_READABLE_CODE"
}
error— texto humano, pt-BR, pode mudar.code— discriminador estável; use sempre ocodena sua lógica, nunca o texto.
Sucesso retorna o JSON do recurso cru (sem envelope { success, data }).
Sempre que for reagir programaticamente a um erro, compare contra o code (string estável), não contra o texto em error.
Catálogo de status codes / error codes
| HTTP | code | Quando |
|---|---|---|
| 400 | INVALID_BODY | Validação Zod falhou (mensagem do primeiro erro incluída) |
| 400 | BAD_REQUEST | Erro 4xx de framework (multipart inválido, content-type, parse de body) |
| 400 | NO_FILE | Upload multipart sem o campo file |
| 400 | TEMPLATE_PENDING | Tentativa de editar template com status PENDING |
| 400 | INVALID_URL | URL inválida ou não-https — vale para url de webhook e para redirect_uri/origin de onboarding |
| 400 | FORBIDDEN_URL | URL de webhook aponta para IP privado/loopback (proteção SSRF) |
| 400 | INVALID_DOMAIN | Domínio de onboarding malformado, ou aponta para localhost/rede interna/IP literal |
| 400 | REDIRECT_URI_NOT_ALLOWED | Host do redirect_uri não está registrado como domínio REDIRECT ativo |
| 400 | ORIGIN_NOT_ALLOWED | Host do origin não está registrado como domínio EMBED ativo |
| 401 | UNAUTHENTICATED | API key ausente, inválida, revogada ou expirada |
| 402 | SUBSCRIPTION_REQUIRED | Assinatura inativa (e fora de período de graça válido) |
| 402 | NO_FREE_SLOT | Sem slot de conexão livre para criar sessão de onboarding |
| 403 | CONTACT_OPTED_OUT | Contato marcado como blocked (opt-out LGPD) |
| 404 | ACCOUNT_NOT_FOUND | Conexão WhatsApp não existe ou é de outro usuário |
| 404 | MESSAGE_NOT_FOUND | Mensagem não existe ou é de outro usuário |
| 404 | TEMPLATE_NOT_FOUND | Template não existe ou é de outro usuário |
| 404 | ENDPOINT_NOT_FOUND | Webhook endpoint não existe ou é de outro usuário |
| 404 | DELIVERY_NOT_FOUND | Delivery não existe ou é de outro usuário |
| 404 | QR_CODE_NOT_FOUND | QR code não existe ou é de outro usuário |
| 404 | MEDIA_NOT_FOUND | Mídia não existe ou já foi apagada |
| 404 | NOT_FOUND | Rota inexistente |
| 409 | WINDOW_CLOSED | Mensagem free-form (texto/mídia) fora da janela de 24h — use template |
| 409 | ACCOUNT_TOKEN_INVALID | Token Meta da conexão expirou — reconecte no painel |
| 409 | IDEMPOTENCY_IN_FLIGHT | POST com a mesma Idempotency-Key ainda processando |
| 409 | ENDPOINT_LIMIT | Limite de 10 webhook endpoints por usuário atingido |
| 409 | REPLAY_NOT_ALLOWED | Delivery não está em estado replayável (já em fila/in-flight) |
| 409 | DOMAIN_LIMIT_REACHED | Limite de 20 domínios de onboarding por conta atingido |
| 409 | DOMAIN_NOT_REGISTERED | Domínio de embed ainda não registrado na Meta do nosso lado |
| 409 | SESSION_UNUSABLE | Sessão de onboarding inexistente, expirada, já usada ou token errado (mensagem única de propósito) |
| 410 | MEDIA_EXPIRED | Mídia recebida apagada pela Meta ~7 dias após o recebimento |
| 413 | — | Arquivo de mídia maior que o limite (64 MB no gateway) |
| 422 | META_ERROR | Meta rejeitou a operação (mensagem da Meta no error) |
| 429 | RATE_LIMITED | Cota por minuto da chave excedida (+ Retry-After) |
| 429 | META_RATE_LIMIT | Meta retornou 429 (+ Retry-After opcional) |
| 429 | TIER_DAILY_CAP_REACHED | Cap diário do tier Meta atingido |
| 500 | INTERNAL_ERROR | Exceção não tratada |
| 502 | MEDIA_DOWNLOAD_FAILED | Falha ao baixar a mídia na Meta |