Erros
A API usa os status HTTP de sempre: 2xx deu certo, 4xx tem algo a corrigir na requisição e 5xx é problema do nosso lado ou do WhatsApp.
Formato
Seção intitulada “Formato”Todo erro tem o mesmo corpo JSON:
{ "error": { "type": "invalid_request_error", "code": "missing_field", "message": "Informe `to` ou `contact_id`.", "param": "to", "request_id": "req_6f1d2c3b4a5e" }}| Campo | Descrição |
|---|---|
type |
Categoria do erro (veja abaixo). |
code |
Código estável e específico. Use este campo no seu código para decidir o que fazer. |
message |
Explicação em português para humanos. Pode mudar de texto; não compare strings com ele. |
param |
Campo que causou o erro, quando houver (ex.: to, send_at). |
request_id |
Identificador da requisição — o mesmo valor do cabeçalho X-Request-Id. |
Toda resposta (de sucesso ou de erro) traz o cabeçalho X-Request-Id. Registre-o nos seus logs e envie para o suporte quando precisar de ajuda com uma chamada específica.
Tipos (type)
Seção intitulada “Tipos (type)”type |
Significado |
|---|---|
invalid_request_error |
A requisição tem algum problema (JSON, campos, parâmetros). |
authentication_error |
Chave ausente, inválida, revogada ou expirada. |
permission_error |
A chave não tem permissão para a ação (ex.: chave somente leitura). |
not_found_error |
O recurso ou a rota não existe. |
conflict_error |
Conflito de estado ou de Idempotency-Key. |
channel_error |
Problema com o canal de envio (ex.: WhatsApp desconectado). |
rate_limit_error |
Limite de requisições por minuto excedido. |
api_error |
Erro inesperado do nosso lado. |
Códigos (code)
Seção intitulada “Códigos (code)”| HTTP | code |
Quando acontece | O que fazer |
|---|---|---|---|
| 400 | invalid_json |
O corpo não é um JSON válido. | Confira aspas, vírgulas e o cabeçalho Content-Type: application/json. |
| 400 | missing_field |
Faltou um campo obrigatório (param diz qual). |
Envie o campo. Ex.: to ou contact_id em POST /messages. |
| 400 | invalid_field |
Um campo tem valor ou formato inválido (param diz qual). |
Corrija o valor: UUID malformado, data no passado, texto longo demais, limit fora de 1–100… |
| 400 | invalid_phone |
O telefone não parece um número válido. | Envie com DDI e DDD, ex.: 5511999998888. |
| 401 | missing_api_key |
Nenhuma chave foi enviada. | Envie Authorization: Bearer tt_live_.... |
| 401 | invalid_api_key |
Chave inexistente ou digitada errada. | Copie a chave de novo ou crie outra. |
| 401 | revoked_api_key |
A chave foi revogada. | Crie uma chave nova no painel. |
| 401 | expired_api_key |
A validade da chave acabou. | Crie uma chave nova no painel. |
| 403 | read_only_key |
Chave somente leitura tentou escrever (POST, PATCH, DELETE). |
Use uma chave com acesso total. |
| 404 | resource_not_found |
O ID não existe (ou é de outra organização). | Confira o ID. Ex.: o contato foi apagado no painel. |
| 404 | route_not_found |
O caminho não existe. | Confira a URL: ela começa com /v1/ e usa os nomes em inglês (/contacts, /messages…). |
| 405 | method_not_allowed |
O caminho existe, mas não aceita esse método. | Ex.: PUT em vez de PATCH. Veja a referência. |
| 409 | idempotency_conflict |
A mesma Idempotency-Key foi usada com um corpo diferente. |
Gere uma chave nova para cada operação diferente. Veja Idempotência. |
| 409 | invalid_state |
A ação não é possível no estado atual do recurso. | Ex.: cancelar uma mensagem agendada que já foi enviada, gerar QR Code para um WhatsApp já conectado, editar uma mensagem depois de 15 minutos, pausar uma campanha que não está enviando. Busque o recurso e confira o status. |
| 422 | channel_unavailable |
Não há WhatsApp conectado para enviar (ou o canal escolhido está desconectado). Em campanhas: não há número do WhatsApp Oficial conectado. | Reconecte o canal com POST /channels/{channel_id}/connect (ou no painel, em Configurações → Conexões). Para campanhas, conecte o WhatsApp Oficial no painel, em Campanhas. |
| 422 | limit_reached |
Um limite da conta foi atingido: o máximo de conexões de WhatsApp do plano (POST /channels) ou 10 webhooks por organização (POST /webhooks). |
Remova itens que não usa mais (ou reconecte um canal existente em vez de criar outro). Para mais conexões, faça upgrade do plano no painel. |
| 429 | rate_limit_exceeded |
Mais de 120 requisições no mesmo minuto com a mesma chave. | Espere os segundos do cabeçalho Retry-After. Veja Limites de uso. |
| 500 ou 502 | internal_error |
Erro inesperado do nosso lado. | Tente de novo com espera progressiva. Se persistir, fale com o suporte com o request_id. |
| 502 | provider_error |
O WhatsApp recusou a operação. Num envio, a mensagem fica registrada com status failed. Ao conectar, o WhatsApp não devolveu o QR Code ou o código de pareamento. |
Leia a message. Confira se o número tem WhatsApp e se a mídia é acessível. Não repita em loop. |
| 503 | service_unavailable |
A API está temporariamente indisponível. | Tente de novo com espera progressiva. Use Idempotency-Key em POST. |
| 504 | timeout |
A requisição demorou demais para ser respondida (ex.: o WhatsApp demorou para gerar o QR Code). | Tente de novo com a mesma Idempotency-Key: se a primeira tiver dado certo, você recebe a resposta original. |
Repare que há dois 422 com type diferentes: limit_reached é invalid_request_error e channel_unavailable é channel_error.
{ "error": { "type": "invalid_request_error", "code": "limit_reached", "message": "Seu plano permite 3 conexões de WhatsApp. Remova uma ou faça upgrade no painel.", "request_id": "req_6f1d2c3b4a5e" }}Como tratar os erros no código
Seção intitulada “Como tratar os erros no código”- Decida pelo
code, não pelamessage. - Erros
4xxnão melhoram com retentativa (exceto429): corrija a requisição. 429,500,503,504e falhas de rede podem ser repetidos com espera progressiva (ex.: 1 s, 2 s, 4 s…). EnvieIdempotency-KeyemPOSTpara não duplicar nada.502 provider_erroré uma recusa do WhatsApp para aquela mensagem: repetir em sequência raramente ajuda e pode prejudicar o número.
async function toptalking(path, options = {}) { const res = await fetch(`https://platform.toptalking.com.br/v1${path}`, { ...options, headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}`, 'Content-Type': 'application/json', ...options.headers, }, }); const body = await res.json(); if (!res.ok) { const { code, message, request_id } = body.error; const err = new Error(`[${res.status} ${code}] ${message} (request_id: ${request_id})`); err.status = res.status; err.code = code; err.retryAfter = Number(res.headers.get('Retry-After')) || null; throw err; } return body;}