Todos os caminhos desta documentação são relativos à base URL abaixo.
Por exemplo, POST /session/{number}/send-message corresponde a https://wpp.dw.hml.2wa.com.br/session/{number}/send-message.
Todas as rotas exigem o header x-api-key com uma API Key ativa.
Gerencie suas API Keys na página API Keys.
Todas as rotas possuem limite de requisições por minuto. Quando excedido, a API retorna 429 Too Many Requests.
| Header | Descrição |
|---|---|
| X-RateLimit-Limit | Limite de requisições por minuto da sua conta |
| X-RateLimit-Remaining | Requisições restantes na janela atual |
| X-RateLimit-Reset | Timestamp (Unix) quando a janela reseta |
O limite padrão é 60 req/min. Caso precise de mais, contate o administrador.
POST /session/connect — Inicia uma nova conexão e retorna um tempIdGET /session/pending/{tempId}/qr — Obtenha o QR code para escanearPOST /session/pending/{tempId}/pairing-code — Obtenha um código numérico de 8 caracteres para vincular sem QRGET /session/pending/{tempId}/status — Monitore até conectar; a resposta incluirá o phone_numberInicia uma nova conexão WhatsApp. Retorna um ID temporário para acompanhar o processo.
| Campo | Tipo | Descrição |
|---|---|---|
| webhookUrl | string | URL para receber eventos via webhook |
| displayName | string | Nome de exibição do número |
| language | string | en ou pt-BR (padrão: en). Idioma do campo error nos webhooks deste número. Só pode ser definido aqui, no pareamento |
| proxyHost | string | Host do proxy |
| proxyPort | integer | Porta do proxy |
| proxyUser | string | Usuário do proxy |
| proxyPass | string | Senha do proxy |
| proxyType | string | http ou socks5 (padrão: http) |
| phoneNumber | string | Obrigatório na sua conta. Telefone da conexão (ex: 5548992211646). É o número que será validado no Ella Smart antes de a conexão existir. Aceita máscara e aceita ficar sem o código do país, mas enviar com ele é o mais seguro |
A sua conta está configurada para só conectar número que esteja cadastrado no Ella Smart e com acesso ativo. Por isso o phoneNumber é obrigatório aqui: ele é consultado antes de qualquer coisa, e a conexão só é criada se a consulta liberar.
A validação é refeita em outros três momentos, porque o cadastro pode mudar depois: no código de pareamento, na restauração das conexões quando o servidor reinicia, e de hora em hora enquanto o número está no ar. Um número que perde o acesso (mensalidade vencida, cadastro removido) é desconectado na primeira dessas passagens e você recebe session_disconnected com reason: "not_authorized".
| Resposta | O que aconteceu |
|---|---|
| 403 NUMBER_NOT_AUTHORIZED | O Ella Smart respondeu. O campo reason diz o motivo: NOT_FOUND (número não cadastrado) ou NO_ACTIVE_ACCESS (cadastro existe, acesso não está ativo) |
| 503 VALIDATION_UNAVAILABLE | Não foi possível consultar agora. Não é recusa do número: tente de novo em alguns instantes. A conexão não é criada sem confirmação |
| 400 MISSING_PHONE_NUMBER | O phoneNumber não foi informado |
| 400 INVALID_PHONE_NUMBER | O phoneNumber não tem entre 10 e 15 dígitos |
Nenhuma dessas respostas traz tempId. O fluxo para aí: não há conexão pendente para acompanhar e não há QR para exibir. Mostre o motivo para a dona do número em vez de seguir para a tela de pareamento.
Se o QR for lido por um aparelho com número diferente do autorizado, a sessão não é dada por pronta e o número não entra em operação. Nesse caso o GET /session/pending/{tempId}/status responde connected: false com sessionStatus: "disconnected", e o motivo chega no session_disconnected com detail: "PHONE_MISMATCH".
Para avisar a dona do número antes de abrir a tela de pareamento, consulte GET /session/number-access.
Retorna o QR code da sessão pendente como imagem base64.
Faça polling a cada 2-3 segundos até obter o QR. Se status: false, o QR ainda não está pronto.
O telefone informado aqui tem que ser o mesmo que foi autorizado no POST /session/connect. Se for outro, a resposta é 400 PHONE_MISMATCH e a mensagem diz qual era o esperado. O acesso no Ella Smart também é conferido de novo: se ele caiu entre o cadastro e o pareamento, a resposta é 403 NUMBER_NOT_AUTHORIZED.
Alternativa ao QR code. Retorna um código numérico de 8 caracteres para vincular o dispositivo. No celular, vá em Dispositivos Vinculados > Vincular com número de telefone e insira o código.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| phoneNumber | string | Sim | Número do telefone a vincular (ex: 5511999998888) |
O código expira em ~60 segundos. Pode solicitar novo código na mesma sessão. Nota: após solicitar pairing code, o QR code não será mais emitido naquela sessão.
Monitora o status da conexão pendente. Quando conectado, retorna o número de telefone.
O tempId expira após 5 minutos se não for escaneado.
Todas usam o número de telefone como identificador (ex: 5511999998888).
Lista todos os números conectados da sua conta com status em tempo real.
Diz se um número pode conectar, sem tentar conectar. Serve para avisar a dona do número antes de abrir a tela de pareamento, em vez de deixar o cadastro falhar na frente dela.
| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| phone | Sim | Telefone a consultar, entre 10 e 15 dígitos. Aceita formatado, e aceita sem o código do país, mas enviar com ele é o mais seguro |
| reason | Descrição |
|---|---|
| OK | Cadastrado e com acesso ativo. O allowed vem true |
| NOT_FOUND | Número não está cadastrado no Ella Smart |
| NO_ACTIVE_ACCESS | Cadastro existe, mas o acesso não está ativo |
Número recusado também responde 200: a pergunta foi respondida, e o allowed é o que decide. Só 503 VALIDATION_UNAVAILABLE significa que não houve resposta. O name vem null quando o número não está cadastrado.
Retorna o status da sessão de um número específico.
Use o connected para decidir se pode enviar mensagem agora. O sessionStatus detalha a situação:
| sessionStatus | Descrição |
|---|---|
| connected | Número em operação, pronto para enviar e receber |
| connecting | Sessão subindo, ou religando depois de uma oscilação. O número não saiu do ar: não há o que fazer além de aguardar |
| disconnected | Número fora do ar. Precisa ser conectado de novo |
A conexão com o WhatsApp Web oscila várias vezes por dia por conta do próprio servidor, quase sempre com retomada em segundos. Durante essas oscilações a resposta é connecting, e não disconnected, justamente para a sua tela não mostrar o número como caído sem ele ter caído.
Envia uma mensagem de texto.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| to | string | Sim | Número destino (ex: 5511999998888) |
| isGroup | boolean | Não | Marca que o to é o id de um grupo. Dispensável se o to já vier com @g.us |
| message | string | Sim | Texto da mensagem |
| humanMode | boolean | Não | Simula digitação antes de enviar: manda "digitando..." e espera um tempo proporcional ao texto |
O messageId pode ser usado para rastrear o status de entrega via GET /session/{number}/messages/{messageId}/status.
O to aceita o id do grupo com o sufixo, ou o id puro junto de isGroup. A segunda forma existe para responder direto com o que veio no webhook, sem precisar montar o JID:
Grupo não passa pela checagem de cadastro no WhatsApp, que só existe para número individual. Se o grupo não existir ou o seu número não participar dele, quem recusa é o WhatsApp e o erro volta como SEND_ERROR com o texto original. Vale o mesmo para send-media, schedule-message e schedule-media.
Envia arquivo. Aceita dois formatos: upload (multipart/form-data) ou base64 (application/json).
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| to | string | Sim | Número destino |
| isGroup | boolean | Não | Marca que o to é o id de um grupo. Dispensável se o to já vier com @g.us |
| file | file | Sim | Arquivo a enviar |
| caption | string | Não | Texto de legenda (imagens, vídeos, documentos) |
| sendAudioAsVoice | boolean | Não | Enviar áudio como mensagem de voz |
| humanMode | boolean | Não | Simula digitação antes de enviar: manda "digitando..." e espera um tempo proporcional ao texto |
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| to | string | Sim | Número destino |
| isGroup | boolean | Não | Marca que o to é o id de um grupo. Dispensável se o to já vier com @g.us |
| base64 | string | Sim | Conteúdo do arquivo em base64 |
| filename | string | Sim | Nome do arquivo (ex: foto.jpg) |
| mimetype | string | Sim | Tipo MIME (ex: image/jpeg) |
| caption | string | Não | Texto de legenda (imagens, vídeos, documentos) |
| sendAudioAsVoice | boolean | Não | Enviar áudio como mensagem de voz |
| humanMode | boolean | Não | Simula digitação antes de enviar: manda "digitando..." e espera um tempo proporcional ao texto |
O WhatsApp entrega áudio apenas nestes formatos. Enviar fora da lista faz a mensagem ser descartada pelo WhatsApp sem aviso, por isso ela é recusada aqui.
| Formato do arquivo | Situação | Observação |
|---|---|---|
| OGG/Opus | Entregue | O ideal para mensagem de voz (sendAudioAsVoice) |
| MP3 | Entregue | |
| MP4 / M4A / AAC | Entregue | |
| AMR | Entregue | |
| WebM | Recusado | Retorna 400 com UNSUPPORTED_AUDIO_FORMAT. Converta para um dos formatos acima |
| WAV | Recusado | |
| FLAC | Recusado |
Não é preciso acertar o texto do mimetype: ele é conferido contra o conteúdo do arquivo e ajustado no envio. Mandar audio/ogg com um arquivo OGG/Opus tem o mesmo efeito de mandar audio/ogg; codecs=opus. A mesma regra vale para schedule-media, que recusa já no agendamento.
Consulta o status de entrega de uma mensagem enviada, usando o messageId retornado por send-message ou send-media.
O status evolui conforme o WhatsApp confirma a entrega. Cada mudança também dispara o webhook message_status_updated.
| Status | Significado |
|---|---|
| sent | Mensagem enviada pelo gateway |
| server | Recebida pelo servidor do WhatsApp |
| delivered | Entregue no aparelho do destinatário |
| read | Lida pelo destinatário |
| failed | Falha no envio |
Retorna 404 se o messageId não for encontrado para esse número.
Lista os contatos individuais do WhatsApp conectado, com o número e o nome de cada um.
O name sempre vem preenchido e cai para o próprio número quando o WhatsApp não informou nome. Use o hasName para saber se o nome é de verdade, e não exibir o número como se fosse nome.
Contatos cujo telefone o WhatsApp ainda não informou ficam de fora da lista, porque o identificador interno não serve para exibir nem para enviar mensagem.
Grupos não entram nesta lista. Para vê-los, use GET /session/{number}/chats.
A agenda não chega junto com a conexão. Ela vem numa sincronização própria, que começa depois do pareamento e leva de segundos a alguns minutos. Quem consulta nesse intervalo recebe poucos contatos, ou nenhum, e a resposta continua sendo 200.
O campo syncing existe para essa situação. Quando vem true, a lista ainda está sendo preenchida: trate como "ainda não terminou", e não como "este número não tem contatos". Uma consulta que encontra a lista vazia também pede a agenda ao WhatsApp antes de responder, então a consulta seguinte tende a já vir completa.
Para importar com segurança, repita a consulta até o syncing vir false, com alguns segundos entre as tentativas. Consultas em sequência rápida não aceleram nada, porque há uma espera mínima entre dois pedidos de agenda do mesmo número.
Retorna detalhes de um contato específico, incluindo foto de perfil. O contactId é o JID do contato (ex.: 5521988887777@s.whatsapp.net).
profilePicUrl é null quando o contato não tem foto ou não permite a visualização.
Verifica quais números têm WhatsApp, antes de tentar enviar. Aceita um número ou até 50 separados por vírgula, numa consulta só.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| numbers | string | Sim | Um número, ou até 50 separados por vírgula |
A ordem da resposta acompanha a da consulta. O registeredNumber nem sempre é igual ao que foi perguntado: no Brasil o nono dígito entra e sai, e é a forma devolvida que vale para os envios seguintes.
Número com formato inválido volta com exists: false e um errorCode próprio, sem interromper a consulta dos outros.
Esta checagem já acontece sozinha em todo envio para número, então a rota não é obrigatória: ela serve para descobrir antes, e não durante o disparo. Consultar listas grandes de números desconhecidos é um dos comportamentos que o WhatsApp associa a spam e pode custar o bloqueio do seu número, por isso o limite de 50 por consulta.
Lista as conversas em memória do WhatsApp conectado.
Inclui os grupos de que o número participa. O id termina em @g.us quando é grupo e em @s.whatsapp.net quando é conversa individual.
Retorna detalhes de uma conversa com as últimas mensagens.
Aceita tanto o chatId de uma conversa individual quanto o de um grupo (...@g.us).
| Param | Tipo | Padrão | Descrição |
|---|---|---|---|
| limit | integer | 10 | Quantidade de mensagens |
| mediaBase64 | boolean | false | Incluir mídia como base64 |
Com mediaBase64=true, cada mensagem que possui mídia inclui o campo mediaBase64 com o conteúdo do arquivo.
Lista os grupos de que o número participa, com nome, quantidade de participantes e as permissões que importam antes de publicar.
| Param | Tipo | Padrão | Descrição |
|---|---|---|---|
| refresh | boolean | false | Ignora o cache de 60s e consulta o WhatsApp de novo |
O id serve direto como to de um envio ou chatId de uma consulta. O groupId é o mesmo valor sem sufixo, que é como o grupo chega no from do webhook.
Antes de publicar num grupo, olhe o isAnnouncementOnly, que indica grupo só de admins, junto com o isAdmin, que diz se o seu número é admin ali. Com os dois, você sabe de antemão se a mensagem será aceita.
Os mesmos campos da listagem, mais os participantes. O groupId aceita com ou sem o sufixo @g.us.
O phone vem null quando o WhatsApp identifica o participante apenas por um id interno e não informa o número. Grupo inexistente, ou do qual o seu número não participa, responde 404 com errorCode GROUP_NOT_FOUND.
Histórico de mensagens gravado pelo servidor, com filtro por conversa e por período. Diferente de /chats/{chatId}, que lê a memória da sessão e se perde quando a conexão cai, este histórico sobrevive a quedas e reinícios.
A retenção é de 7 dias. O valor vem em retentionDays na resposta, e o que passa da janela é apagado automaticamente. Não há histórico anterior à data em que o recurso entrou no ar.
| Param | Tipo | Padrão | Descrição |
|---|---|---|---|
| chatId | string | - | Conversa a consultar. Sem ele, traz todas as conversas do número |
| isGroup | boolean | false | Marca que o chatId é o id de um grupo, quando vier sem o sufixo @g.us |
| startDate | string | - | Início do período em ISO 8601 (ex: 2026-08-29T00:00:00-03:00) |
| endDate | string | - | Fim do período em ISO 8601 |
| limit | integer | 50 | Máximo de 200 por página |
| offset | integer | 0 | Deslocamento para paginação |
As mensagens vêm da mais recente para a mais antiga, e o total serve para montar a paginação. O período filtra pelo horário da mensagem no WhatsApp, e o fuso enviado é respeitado.
Para um grupo, use o chatId com @g.us ou o id puro com isGroup=true, que é o mesmo valor que chega no from do webhook.
Conversas que tiveram mensagem no período, com a contagem e a data da última. Serve para descobrir o que consultar sem precisar saber os ids de antemão. Aceita startDate e endDate.
Faz download da mídia de uma mensagem específica. Funciona para mensagens recebidas dentro da janela de retenção de 7 dias, mesmo que a conexão tenha caído e voltado no meio do caminho.
Só mensagens com anexo têm o que baixar. O webhook message_received e a rota /messages trazem o campo hasMedia, que evita a chamada quando não há anexo. Reações, mensagens de protocolo e enquetes, por exemplo, nunca têm.
O messageId é o id da mensagem no WhatsApp, o mesmo que chega no webhook ou volta no envio. Não é o id do agendamento: o agendamento guarda o messageId da mensagem que ele gerou, e é esse valor que serve aqui.
| HTTP | errorCode | Quando ocorre |
|---|---|---|
| 400 | MESSAGE_HAS_NO_MEDIA | A mensagem existe, mas não tem anexo |
| 404 | MESSAGE_NOT_FOUND | Mensagem não encontrada nesse número, ou já fora da janela de retenção |
| 500 | DOWNLOAD_MEDIA_FAILED | A mensagem tem anexo, mas o WhatsApp não entregou o arquivo |
Desconecta e remove o número da sua conta. Faz logout do WhatsApp.
Agende disparos para um horário futuro. No horário, a mensagem é enviada automaticamente, gerando o mesmo registro de status (messages/{messageId}/status) e os mesmos webhooks de entrega/leitura de um envio imediato.
Agenda uma mensagem de texto para envio futuro.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| to | string | Sim | Número destino (ex: 5511999998888) |
| isGroup | boolean | Não | Marca que o to é o id de um grupo. Dispensável se o to já vier com @g.us |
| message | string | Sim | Texto da mensagem |
| scheduledAt | string | Sim | Data/hora futura em ISO 8601. O fuso segue o valor enviado: Z significa UTC; para horário de Brasília use o offset -03:00 (ex: 2026-06-26T14:08:00-03:00) |
| humanMode | boolean | Não | Simula comportamento humano antes do envio |
| retryIfOffline | boolean | Não | Se o número estiver offline no horário, mantém tentando dentro da janela de retentativa |
| retryWindowMinutes | integer | Não | Janela de retentativa em minutos após o horário (padrão 30). Depois disso, marca como falho |
Agenda o envio de uma mídia. Aceita upload (multipart/form-data) ou base64 (application/json). Tamanho máximo: 16MB.
send-media)| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| to | string | Sim | Número destino |
| isGroup | boolean | Não | Marca que o to é o id de um grupo. Dispensável se o to já vier com @g.us |
| file | file | Sim* | Arquivo (multipart) — ou use base64/filename/mimetype |
| base64 / filename / mimetype | string | Sim* | Mídia em base64 (alternativa ao upload) |
| scheduledAt | string | Sim | Data/hora futura em ISO 8601. O fuso segue o valor enviado: Z = UTC; para Brasília use o offset -03:00 |
| caption | string | Não | Legenda |
| sendAudioAsVoice | boolean | Não | Enviar áudio como mensagem de voz |
| humanMode / retryIfOffline / retryWindowMinutes | - | Não | Mesmas opções de schedule-message |
Lista os agendamentos da sua conta (paginado).
| Param | Tipo | Descrição |
|---|---|---|
| status | string | Filtra por pending, processing, sent, failed ou cancelled |
| number_id | integer | Filtra por número de origem |
| limit / offset | integer | Paginação (padrão 50 / 0) |
Retorna um agendamento específico.
| Campo | Descrição |
|---|---|
| id | Identificador do agendamento |
| type | text ou media |
| to_number | Número destino |
| message | Texto (ou legenda, no caso de mídia) |
| scheduled_at | Data/hora programada do disparo |
| status | Estado atual (ver abaixo) |
| retry_if_offline / retry_until | Configuração e prazo da retentativa |
| attempts | Quantas vezes o envio foi tentado |
| message_id | ID da mensagem gerada (preenchido após o envio) |
| error_message | Motivo da falha, quando status = failed |
| sent_at | Quando foi efetivamente enviado |
| Status | Significado |
|---|---|
| pending | Aguardando o horário do disparo |
| processing | Em processamento pelo worker |
| sent | Enviado com sucesso (use message_id para acompanhar a entrega) |
| failed | Falhou definitivamente (ver error_message) |
| cancelled | Cancelado antes do disparo |
Retorna o histórico de status do agendamento, em ordem cronológica. Cada transição registra o motivo, ajudando a entender por que um disparo falhou ou foi reagendado.
logs| Campo | Descrição |
|---|---|
| status | Evento da transição (ver abaixo) |
| message | Detalhe ou motivo do evento (ex.: mensagem de erro) |
| attempt | Número da tentativa de envio no momento do evento |
| created_at | Quando o evento ocorreu |
| Evento | Significado |
|---|---|
| created | Agendamento criado |
| processing | Reservado pelo worker para envio |
| sent | Enviado com sucesso |
| requeued | Voltou para a fila (número offline com retentativa ativa, ou reinício do worker) |
| failed | Falhou (ver message com o motivo) |
| cancelled | Cancelado antes do disparo |
Cancela um agendamento. Apenas agendamentos com status pending podem ser cancelados.
Histórico paginado das chamadas feitas à API pela sua conta.
| Param | Tipo | Padrão | Descrição |
|---|---|---|---|
| limit | integer | 50 | Quantidade de registros |
| offset | integer | 0 | Deslocamento para paginação |
| startDate | string | - | Data inicial (ISO 8601) |
| endDate | string | - | Data final (ISO 8601) |
Resumo de uso no período: total de chamadas, endpoints mais usados e contagem de mensagens por status.
| Param | Tipo | Descrição |
|---|---|---|
| startDate | string | Data inicial (ISO 8601) |
| endDate | string | Data final (ISO 8601) |
Histórico das tentativas de entrega de webhook de um número, com payload, status HTTP, tentativa e erro.
| Param | Tipo | Padrão | Descrição |
|---|---|---|---|
| limit | integer | 50 | Quantidade de registros |
| offset | integer | 0 | Deslocamento para paginação |
Quando configurado, o sistema envia eventos para a URL de webhook via POST.
Toda requisição de webhook inclui o header X-Webhook-Signature com uma assinatura HMAC-SHA256. Use o webhook_secret disponível na página API Keys para validar a autenticidade.
Se a entrega falhar, o sistema faz até 3 tentativas: imediata, depois 30s e 2min. Todas as tentativas são registradas e visíveis em GET /session/{number}/webhook-logs.
O WhatsApp está migrando as conversas individuais para um identificador interno (LID). Quando isso acontece, o from traz esse identificador, que não é telefone, e o número real vem em fromPhone. Para cadastrar o contato ou responder, use sempre o fromPhone. Ele vem null quando o WhatsApp ainda não informou o número correspondente.
Mensagens de grupo também chegam por aqui, e nelas o isGroup vem true. Nesse caso o from traz o identificador do grupo (por exemplo 120363023480137063) em vez do número de quem escreveu, o participant traz o número de quem enviou e o pushName, o nome dessa pessoa. Para responder no próprio grupo, devolva o from como to junto de isGroup: true; para falar no privado com quem escreveu, use o participant.
O participant pode vir null quando o WhatsApp identifica a pessoa apenas por um id interno e não informa o telefone. Nesse caso o pushName continua sendo a pista de quem escreveu, então trate o campo como opcional.
Enviado a cada confirmação de entrega de uma mensagem que você enviou. O campo status pode ter os seguintes valores:
| status | Significado |
|---|---|
| server | Recebida pelo servidor do WhatsApp |
| delivered | Entregue no aparelho do destinatário |
| read | Lida pelo destinatário |
O estado inicial sent é registrado no momento do envio e não gera webhook. Para consultar o status atual de uma mensagem a qualquer momento, use GET /session/{number}/messages/{messageId}/status.
Enviado ao clicar em "Testar Webhook" no painel. Use para validar que a URL está acessível e a assinatura HMAC está correta.
Enviado sempre que o número entra em operação. É o par do session_disconnected: use os dois para saber se pode enviar mensagens naquele momento. O campo reason diferencia os casos:
| reason | Descrição |
|---|---|
| paired | Primeiro vínculo do número, logo após a leitura do QR Code ou do código de pareamento. É neste evento que você descobre qual telefone foi vinculado |
| reconnected | O número voltou depois de uma queda que foi avisada. Oscilações curtas, que se resolvem em segundos, não geram este evento nem o session_disconnected |
Enviado quando o número sai do ar de verdade. O campo reason diferencia os casos:
| reason | Descrição |
|---|---|
| logged_out | A sessão foi desvinculada no celular. É permanente: o número precisa ser vinculado de novo |
| disconnected | Queda que persistiu. O sistema continua tentando reconectar |
| not_authorized | O número não passou na validação do Ella Smart: cadastro não encontrado, ou acesso não está ativo. O campo detail traz NOT_FOUND ou NO_ACTIVE_ACCESS. Não é queda de conexão, e reconectar não resolve: o acesso precisa voltar no Ella Smart |
A conexão com o WhatsApp Web não é estável por natureza: o servidor fecha e reabre o canal várias vezes por dia por conta própria, e a retomada costuma levar poucos segundos, sem perda de mensagem. Este evento não é enviado a cada uma dessas oscilações, justamente para o seu usuário final não ver o número piscando sem motivo.
Ele é enviado quando:
reason vem logged_out.Desconexão pedida por você, pelo painel ou pela API, não gera este evento. O campo code traz o código técnico do encerramento, útil para separar instabilidade de rede de recusa do servidor.
Enviado quando um disparo agendado é entregue com sucesso. O messageId permite acompanhar o status (entregue/lido) pelos eventos message_status_updated.
Enviado quando um disparo agendado falha definitivamente (número não existe no WhatsApp, ou offline após esgotar a janela de retentativa).
Trate a falha sempre pelo errorCode, que é estável e nunca muda de valor. O campo error é só para exibir, e o texto acompanha o idioma escolhido para o número:
| errorCode | Quando ocorre | error (en) | error (pt-BR) |
|---|---|---|---|
| SESSION_NOT_READY | O número estava desconectado no horário do disparo e a janela de retentativa acabou | Session not ready | O número não está conectado ao WhatsApp |
| NOT_ON_WHATSAPP | O destinatário não tem WhatsApp | The number 5521988887777 is not registered on WhatsApp | O número 5521988887777 não tem WhatsApp |
| MISSING_MEDIA | A mídia do agendamento não foi encontrada na hora do envio | Scheduled media is missing | A mídia do agendamento não foi encontrada |
| UNSUPPORTED_AUDIO_FORMAT | O áudio está num formato que o WhatsApp não entrega | WhatsApp does not deliver WebM audio. Convert the file to one of: OGG/Opus, MP3, MP4/AAC, AMR | O WhatsApp não entrega áudio em WebM. Converta o arquivo para um destes: OGG/Opus, MP3, MP4/AAC, AMR |
| SEND_ERROR | Qualquer outra falha devolvida pelo WhatsApp | Texto original do erro, sem tradução | |
O idioma é definido por número, no momento do pareamento, pelo campo language (en ou pt-BR). O padrão é en, então integrações existentes continuam recebendo exatamente o mesmo texto de antes.
| Código | Descrição |
|---|---|
400 | Requisição inválida (parâmetros faltando ou sessão não pronta) |
403 | API Key inválida ou conta inativa |
404 | Número não encontrado ou sessão pendente expirada |
429 | Rate limit excedido — muitas requisições. Verifique os headers X-RateLimit-* |
500 | Erro interno do servidor |
Além do status HTTP, toda resposta de erro traz um errorCode estável, que nunca muda de valor. Decida pelo código e use o message apenas para exibir ao usuário, já que o texto acompanha o idioma do número.
| errorCode | HTTP | Quando ocorre |
|---|---|---|
| MISSING_TO | 400 | Parâmetro to não informado |
| INVALID_TO_DIGITS | 400 | O to tem caracteres que não são dígitos |
| INVALID_TO_LENGTH | 400 | O to não tem entre 7 e 15 dígitos |
| MISSING_MESSAGE | 400 | Parâmetro message ausente ou vazio |
| SESSION_NOT_READY | 400 | O número não está conectado ao WhatsApp |
| NOT_ON_WHATSAPP | 404 | O destinatário não tem WhatsApp |
| NO_FILE | 400 | Envio de mídia sem arquivo e sem base64 |
| MEDIA_TOO_LARGE | 400 | Mídia acima do limite de 16MB |
| UNSUPPORTED_AUDIO_FORMAT | 400 | Áudio num formato que o WhatsApp não entrega, como WebM ou WAV |
| MESSAGE_NOT_FOUND | 404 | Mensagem não encontrada nesse número, ou fora da janela de retenção |
| MESSAGE_HAS_NO_MEDIA | 400 | Pedido de anexo numa mensagem que não tem anexo |
| MISSING_NUMBERS | 400 | Consulta de números sem o parâmetro numbers |
| TOO_MANY_NUMBERS | 400 | Mais de 50 números numa consulta só |
| SCHEDULED_AT_IN_PAST | 400 | O scheduledAt não é uma data futura |
| SCHEDULED_NOT_FOUND | 404 | Agendamento inexistente ou de outra conta |
| CANNOT_CANCEL | 400 | Só agendamentos pendentes podem ser cancelados |
| NUMBER_NOT_FOUND | 404 | Número não encontrado ou de outra conta |
| MISSING_API_KEY | 403 | Header x-api-key ausente |
| INVALID_API_KEY | 403 | API Key inválida ou desativada |
| RATE_LIMIT_EXCEEDED | 429 | Limite de requisições por minuto estourado |
| FEATURE_NOT_ENABLED | 403 | Funcionalidade não liberada para a conta |
| GROUP_NOT_FOUND | 404 | Grupo inexistente ou do qual o seu número não participa |
| INVALID_GROUP_ID | 400 | O to foi marcado como grupo mas não tem formato de id de grupo |
| NUMBER_NOT_AUTHORIZED | 403 | O número não está liberado no Ella Smart. O reason diz se é NOT_FOUND ou NO_ACTIVE_ACCESS |
| VALIDATION_UNAVAILABLE | 503 | Não foi possível consultar o Ella Smart agora. Tente de novo em alguns instantes |
| PHONE_MISMATCH | 400 | O telefone do pareamento é diferente do que foi autorizado no cadastro da conexão |
| INTERNAL_ERROR | 500 | Erro interno |
Os mesmos códigos aparecem no webhook scheduled_message_failed: uma falha de envio devolve NOT_ON_WHATSAPP tanto na resposta HTTP quanto no evento. Veja Webhooks.
O texto do message sai no idioma escolhido para o número no pareamento (campo language: en ou pt-BR). Para rotas que não têm número no path, como POST /session/connect, vale o header Accept-Language; sem ele, o padrão é en.