Formato da resposta
{ "message_uuid": "...", "wamid": "..." }
{
"code": "WINDOW_CLOSED",
"message": "The 24-hour messaging window is closed. Send an approved template to reopen it."
}
{ code, message } — ambos os campos são garantidos.
Faça
switch sobre code: é estável e faz parte do contrato. O message
é texto humano de ajuda e pode ser refinado entre versões da API sem aviso.
As mensagens são entregues em inglês (padrão de indústria, mesmo padrão que
Stripe, GitHub ou Linear). Se precisar exibi-las traduzidas para o usuário
final, mapeie-as no seu cliente por code.Famílias de status
| HTTP | Significado | Repetir? |
|---|---|---|
2xx | Sucesso — 200 leitura, 201 criação, 202 aceito (async), 207 multi-status. | — |
4xx | Erro da requisição — auth, validação ou recurso inexistente. | Não, corrija antes. |
429 | Rate limit excedido. | Sim, após o Retry-After. |
5xx | Erro do servidor. | Sim, com backoff. |
Catálogo de códigos
O status HTTP de cada código é típico: o endpoint específico pode retornar
outro status se o contexto justificar. O authoritative por endpoint vive na
sua especificação OpenAPI. A tabela aqui é referência geral, não contrato
vinculante por endpoint.Os códigos de ambiguidade de resolução de conversa (
PHONE_NUMBER_AMBIGUOUS,
USERNAME_AMBIGUOUS) podem aparecer em
qualquer endpoint que aceite uma referência conversation por
phone/username/whatsapp_user_id, mesmo que sua especificação liste
outros códigos 409.Auth e tenant
| Code | HTTP | Descrição |
|---|---|---|
INVALID_API_TOKEN | 401 | O token não existe ou foi revogado. Gere um novo em Settings → API Token. |
TOKEN_BUSINESS_MISMATCH | 403 | O token não pertence ao slug do negócio na URL. Verifique que ambos se refiram ao mesmo negócio. |
Rate limit
| Code | HTTP | Descrição |
|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | Você excedeu o bucket de 60 req/min. Espere os segundos do header Retry-After. Ver Rate limits. |
Validação
| Code | HTTP | Descrição |
|---|---|---|
INVALID_REQUEST | 400 | O body não passou na validação de schema (campo faltante, tipo incorreto, valor fora do intervalo). |
INVALID_CURSOR | 400 | O cursor de paginação é inválido ou expirou. Reinicie a listagem sem cursor. |
BATCH_LIMIT_EXCEEDED | 400 | O grupo de ações excede o máximo permitido em uma única requisição. O message carrega o cap real. |
Conversa, contato e canal
| Code | HTTP | Descrição |
|---|---|---|
CONVERSATION_NOT_FOUND | 404 | O identificador de conversation (uuid, whatsapp_user_id, username ou phone) não resolve para nenhuma conversa do negócio. |
CONTACT_NOT_FOUND | 404 | O identificador de contato não resolve para nenhum do negócio. |
PHONE_NUMBER_AMBIGUOUS | 409 | Dois contatos distintos compartilham esse telefone no canal indicado (números reciclados / identidades separadas). Identifique a conversa por whatsapp_user_id ou uuid. O mesmo número em canais distintos não é ambíguo: channel o resolve. |
USERNAME_AMBIGUOUS | 409 | Dois contatos distintos compartilham esse username no canal indicado. Identifique a conversa por whatsapp_user_id ou uuid. O mesmo username em canais distintos não é ambíguo: channel o resolve. |
CHANNEL_NOT_FOUND | 404 | A channel (chave pública do canal) enviada na referência não resolve para nenhum canal do negócio. É obrigatória em toda requisição; copie-a em Configurações → Canais ou liste seus canais com GET /channels. |
CHANNEL_NOT_CONFIGURED | 422 | A conversa não tem um canal de WhatsApp configurado. Conecte um no dashboard antes de enviar. |
TESTER_CONVERSATION_NOT_WRITABLE | 422 | As conversas tester não aceitam mídia real: send_message com arquivo (file_uuid) é rejeitado. Texto, respostas rápidas e templates funcionam (simulados). |
TRANSCRIPTION_REQUIRED_TO_RESOLVE | 422 | A ação mark_resolved não pode fechar a conversa: ela tem um AI employee atribuído e mídia recebida com transcrição pendente. O AI monta seu prompt a partir do texto transcrito, então sem ele ficaria cego ao que o cliente enviou. Complete a transcrição manual pelo dashboard e tente novamente. Conversas atendidas por um humano não disparam este erro. |
TRANSCRIPTION_REQUIRED | 422 | A ação send_message inclui mídia (file_uuid) que a visão não consegue transcrever (tipo não suportado ou maior que 20 MB) e não inclui o campo transcription. Forneça a transcrição do arquivo na ação e tente novamente. É um erro por ação: avaliado durante a execução em background. |
Tags
| Code | HTTP | Descrição |
|---|---|---|
TAG_NOT_FOUND | 404 | A tag não existe para este negócio. |
TAG_ALREADY_ASSIGNED | 409 | A tag já está atribuída a esta conversa. |
TAG_NOT_ASSIGNED | 404 | A tag não está atribuída, então não pode ser removida. |
TAG_AMBIGUOUS | 409 | Há várias tags com esse nome. Use tag_uuid para desambiguar. |
TAG_BUSINESS_MISMATCH | 400 | A tag pertence a outro negócio. |
CANNOT_ASSIGN_DEFAULT_TAG | 422 | A tag é gerenciada pelo sistema (administrada pelo backend, ex.: a de conversão pendente) e não pode ser atribuída pela API. |
CANNOT_REMOVE_DEFAULT_TAG | 422 | A tag é gerenciada pelo sistema (administrada pelo backend, ex.: a de conversão pendente) e não pode ser removida pela API. |
Mailboxes e categorias
| Code | HTTP | Descrição |
|---|---|---|
CATEGORY_NOT_FOUND | 404 | A categoria de mailbox não existe para este negócio. |
CATEGORY_BUSINESS_MISMATCH | 403 | A categoria pertence a outro negócio. |
AMBIGUOUS_CATEGORY | 409 | Há várias categorias com esse nome. Use category: { uuid } para desambiguar. |
MAILBOX_NOT_FOUND | 404 | O mailbox não existe para este negócio. |
MAILBOX_ALREADY_ASSIGNED | 409 | A conversa já está nesse mailbox. |
AMBIGUOUS_MAILBOX | 409 | Há vários mailboxes com esse nome. Use mailbox: { uuid } para desambiguar. |
NO_MAILBOXES_IN_CATEGORY | 422 | A categoria não tem mailboxes configurados. Adicione pelo menos um no dashboard. |
Guards de pré-condição
| Code | HTTP | Descrição |
|---|---|---|
WINDOW_CLOSED | 422 | A janela de 24h está fechada. Envie um template aprovado para reabri-la. |
WALLET_BLOCKED | 402 | A wallet de tokens do modelo de AI requerido está vazia ou bloqueada. Recarregue para continuar. |
VISION_WALLET_BLOCKED | 402 | A wallet de vision tokens está vazia. O processamento de visão requer recarga. |
VISION_BLOCKED | 402 | A thread está bloqueada por visão (tokens de visão esgotados ou uma recarga de tokens que falhou), ou a mídia recebida ficou sem transcrição depois que a visão terminou. Recarregue, ou adicione a transcrição da mídia no dashboard, antes de tentar novamente. |
NO_AI_EMPLOYEE_ASSIGNED | 422 | A conversa não tem um funcionário AI atribuído. Atribua um antes de executar a ação. |
Schedules (mensagens programadas)
| Code | HTTP | Descrição |
|---|---|---|
OWNER_MISMATCH | 422 | O executor do scheduled message não coincide com o owner atual da conversa. Reatribua ou cancele o schedule primeiro. |
SCHEDULE_CONFLICT | 409 | O schedule não pôde ser salvo devido a uma mudança concorrente ou uma requisição duplicada na conversa: outra requisição está criando, substituindo ou cancelando um schedule ao mesmo tempo, ou esta requisição reutiliza um scheduled_uuid que já existe. Se a conversa tinha um schedule anterior, esta mesma requisição já o cancelou, portanto um GET reflete o estado real (normalmente sem schedule pending). Para tentar novamente, omita o scheduled_uuid (o servidor gera um) ou use um novo: reutilizar o scheduled_uuid que causou o conflito retorna um 409 permanente. |
Funcionários AI e execução
| Code | HTTP | Descrição |
|---|---|---|
AI_EMPLOYEE_NOT_FOUND | 404 | O funcionário AI não existe para este negócio. |
AMBIGUOUS_AI_EMPLOYEE | 409 | Há vários funcionários com esse nome. Use ai_employee: { uuid } para desambiguar. |
AI_EMPLOYEE_ALREADY_ASSIGNED | 409 | Esse funcionário AI já está atribuído à conversa. |
INVALID_ASSIGNEE_FOR_RUN_AI | 409 | A conversa é human-owned e nenhum ai_employee foi especificado. Passe um ou reatribua um AI primeiro. |
AI_EXECUTION_FAILED | 500 | A execução do AI falhou inesperadamente. Tente novamente; se persistir, verifique o dashboard do funcionário. |
ACTIONS_DEPTH_EXCEEDED | 422 | Ações de AI encadeadas excedem a profundidade máxima permitida em uma requisição. |
Scheduled message action
| Code | HTTP | Descrição |
|---|---|---|
SCHEDULED_MESSAGE_ACTION_REQUIRED | 400 | Há um scheduled message ativo na conversa. Especifique scheduled_message_action (reassign ou cancel). |
SCHEDULED_MESSAGE_ACTION_INVALID | 400 | O valor de scheduled_message_action é inválido. Deve ser reassign ou cancel. |
Uploads
| Code | HTTP | Descrição |
|---|---|---|
INVALID_FILE_TYPE | 400 | O tipo de arquivo não é permitido. Veja a documentação para a lista de MIME types aceitos. |
FILE_TOO_LARGE | 400 | O arquivo excede o tamanho máximo da sua categoria (imagem 5 MB, vídeo/áudio 16 MB, documento 100 MB; text/plain tem um limite próprio de 5 MB). |
STORAGE_QUOTA_EXCEEDED | 413 | O negócio ultrapassou sua cota de storage, ou tem o storage desabilitado (quota_bytes = 0). Libere espaço ou faça upgrade do plano; se o storage estiver desabilitado, contate o suporte. |
STORAGE_QUOTA_CLEANUP_INSUFFICIENT | 507 | O storage está cheio e a limpeza automática não conseguiu liberar espaço suficiente para este upload. Libere espaço ou faça upgrade do plano. |
FILE_NOT_FOUND | 404 | O file_uuid não resolve para a operação solicitada: não existe, não é deste negócio, ou não está no estado que esse endpoint exige (em /files/confirm o arquivo deve continuar pending — um já confirmado ou rejeitado também dá 404; no download de comprovantes deve ser um comprovante confirmado do paymentUuid solicitado). O detalhe por endpoint vive na sua especificação OpenAPI. |
FILE_NOT_UPLOADED | 404 | O binário não chegou ao Storage, ou um blob vazio/parcial ocupa o path. Peça um novo /request-upload e refaça o PUT — um re-PUT no mesmo upload_url falha com Duplicate se o path já está ocupado. |
MIME_MISMATCH | 400 | O MIME type real não coincide com o declarado. Re-suba com o Content-Type correto. |
UPLOAD_FAILED | 500 | O upload não pôde ser concluído por um erro de storage. Tente novamente. |
TOO_MANY_PENDING_UPLOADS | 429 | O negócio tem uploads demais sem confirmar. Confirme ou deixe expirar seus uploads pendentes antes de pedir mais. Tente novamente após os segundos do header Retry-After. |
Mensagens
| Code | HTTP | Descrição |
|---|---|---|
PREPARE_FAILED | 500 | A mensagem não pôde ser preparada (erro de DB ou upstream). Tente novamente. |
SEND_FAILED | 502 | O envio ao WhatsApp falhou. Verifique a saúde do canal e tente novamente. |
BSUID_SEND_DISABLED | 409 | O contato não tem telefone e o envio por identidade BSUID (business-scoped user ID) não está habilitado na plataforma. Não é uma configuração por conta: não há nada para habilitar do seu lado. |
PAYMENT_MARKER_UNKNOWN | 422 | O texto contém um marcador de pagamento que não existe no catálogo (normalmente um erro de digitação). A mensagem inteira é bloqueada: corrija o nome do marcador e envie novamente. |
PAYMENT_MARKER_DATA_UNAVAILABLE | 422 | A conversa não tem o dado que o marcador pede — por exemplo, um perfil apenas com link de pagamento não tem CLABE. Repare os dados de pagamento da conversa antes de reenviar. |
PAYMENT_MARKER_UNSUPPORTED_FIELD | 422 | O marcador está em um campo que não admite substituição: o cabeçalho, o rodapé ou o título de um botão de uma mensagem interativa, ou o cabeçalho de texto / os parâmetros de botão de um template. Nesses campos o tamanho é validado sobre o texto que você envia — medindo o marcador, não o dado —, então substituir poderia estourar o limite da Meta na entrega. Os marcadores só funcionam no corpo da mensagem ou nas variáveis do corpo de um template. |
PAYMENT_MARKER_NOT_ALLOWED_IN_TEMPLATE | 400 | Reservado. As variáveis do corpo de um template sim substituem marcadores desde a v0.3.0; o que não os admite é o cabeçalho e os botões, e isso devolve PAYMENT_MARKER_UNSUPPORTED_FIELD. Nenhum endpoint emite este código hoje. |
TEMPLATE_BODY_TOO_LONG | 422 | O corpo do template, já com as variáveis interpoladas, ultrapassa os 1024 caracteres da Meta. Qualquer variável longa pode estourá-lo; o caso típico é um marcador substituído por um dado mais longo que ele mesmo (uma CLABE tem 18 caracteres e ==clabe_spei== tem 14). Encurte o texto do template ou o valor da variável. |
PAYMENT_PROFILE_GENERATION_FAILED | 500 | Não havia dados de pagamento para esta conversa e a geração falhou. Tente novamente em alguns instantes. |
Respostas rápidas e templates
| Code | HTTP | Descrição |
|---|---|---|
QUICK_REPLY_NOT_FOUND | 404 | A resposta rápida não existe para este negócio. |
QUICK_REPLY_AMBIGUOUS | 409 | Há várias respostas rápidas com esse nome. Use quick_reply: { uuid } para desambiguar. |
QUICK_REPLY_EMPTY | 422 | A resposta rápida não tem ações configuradas. Adicione pelo menos uma no dashboard. |
TEMPLATE_NOT_FOUND | 404 | O template não existe para este negócio. |
TEMPLATE_NOT_APPROVED | 422 | O template não está aprovado pela Meta. Aprovação é requisito para envio. |
AUTH_TEMPLATE_REQUIRES_PHONE | 409 | Não é possível enviar um template de autenticação a um contato sem telefone: a Meta exige o número. Envie a um contato com telefone. |
TEMPLATE_AMBIGUOUS | 409 | O mesmo nome e language existe em 2 ou mais canais de WhatsApp conectados. A requisição não permite escolher a qual canal o template pertence, então a ambiguidade não pode ser resolvida pela integração. Entre em contato com o suporte para resolver a colisão. |
TEMPLATE_VARIABLES_INVALID | 422 | As variáveis do body não coincidem com o template (contagem incorreta, índice faltante ou valor vazio). |
TEMPLATE_HEADER_MISMATCH | 400 | O tipo de header não coincide com o que o template declara (ex: template espera imagem e você enviou texto). |
TEMPLATE_HEADER_TRANSCRIPTION_MISSING | 422 | O header de mídia do template (em send_message com template, ou no depreciado send_quick_reply_or_template) não pode ser transcrito pela visão (tipo não suportado ou maior que 20 MB) e falta o campo header.transcription. Forneça a transcrição do header e tente novamente. É um erro por ação: avaliado durante a execução em background. |
TEMPLATE_FAKE_REQUIRES_TESTER_CONVERSATION | 422 | O template é do módulo Tester (fake) e só pode ser enviado a conversas tester. |
Pagamentos
| Code | HTTP | Descrição |
|---|---|---|
PAYMENT_NOT_FOUND | 404 | Não existe pagamento com esse paymentUuid para este negócio. |
Operações genéricas
| Code | HTTP | Descrição |
|---|---|---|
FETCH_FAILED | 500 | Não foi possível ler os dados necessários para concluir a requisição. Tente novamente. |
UPDATE_FAILED | 500 | A alteração não pôde ser aplicada (erro de DB). Tente novamente. |
UNKNOWN_ERROR | 500 | Erro inesperado. Contate o suporte se persistir. |