# Pré-autorizando uma Confirmação
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/confirmations/issue-confirmation
POST /confirmations
Emite antecipadamente o token de confirmação que uma ação destrutiva registrada exigiria no header X-Confirmation-Token.
Algumas operações da API são disruptivas o suficiente para exigir uma confirmação explícita: elas trocam algo que já está em uso e, se disparadas sem querer, causam uma interrupção. Essas operações exigem o header `X-Confirmation-Token` e, sem ele, respondem `409` (`confirmation_required`) trazendo, no próprio corpo do erro, um token pronto para repetir a chamada.
Este endpoint existe para quem prefere não depender desse `409`: você pede o token antecipadamente, já sabendo qual operação vai confirmar, e envia a chamada original já com o header preenchido. As duas formas produzem exatamente o mesmo tipo de token e são totalmente intercambiáveis.
### O token
O `confirmation_token` retornado é assinado pela própria API. Ele é vinculado ao usuário autenticado, à ação (`action`), ao recurso (`resource`) e aos campos enviados em `params` que definem a mudança: um token emitido para um conjunto de parâmetros não confirma uma chamada com parâmetros diferentes. Ele expira em `expires_at`, cerca de 5 minutos após a emissão.
### Ações registradas
O campo `action` só aceita ações que a API reconhece como confirmáveis. Cada uma exige um campo diferente em `params`, que é exatamente o que o token passa a confirmar:
| `action` | `params` obrigatório |
| ----------------------------- | ----------------------------------------------------------- |
| `instance.migrate_connection` | `to`: o tipo de conexão de destino (`unofficial` ou `waba`) |
| `instance.reconnect` | `phone_number_id`: o ID do número de telefone de destino |
Omitir o campo obrigatório de `params` é um erro de validação `400`, de propósito: um token emitido sem ele confirmaria uma mudança vazia e falharia depois, na operação real, com um erro de incompatibilidade difícil de entender.
Este endpoint não verifica se o `resource` existe nem se pertence a você, de propósito. O token só passa a valer alguma coisa quando a operação que ele confirma é chamada de verdade, e essa operação sempre confere a posse do recurso por conta própria antes de agir. Um token emitido para um recurso de outra conta simplesmente não confirma nada quando usado.
### O que isso não é
Essa confirmação não é uma camada de segurança nem um passo de autorização. Quem já tem o token de acesso da sua conta sempre consegue emitir uma confirmação, para qualquer ação registrada. Ela existe para tornar deliberada uma mudança disruptiva que, de outra forma, poderia acontecer por engano, e não para impedir chamadas mal-intencionadas.
### Exemplo
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/confirmations \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action": "instance.reconnect",
"resource": "ozj35qv418rpmlrb",
"params": {
"phone_number_id": "1016102021584086"
}
}'
```
```javascript Node.js (fetch) theme={null}
const response = await fetch('https://api.zapsterapi.com/v1/confirmations', {
method: 'POST',
headers: {
Authorization: 'Bearer SEU_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'instance.reconnect',
resource: 'ozj35qv418rpmlrb',
params: { phone_number_id: '1016102021584086' },
}),
})
const confirmation = await response.json()
console.log(confirmation.confirmation_token)
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.zapsterapi.com/v1/confirmations",
headers={"Authorization": "Bearer SEU_TOKEN"},
json={
"action": "instance.reconnect",
"resource": "ozj35qv418rpmlrb",
"params": {"phone_number_id": "1016102021584086"},
},
timeout=30,
)
confirmation = response.json()
print(confirmation["confirmation_token"])
```
Use o `confirmation_token` retornado no header `X-Confirmation-Token` da chamada original, dentro dos `expires_at` retornados junto.
# Adicionar Participantes
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/add-participants
POST /wa/instances/{instance_id}/groups/{group_id}/participants
Adicionar novo participante em um grupo.
# Criar um Grupo
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/create
POST /wa/instances/{instance_id}/groups
Este endpoint permite a criação de grupos no WhatsApp. Para criar um grupo, apenas o campo `name` é obrigatório. Os demais campos como foto de perfil, descrição e participantes são opcionais. Após a criação, você pode modificar qualquer um destes campos utilizando o endpoint de [Atualizar um Grupo](/pt-BR/v1/api-reference/groups/update-data).
## Foto de Perfil
Para definir uma foto de perfil durante a criação do grupo, utilize o campo `profile_picture`. Este campo aceita tanto uma URL quanto uma string em formato base64 contendo a imagem.
Recomendamos fortemente o uso de URLs ao invés de base64, pois é uma prática mais eficiente e adequada, especialmente para arquivos de maior tamanho. Embora o formato base64 seja suportado, seu uso pode impactar negativamente a performance da requisição.
## Participantes
Para adicionar participantes durante a criação do grupo, utilize o campo `participants`. Os números informados neste campo serão automaticamente adicionados como membros após a criação do grupo ser concluída.
**Importante:** Para adicionar participantes ao grupo, é necessário que:
1. O usuário tenha configurado a opção "Who can add me to groups" como "Everyone" nas configurações de privacidade do WhatsApp, ou
2. O usuário tenha a instância salva como contato
Caso contrário, o usuário só poderá entrar no grupo através de um link de convite.
# Remover Participantes
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/delete-participants
DELETE /wa/instances/{instance_id}/groups/{group_id}/participants
Remover participante(s) de um grupo.
# Rebaixar Participantes
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/demote-participants
DELETE /wa/instances/{instance_id}/groups/{group_id}/demote-participants
Rebaixar participantes para membros comum de um grupo.
# Listar Grupos
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/fetch-all
GET /wa/instances/{instance_id}/groups
Listar todos os grupos em que a instância participa
# Listar Participantes
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/fetch-participants
GET /wa/instances/{instance_id}/groups/{group_id}/participants
Listar todos os participantes de um grupo
# Entrar em Grupos
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/join-group
POST /wa/instances/{instance_id}/groups/join
Entre em grupos usando um código de convite
# Promover Participantes
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/promote-participants
POST /wa/instances/{instance_id}/groups/{group_id}/promote-participants
Promover participantes para administrador de um grupo.
# Atualizar um Grupo
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/groups/update-data
PATCH /wa/instances/{instance_id}/groups/{group_id}
Utilize este endpoint para atualizar os campos `name` (Nome), `profile_picture` (Foto de perfil) e/ou `description` (Descrição do perfil) de um determinado. Todas as atualizações são opcionais, ou seja, apenas as informações presentes no corpo da requisição serão alteradas.
# Criando Instância
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/create-instance
POST /wa/instances
Ao criar uma instância, você escolhe o tipo de conexão:
* **Não oficial** (`connection_type: "unofficial"`): o padrão. Depois de criar, você conecta via QR code ou código de pareamento.
* **Oficial WABA** (`connection_type: "waba"`): usa a API oficial da Meta. Você precisa fornecer as credenciais no objeto `waba`.
Para instâncias WABA, existem duas formas de obter as credenciais:
1. **Embedded Signup** (recomendado): fluxo OAuth pelo dashboard, sem precisar mexer no Meta Business Manager. Veja o [guia passo a passo](/pt-BR/v1/guides/connect-waba-instance).
2. **Token manual**: você gera um System User Token no Meta Business Manager e passa direto na API. Veja o [método avançado](/pt-BR/v1/guides/connect-waba-instance#método-2-token-manual-avançado).
Quando `connection_type` é `waba`, o objeto `waba` com `access_token`, `phone_number_id` e `waba_id` é obrigatório. Para instâncias não oficiais, esse campo é ignorado.
Para entender as diferenças entre os dois tipos, veja o [comparativo WABA vs não oficial](/pt-BR/v1/guides/waba-vs-unofficial).
# Criando Webhooks
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/create-webhook
POST /wa/instances/{instance_id}/webhooks
Este endpoint permite registrar um novo **webhook** para uma instância específica. Os webhooks são usados para receber notificações em tempo real sobre eventos importantes na instância, como mensagens recebidas ou mudanças de status.
**⚠️ Importante:** É obrigatório fornecer **ou** uma `url` **ou** um `webhook_id`. Se nenhum dos dois for informado, a requisição falhará.
### 🔍 Considerações
* Pelo menos um evento deve ser especificado na criação do webhook.
* Se uma `url` e um `webhook_id` forem fornecidos ao mesmo tempo, o `webhook_id` será priorizado.
* O webhook pode ser desativado posteriormente usando a propriedade `enabled`.
# Excluindo Instância
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/delete-instance
DELETE /wa/instances/{instance_id}
Utilize este endpoint quando você precisar excluir definitivamente uma instância.
**Atenção**: Esta é uma ação irreversível, sua instância será desconectada (caso esteja) e não poderá mais ser usada para para recebimento ou envio de mensagens.
# Excluindo Webhooks
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/delete-webhook
DELETE /wa/instances/{instance_id}/webhooks/{webhook_id}
Este endpoint permite **desvincular um webhook de uma instância**, removendo sua associação com a instância específica. **O webhook não será excluído**, apenas **desassociado** da instância, permanecendo ativo em outras instâncias e na conta do usuário caso ainda esteja vinculado a outras instâncias.
# Dados da Instância
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/instance-details
GET /wa/instances/{instance_id}
# Obtendo QR Code
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/instance-qrcode
GET /wa/instances/{instance_id}/qrcode
Este endpoint permite capturar o QR Code de uma instância para autenticação no WhatsApp. Ele retorna a imagem no formato `image/png`, permitindo exibi-la diretamente em uma tag `
` no HTML, se necessário. Para acessar este recurso, é obrigatório fornecer um **token de acesso**, que pode ser passado no cabeçalho da requisição ou na **query string**.
Para utilizar este endpoint, é necessário fornecer um **token de acesso** válido. A forma recomendada é enviá-lo no **cabeçalho da requisição**. Opcionalmente, ele pode ser passado na URL como **query string**, mas isso expõe o token e não é recomendado.
### Usando o Token na Query String ⚠️ (Caso de Uso Específico)
```html theme={null}
```
**⚠️ Importante:** O uso do token na URL pode expô-lo em logs de servidores e históricos de navegadores, o que representa um risco de segurança. Sempre prefira a autenticação via cabeçalho HTTP.
🚀 **Por que essa opção está disponível?**
A renderização do QR Code via **query string** foi criada para permitir que o cliente compartilhe o link diretamente com seu usuário final, usando um **token temporário**. Dessa forma, o usuário pode simplesmente abrir o link no navegador, visualizar o QR Code e conectar a instância. Essa funcionalidade pode ser útil em cenários onde o cliente final não tem acesso ao painel da API, mas precisa conectar a conta do WhatsApp rapidamente.
### ❌ QR Code Indisponível
Se a instância já estiver conectada ou o QR Code não estiver disponível, a API retornará um erro:
```json theme={null}
{
"errors": [
{
"code": "qrcode_unavailable",
"message": "The instance's QR code is not available. This might be because your instance is already connected."
}
]
}
```
### 📡 QR Code em Tempo Real
Se deseja atualizar o QR Code em tempo real sem que seu usuário precise sair da sua plataforma, recomendamos utilizar os eventos da instância para acompanhar as atualizações.
Para isso, você pode configurar um webhook para escutar o evento `instance.qrcode`. Sempre que o QR Code da sua instância for atualizado, seu sistema receberá uma notificação automática, permitindo que você atualize a exibição do QR Code em tempo real e garanta uma experiência fluida para o usuário.
### 📌 Considerações Finais
* O QR Code muda constantemente, então é necessário **atualizar periodicamente** até a conexão ser estabelecida.
* Instâncias conectadas **não possuem QR Code disponível**.
* Para segurança, evite expor tokens na URL; prefira enviá-los via cabeçalho HTTP.
* Se for utilizar a query string, certifique-se de que o **token seja temporário** para evitar riscos de exposição.
# Listando Instâncias
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/list-instances
GET /wa/instances
# Migrando o Tipo de Conexão
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/migrate-instance
POST /wa/instances/{instance_id}/migrate
Migra a instância entre a conexão não oficial (QR Code) e a API oficial (WABA), preservando o ID, os webhooks e as configurações.
Use este endpoint para trocar o tipo de conexão de uma instância existente sem perder nada da sua integração: o ID da instância, os webhooks cadastrados e as configurações permanecem exatamente como estavam. A migração funciona nos dois sentidos.
### Não oficial para API oficial (WABA)
Envie `connection_type: "waba"` junto com o objeto `waba`, contendo `access_token`, `phone_number_id` e `waba_id`.
O Embedded Signup (login com o Facebook) só está disponível pelo painel da Zapster: ele depende de uma página hospedada por nós e não pode ser reproduzido por chamada de API. Para migrar por aqui, gere um System User Token no Meta Business Manager e informe-o no objeto `waba`.
O ambiente de execução da conexão não oficial é desativado e o número passa a operar pela Cloud API da Meta. Ao final, a instância fica `connected`.
### API oficial (WABA) para não oficial
Envie `connection_type: "unofficial"`, sem credenciais. A configuração WABA é removida com segurança na Meta e um novo ambiente de conexão é preparado. A instância fica `disconnected`, aguardando a leitura do QR Code (ou código de pareamento) para conectar o número.
### Webhooks são revalidados
Os tipos de conexão suportam conjuntos diferentes de eventos de webhook, e a API oficial suporta um conjunto menor. Antes de migrar, os webhooks já cadastrados na instância são validados contra o tipo de destino: se algum estiver inscrito em um evento que o destino não emite, a migração é rejeitada com `400` (`unsupported_webhook_event`), listando todos os eventos incompatíveis e os eventos válidos. Ajuste as inscrições e repita a chamada.
### Confirmação para instâncias em uso
Migrar uma instância que não está `disconnected` interrompe o serviço dela durante a troca, mesmo quando ela está apenas `offline`: só a instância já `disconnected` dispensa a confirmação. Nesse caso, a chamada exige o header `X-Confirmation-Token`.
Esse token não é um valor arbitrário: é assinado pela própria API e vinculado ao usuário autenticado, à ação (`instance.migrate_connection`), à instância e ao tipo de conexão de destino. Um token obtido para migrar para `waba` não confirma uma migração para `unofficial`, e vice-versa. Ele expira em cerca de 5 minutos.
Existem duas formas de obter o token, e ambas produzem o mesmo resultado:
1. **Chame o endpoint sem o header.** A resposta é `409` (`confirmation_required`), e o corpo traz em `details.confirmation_token` um token já pronto para a chamada que você acabou de tentar, junto com `expires_at`, `from`, `to`, `status` e `resource`. Basta repetir a chamada idêntica com esse valor no header.
2. **Peça o token antes de tentar migrar**, em [`POST /confirmations`](/pt-BR/v1/api-reference/confirmations/issue-confirmation), informando `action: "instance.migrate_connection"`, o `resource` (ID da instância) e `params.to` com o tipo de conexão de destino.
Se o token estiver ausente, malformado, expirado ou não corresponder exatamente à chamada (outro tipo de destino, por exemplo), a API responde com o mesmo `409` e um token novo pronto para uso. O campo `details.reason` existe só para depuração: o fluxo do cliente é sempre "recebi 409, pego o token, tento de novo", nunca uma decisão baseada no motivo.
Essa confirmação não é uma camada de segurança. Quem tem o token de acesso da conta sempre consegue emitir uma confirmação; ela existe para tornar deliberada uma migração disruptiva que aconteceria por engano, não para impedir chamadas mal-intencionadas.
# Obtendo Cód. Pareamento
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/pairing-code
POST /wa/instances/{instance_id}/pairing-code
O **código de pareamento** é uma alternativa ao QR Code para conectar uma instância do WhatsApp a um dispositivo. Ele permite autenticar e vincular a conta sem a necessidade de escanear um QR Code, tornando o processo mais prático em algumas situações.
### 🛠️ Quando Usar o Código de Pareamento?
* Caso esteja conectando um dispositivo sem acesso a uma câmera para escanear o QR Code.
* Se o processo de conexão precisar ser automatizado em um fluxo onde a leitura de QR Code não é viável.
* Para oferecer uma opção alternativa ao QR Code, facilitando a conexão.
### 📌 Como Funciona?
* O WhatsApp gera um código temporário para vinculação.
* Esse código deve ser inserido no aplicativo WhatsApp no dispositivo que deseja conectar.
* Após a confirmação, a instância será pareada e estará pronta para uso.
# Desligando Instância
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/power-instance-off
POST /wa/instances/{instance_id}/power-off
Este endpoint permite desligar uma instância que está conectada ou desconectada.
Ao ser ligada novamente, a instância pode retornar já conectada, mantendo a sessão anterior. Em alguns casos, se a instância ficar desligada por muito tempo ou se o WhatsApp desconectar dispositivos inativos, ela poderá retornar desconectada ao ser ligada.
Disponível apenas para instâncias não oficiais. Instâncias oficiais (WhatsApp Cloud API) rodam na infraestrutura da Meta, estão sempre disponíveis e não podem ser ligadas, desligadas ou reiniciadas. A requisição retorna `400` com o código `waba_feature_not_supported`.
# Ligando Instância
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/power-instance-on
POST /wa/instances/{instance_id}/power-on
Este endpoint permite ligar uma instância que está atualmente offline. Se a instância já estiver conectada, esta ação não terá efeito.
Disponível apenas para instâncias não oficiais. Instâncias oficiais (WhatsApp Cloud API) rodam na infraestrutura da Meta, estão sempre disponíveis e não podem ser ligadas, desligadas ou reiniciadas. A requisição retorna `400` com o código `waba_feature_not_supported`.
# Reconectando uma Instância WABA
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/reconnect-instance
POST /wa/instances/{instance_id}/reconnect
Reconecta uma instância WABA, rotacionando as credenciais ou apontando o mesmo ID para outro número, preservando os webhooks e as configurações.
Use este endpoint para reconectar uma instância da API oficial (WABA) sem precisar excluí-la e criar outra. O ID da instância, os webhooks cadastrados e as configurações permanecem exatamente como estavam: você só fornece novamente as credenciais do número.
Diferente do que valia antes, a instância não precisa estar `disconnected` para chamar este endpoint. O comportamento muda conforme a situação:
| Situação | O que acontece |
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| Instância `disconnected` | Reconecta normalmente, sem exigir confirmação |
| Instância em uso, **mesmo** `phone_number_id` | Rotaciona as credenciais (ex.: token revogado no Meta Business Manager), sem exigir confirmação |
| Instância em uso, `phone_number_id` **diferente** | Aponta a instância para outro número, exige o header `X-Confirmation-Token` |
Rotacionar as credenciais do mesmo número é uma operação segura e idempotente, e é o caso mais comum: um token revogado no Meta Business Manager, por exemplo. Já apontar a instância para outro número é o único caso realmente arriscado, pois o ID, os webhooks e as configurações continuam os mesmos, mas a instância passa a atender por um número diferente. Por isso só esse caso pede confirmação: uma confirmação que aparecesse em toda chamada viraria um clique automático e deixaria de proteger qualquer coisa.
### Credenciais
Envie o objeto `waba` com `access_token`, `phone_number_id` e `waba_id` — os mesmos campos aceitos na criação de instância. Campos opcionais como `app_id`, `app_secret`, `webhook_verify_token` e `auth_method` também são aceitos.
Se o número foi conectado pelo login com o Facebook, em vez de um token gerado no Meta Business Manager, faça a reconexão pelo painel da Zapster. Esse login precisa acontecer em uma página hospedada por nós e não pode ser reproduzido por chamada de API.
### O que acontece na reconexão
Você não precisa refazer nada do que já estava configurado. Ao receber as credenciais, a Zapster:
1. **Confere o token com a Meta**, para garantir que ele é válido e tem acesso ao número informado.
2. **Guarda as credenciais com segurança**, criptografadas.
3. **Aponta as mensagens do número de volta para a sua instância**, para que os webhooks voltem a chegar no endereço que você já tinha cadastrado.
4. **Conclui o registro do número na Meta**, quando ainda for necessário.
Terminado isso, a instância volta ao status `connected` e volta a enviar e receber normalmente. Como o ID não muda, **nada precisa ser alterado no seu código**.
Se alguma etapa falhar (token inválido, por exemplo), a instância permanece no estado anterior e a resposta traz o motivo. Basta corrigir e chamar de novo.
### Confirmação para trocar o número da instância
Apontar uma instância em uso para um `phone_number_id` diferente do atual exige o header `X-Confirmation-Token`.
Esse token não é um valor arbitrário: é assinado pela própria API e vinculado ao usuário autenticado, à ação (`instance.reconnect`), à instância e ao `phone_number_id` de destino. Um token obtido para um número não confirma a troca para outro. Ele expira em cerca de 5 minutos.
Existem duas formas de obter o token, e ambas produzem o mesmo resultado:
1. **Chame o endpoint sem o header.** Se as credenciais enviadas apontam para um número diferente do atual, a resposta é `409` (`confirmation_required`), e o corpo traz em `details.confirmation_token` um token já pronto para a chamada que você acabou de tentar, junto com `expires_at`, `from`, `to`, `status` e `resource`. Basta repetir a chamada idêntica com esse valor no header.
2. **Peça o token antes de tentar reconectar**, em [`POST /confirmations`](/pt-BR/v1/api-reference/confirmations/issue-confirmation), informando `action: "instance.reconnect"`, o `resource` (ID da instância) e `params.phone_number_id` com o número de destino.
Se o token estiver ausente, malformado, expirado ou não corresponder exatamente à chamada (outro `phone_number_id`, por exemplo), a API responde com o mesmo `409` e um token novo pronto para uso. O campo `details.reason` existe só para depuração: o fluxo do cliente é sempre "recebi 409, pego o token, tento de novo", nunca uma decisão baseada no motivo.
Essa confirmação não é uma camada de segurança. Quem tem o token de acesso da conta sempre consegue emitir uma confirmação; ela existe para tornar deliberada uma troca de número que aconteceria por engano, não para impedir chamadas mal-intencionadas.
### Exemplos
Os exemplos abaixo cobrem o caso mais comum: rotacionar as credenciais do mesmo número, que não exige o header `X-Confirmation-Token`. Para apontar a instância a outro número, adicione o header com o token obtido conforme a seção anterior.
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/instances/ozj35qv418rpmlrb/reconnect \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255"
}
}'
# Trocando o número da instância, com o token de confirmação:
curl -X POST https://api.zapsterapi.com/v1/wa/instances/ozj35qv418rpmlrb/reconnect \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Confirmation-Token: eyJ2IjoxLCJhY3QiOiJpbnN0YW5jZS5yZWNvbm5lY3QifQ.q1w2e3r4t5y6" \
-d '{
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102099998765",
"waba_id": "419378847918255"
}
}'
```
```javascript Node.js (fetch) theme={null}
const instanceId = 'ozj35qv418rpmlrb'
const response = await fetch(
`https://api.zapsterapi.com/v1/wa/instances/${instanceId}/reconnect`,
{
method: 'POST',
headers: {
Authorization: 'Bearer SEU_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
waba: {
access_token: 'EAAxxxxxxx...',
phone_number_id: '1016102021584086',
waba_id: '419378847918255',
},
}),
},
)
const instance = await response.json()
console.log(instance.status) // connected
```
```javascript Node.js (axios) theme={null}
import axios from 'axios'
const instanceId = 'ozj35qv418rpmlrb'
const { data: instance } = await axios.post(
`https://api.zapsterapi.com/v1/wa/instances/${instanceId}/reconnect`,
{
waba: {
access_token: 'EAAxxxxxxx...',
phone_number_id: '1016102021584086',
waba_id: '419378847918255',
},
},
{ headers: { Authorization: 'Bearer SEU_TOKEN' } },
)
console.log(instance.status) // connected
```
```javascript JavaScript (navegador) theme={null}
// Nunca chame a Zapster direto do navegador: o seu token daria acesso total
// à conta a quem abrisse o DevTools. Chame o seu próprio backend, e é ele
// quem fala com a Zapster usando o token guardado no servidor.
const response = await fetch('/api/instancias/ozj35qv418rpmlrb/reconectar', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
access_token: 'EAAxxxxxxx...',
phone_number_id: '1016102021584086',
waba_id: '419378847918255',
}),
})
const instance = await response.json()
console.log(instance.status) // connected
```
```python Python theme={null}
import requests
instance_id = "ozj35qv418rpmlrb"
response = requests.post(
f"https://api.zapsterapi.com/v1/wa/instances/{instance_id}/reconnect",
headers={"Authorization": "Bearer SEU_TOKEN"},
json={
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255",
}
},
timeout=30,
)
instance = response.json()
print(instance["status"]) # connected
```
```go Go theme={null}
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
instanceID := "ozj35qv418rpmlrb"
body, _ := json.Marshal(map[string]any{
"waba": map[string]string{
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255",
},
})
url := fmt.Sprintf(
"https://api.zapsterapi.com/v1/wa/instances/%s/reconnect",
instanceID,
)
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer SEU_TOKEN")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var instance map[string]any
json.NewDecoder(res.Body).Decode(&instance)
fmt.Println(instance["status"]) // connected
}
```
```php PHP theme={null}
[
'access_token' => 'EAAxxxxxxx...',
'phone_number_id' => '1016102021584086',
'waba_id' => '419378847918255',
],
]);
$ch = curl_init("https://api.zapsterapi.com/v1/wa/instances/{$instanceId}/reconnect");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer SEU_TOKEN',
'Content-Type: application/json',
],
]);
$instance = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $instance['status']; // connected
```
```java Java theme={null}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ReconnectInstance {
public static void main(String[] args) throws Exception {
String instanceId = "ozj35qv418rpmlrb";
String payload = """
{
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255"
}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(
"https://api.zapsterapi.com/v1/wa/instances/"
+ instanceId + "/reconnect"))
.header("Authorization", "Bearer SEU_TOKEN")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
```
# Reiniciando Instância
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/restart-instance
POST /wa/instances/{instance_id}/restart
Este endpoint reinicia uma instância, colocando-a offline temporariamente por um curto período. A instância poderá ficar offline por até 1 minuto durante o processo de reinicialização.
Em alguns casos, dependendo da estabilidade da sessão, pode ser necessário um novo login no WhatsApp.
Disponível apenas para instâncias não oficiais. Instâncias oficiais (WhatsApp Cloud API) rodam na infraestrutura da Meta, estão sempre disponíveis e não podem ser ligadas, desligadas ou reiniciadas. A requisição retorna `400` com o código `waba_feature_not_supported`.
# Atualizando a Instância
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/update-instance
PATCH /wa/instances/{instance_id}
Atualiza os dados da instância na plataforma, como o nome e os metadados.
Use este endpoint para atualizar os dados da própria instância na plataforma: o nome (`name`), os metadados (`metadata`) e o identificador de pesquisa (`lookup_key`).
Ele não altera o perfil do WhatsApp (nome de exibição, foto, descrição). Para isso, use o endpoint de [atualização de perfil](/pt-BR/v1/api-reference/instance/update-profile). As configurações de comportamento têm o seu próprio endpoint de [atualização de configurações](/pt-BR/v1/api-reference/instance/update-settings).
### Atualize só o que precisar
Você não precisa enviar todos os campos a cada chamada. Envie apenas o que quer mudar e tudo o que ficar de fora continua exatamente como está.
Nenhum campo aceita `null`: `name` é sempre um texto, e os valores de `metadata` são sempre um texto ou um número. Para "limpar" um valor, veja a regra da string vazia logo abaixo.
### Como o `metadata` é atualizado
O `metadata` também é atualizado de forma parcial: as chaves enviadas são alteradas e todas as outras permanecem intactas. Não é necessário (nem recomendado) reenviar o objeto inteiro.
* Para **alterar ou criar** uma chave, envie a chave com o novo valor.
* Para **manter** uma chave como está, simplesmente não a envie.
* Para **limpar** o valor de uma chave, envie uma string vazia `""`.
Por exemplo, se a instância tem os metadados `customer_id`, `customer_name` e `campaign`, a requisição abaixo altera `customer_id`, limpa `campaign` e mantém `customer_name` intacto:
```json theme={null}
{
"metadata": {
"customer_id": "789012",
"campaign": ""
}
}
```
### Chaves reservadas `wa_`
Chaves de metadata iniciadas com `wa_` são gerenciadas automaticamente pela plataforma e funcionam como somente leitura: se você enviá-las na requisição, elas são ignoradas e os valores originais são preservados. Use outros nomes para as suas próprias chaves.
# Atualizando Perfil
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/update-profile
PATCH /wa/instances/{instance_id}/profile
Utilize este endpoint para atualizar os campos `name` (Nome), `profile_picture` (Foto de perfil) e/ou `about` (Descrição do perfil) no perfil do usuário. Todas as atualizações são opcionais, ou seja, apenas as informações presentes no corpo da requisição serão alteradas.
### Comportamento
Se você enviar apenas uma ou duas informações, apenas esses campos serão atualizados. Campos não incluídos na requisição permanecerão inalterados.
**Nota**: Em alguns casos, a atualização do nome do perfil pode falhar. Estamos continuamente trabalhando para melhorar este comportamento, porém, há dependências externas que podem afetar o sucesso da operação.
# Atualizando Configurações
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/update-settings
PATCH /wa/instances/{instance_id}/settings
Atualiza as configurações de comportamento da instância. Envie apenas o que quer mudar: tudo o que ficar de fora continua exatamente como está.
Use este endpoint para atualizar as configurações de comportamento da sua instância: rejeição de ligações, delay antes do envio de mensagens, presença (online/digitando), limpeza de conversa e confirmação de leitura automática.
### Atualize só o que precisar
Você não precisa enviar todas as configurações a cada chamada. Envie apenas o que quer mudar e tudo o que ficar de fora continua exatamente como está.
Isso vale até para configurações com subcampos, como `message_delay` e o formato segmentado de `read_confirmation`: cada subcampo que você não enviar também fica como estava. Por exemplo, enviando apenas:
```json theme={null}
{
"settings": {
"read_confirmation": {
"chats": true
}
}
}
```
Você liga a confirmação de leitura automática só para conversas individuais, e `groups` e `status` seguem do jeito que estavam.
### Configurações disponíveis
* **`call_rejection`**: define se ligações recebidas devem ser rejeitadas automaticamente. Aceita `all` (rejeita todas), `none` (não rejeita nenhuma), `video_only` (rejeita apenas chamadas de vídeo) ou `audio_only` (rejeita apenas chamadas de áudio).
* **`message_delay`**: adiciona um atraso proposital antes do envio de cada mensagem, útil para simular um comportamento mais humano. É um objeto com `enabled` (liga/desliga o delay), `min` e `max` (limites em segundos, o tempo real é sorteado dentro desse intervalo).
* **`delay_per_word`**: quando ligado, o delay antes do envio passa a ser calculado com base na quantidade de palavras da mensagem, até um teto de 10 segundos. Quando `message_delay` está configurado, ele tem prioridade e `delay_per_word` é ignorado.
* **`presence_behavior`**: controla quando a instância aparece como "online" para os contatos. `only_composing` mostra "online" apenas durante o envio da mensagem (recomendado), `always_online` mantém a instância sempre online e `always_offline` evita aparecer online exceto quando necessário para o envio.
* **`delete_chat_after_sent`**: quando ligado, limpa a conversa no aparelho logo depois do envio da mensagem, para evitar acúmulo de histórico no dispositivo conectado.
* **`read_confirmation`**: controla a confirmação de leitura automática das mensagens recebidas. Aceita os valores `never` (nunca confirma) ou `always` (sempre confirma), ou um objeto segmentado por tipo de conversa com os campos `chats`, `groups` e `status`, cada um booleano e independente. Quando o segmento `status` está ligado, os status publicados pelos seus contatos são marcados como vistos assim que recebidos. Mensagens enviadas pela própria instância, listas de transmissão e publicações de canais nunca recebem confirmação automática, independentemente dessa configuração.
Se você precisa de controle fino sobre o momento exato da confirmação de leitura, por exemplo, marcar como lida só depois que um atendente responder, desligue a confirmação automática do segmento desejado e use o endpoint de [leitura sob demanda](/pt-BR/v1/api-reference/messages/read-message) para confirmar mensagem por mensagem.
A atualização é aplicada à instância em tempo real, sem necessidade de reiniciá-la.
# Atualizando Webhooks
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/instance/update-webhook
PATCH /wa/instances/{instance_id}/webhooks/{webhook_id}
Este endpoint permite **atualizar um webhook existente** para uma instância específica.
### ⚠️ Importante: Alteração de Nome ou URL
Modificar o **nome** ou a **URL** de um webhook existente impactará **todas as instâncias** que utilizam esse webhook. Isso significa que qualquer instância vinculada será automaticamente atualizada para refletir as mudanças.
Se precisar utilizar um **novo nome** ou uma **URL diferente** sem afetar instâncias existentes, recomendamos criar um **novo webhook** em vez de modificar um já em uso.
Dessa forma, o novo webhook será vinculado **apenas aos recursos desejados**, evitando impactos inesperados em outras configurações.
### 🔍 Considerações
* Todos os parâmetros são opcionais, sendo possível atualizar apenas os campos desejados.
* Se a URL do webhook for alterada, a API pode exigir uma nova validação.
* O webhook pode ser desativado definindo `enabled` como `false`.
# Cancelar Mensagem Agendada
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/messages/cancel-message
DELETE /wa/messages/{id}
Cancela uma mensagem que ainda não foi enviada.
Só funciona para mensagens com status `scheduled` ou `pending`.
Mensagens já enviadas, falhadas ou canceladas retornam erro 422.
Use este endpoint para cancelar uma mensagem que ainda não foi enviada.
Só é possível cancelar mensagens com status `scheduled` ou `pending`. Se a mensagem já foi enviada, falhou ou já está cancelada, a API retorna erro 422.
Ao cancelar, o status da mensagem muda para `canceled` e o campo `canceled_at` é preenchido com a data e hora do cancelamento.
O cancelamento é definitivo. Não é possível "descancelar" uma mensagem. Se precisar reenviá-la, crie uma nova.
# Listar Mensagens
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/messages/list-messages
GET /wa/messages
Lista todas as mensagens (imediatas e agendadas) dentro de um período.
Retorna informações de status, entrega e leitura de cada mensagem.
Usa paginação cursor-based para navegar entre páginas de resultados.
O período máximo por consulta é de 90 dias. O quão longe no passado
você pode consultar depende do seu plano (retenção do histórico).
Lista todas as mensagens enviadas e agendadas dentro de um período. Retorna informações de status, entrega e leitura de cada mensagem.
## Parâmetros obrigatórios
Os campos `from` e `to` definem o período da consulta. O período máximo é de 90 dias por requisição.
O quão longe no passado você pode consultar depende do seu plano:
| Plano | Retenção do histórico |
| ---------- | --------------------- |
| Essential | 24 horas |
| Pro | 30 dias |
| Enterprise | 180 dias |
## Filtros disponíveis
Você pode combinar qualquer filtro na mesma requisição:
| Filtro | Descrição | Exemplo |
| ----------------- | ------------------------------ | -------------------------- |
| `status` | Filtrar por status da mensagem | `status=scheduled` |
| `instance_id` | Filtrar por instância | `instance_id=inst_xyz` |
| `recipient` | Filtrar por destinatário | `recipient=5511999999999` |
| `message_id` | Buscar pelo ID do WhatsApp | `message_id=wamid.HBgM...` |
| `connection_type` | Filtrar por tipo de conexão | `connection_type=waba` |
## Paginação
A listagem usa paginação cursor-based. Cada resposta inclui um objeto `meta` com:
* `has_more`: indica se existem mais resultados
* `next_cursor`: valor para passar no parâmetro `after` da próxima requisição
* `limit`: quantidade de itens por página
Para navegar entre páginas:
1. Faça a primeira requisição sem o parâmetro `after`
2. Se `has_more` for `true`, pegue o valor de `next_cursor`
3. Faça a próxima requisição com `after=`
4. Repita até `has_more` ser `false`
O padrão é 20 itens por página. Você pode ajustar com o parâmetro `limit` (mínimo 1, máximo 100).
## Sobre o campo errors
Quando uma mensagem falha (`status=failed`), o campo `errors` contém os detalhes do problema. Para instâncias WABA, inclui o código de erro da Meta e um link para a documentação.
Erros comuns:
| Código | Descrição |
| ------ | ------------------------------------------------- |
| 131047 | Janela de 24 horas expirada (precisa de template) |
| 132000 | Template não encontrado ou parâmetros incorretos |
| 132001 | Template não existe na tradução informada |
# Marcar Mensagem como Lida
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/messages/read-message
POST /wa/messages/{id}/read
Marca uma mensagem recebida como lida sob demanda. Útil quando a leitura automática está desligada e o seu fluxo decide o momento certo de confirmar a leitura (por exemplo, depois que um atendente responde).
A instância pode ser informada pelo campo `instance_id` no corpo da requisição ou pelo cabeçalho `X-Instance-Id`.
Use este endpoint para marcar uma mensagem recebida como lida sob demanda. Ele é o complemento ideal da leitura automática desligada: seu sistema decide o momento certo de confirmar a leitura, por exemplo depois que um atendente responde ao cliente.
O `id` da mensagem é o mesmo recebido nos webhooks de mensagem, como o campo `data.id` do evento `message.received`. A instância pode ser informada pelo campo `instance_id` no corpo ou pelo cabeçalho `X-Instance-Id`.
A resposta traz o resultado da operação no campo `status`:
* `read`: a mensagem foi marcada como lida.
* `ignored`: a mensagem foi enviada pela própria instância, então não há leitura a confirmar.
* `not_found`: a mensagem está fora do prazo de leitura (veja abaixo) ou nunca foi processada pela instância.
## Prazo para marcar como lida
Cada mensagem fica disponível para leitura por um período limitado depois que chega na instância:
* Conversas individuais e grupos: até 3 dias após o recebimento da mensagem.
* Status: até 24 horas após a publicação, o mesmo período em que o status fica visível no WhatsApp.
Depois desse prazo o retorno para aquele ID é `not_found`. Isso não indica uma falha na instância: a janela de leitura expirou e a confirmação não pode mais ser enviada.
Para marcar várias mensagens de uma vez, use o endpoint de [leitura em lote](/pt-BR/v1/api-reference/messages/read-messages-batch).
Se a conta do WhatsApp conectada estiver com a confirmação de leitura desativada nas configurações de privacidade, a mensagem é marcada como lida apenas localmente e o remetente não vê o tique azul.
Este endpoint está disponível apenas para instâncias não oficiais. Instâncias com API oficial (WABA) retornam erro por enquanto.
# Marcar Mensagens como Lidas (Lote)
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/messages/read-messages-batch
POST /wa/messages/read
Marca até 100 mensagens recebidas como lidas em uma única requisição. As mensagens podem pertencer a conversas diferentes.
O resultado é discriminado por mensagem: `read` (lida), `ignored` (mensagem enviada pela própria instância, sem leitura a confirmar) ou `not_found` (mensagem fora do prazo de leitura ou nunca processada pela instância).
Use este endpoint para marcar até 100 mensagens recebidas como lidas em uma única requisição. As mensagens podem pertencer a conversas diferentes, incluindo grupos, sem custo adicional.
Os `ids` são os mesmos recebidos nos webhooks de mensagem, como o campo `data.id` do evento `message.received`. Requisições com mais de 100 IDs retornam erro de validação.
A resposta discrimina o resultado por mensagem no campo `results`, nunca um sucesso genérico:
* `read`: a mensagem foi marcada como lida.
* `ignored`: a mensagem foi enviada pela própria instância, então não há leitura a confirmar.
* `not_found`: a mensagem está fora do prazo de leitura (veja abaixo) ou nunca foi processada pela instância.
## Prazo para marcar como lida
Cada mensagem fica disponível para leitura por um período limitado depois que chega na instância:
* Conversas individuais e grupos: até 3 dias após o recebimento da mensagem.
* Status: até 24 horas após a publicação, o mesmo período em que o status fica visível no WhatsApp.
Depois desse prazo o retorno para aquele ID é `not_found`. Isso não indica uma falha na instância: a janela de leitura expirou e a confirmação não pode mais ser enviada.
Para marcar uma única mensagem, use o endpoint de [leitura unitária](/pt-BR/v1/api-reference/messages/read-message).
Se a conta do WhatsApp conectada estiver com a confirmação de leitura desativada nas configurações de privacidade, as mensagens são marcadas como lidas apenas localmente e o remetente não vê o tique azul.
Este endpoint está disponível apenas para instâncias não oficiais. Instâncias com API oficial (WABA) retornam erro por enquanto.
# Enviando Mensagens
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/messages/sending
POST /wa/messages
## Respondendo Mensagens
Para responder a mensagens já enviadas ou recebidas, utilize a propriedade `reply_to`. Isso permite que sua resposta seja vinculada diretamente à mensagem original, proporcionando um contexto claro na conversa (como mostrado na imagem abaixo).
**Limitação:** Atualmente, só é possível responder a mensagens que foram enviadas/recebidas nos últimos 7 dias.
## Agendando mensagens
Para agendar uma mensagem para envio futuro, adicione o campo `send_at` ao body da requisição com a data e hora no formato ISO 8601.
Quando `send_at` está presente, a resposta muda:
* Status HTTP **201** (em vez de 200)
* Corpo com `message_id`, `status: "scheduled"` e `send_at` em UTC
O campo `send_at` é opcional. Quando não informado, a mensagem é enviada imediatamente como sempre.
O `send_at` deve ser no mínimo 1 minuto no futuro. O limite máximo depende do seu plano.
Veja os [limites por plano](/pt-BR/v1/concepts/scheduled-messages#limites-por-plano).
Para cancelar uma mensagem agendada, veja [Cancelar mensagem](/pt-BR/v1/api-reference/messages/cancel-message).
Para listar e rastrear todas as mensagens, veja [Listar mensagens](/pt-BR/v1/api-reference/messages/list-messages).
# Verificação de Número
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/utils/fetch-recipient
GET /wa/instances/{instance_id}/recipients/{recipient}
## Introdução
Este endpoint permite verificar a existência de um destinatário em uma determinada instância do WhatsApp. A API retorna informações básicas sobre o destinatário, como o ID, se é uma conta comercial, o nome e a URL da foto de perfil. Esse endpoint é útil para garantir que o número fornecido está registrado e ativo na plataforma, antes de enviar mensagens ou realizar outras operações.
## Casos de Uso
* **Validação antes de envio de mensagens**: Antes de enviar uma mensagem a um destinatário, verifique se o número existe e está registrado no WhatsApp para evitar erros e falhas no envio.
* **Validação em formulários**: Utilize este endpoint para validar números de telefone inseridos por usuários em formulários. Antes de permitir que o usuário prossiga, a aplicação pode verificar se o número inserido está registrado no WhatsApp, garantindo que os dados fornecidos são válidos e que o destinatário é alcançável via WhatsApp.
## Pontos de Atenção
O campo `name` nem sempre estará presente na resposta da API. Isso ocorre devido a uma limitação técnica onde a Zapster só consegue armazenar em cache o nome do contato se ele tiver conversado pelo menos uma vez com a instância. Se o contato nunca conversou, este campo estará ausente.
O campo `profile_picture` retornará `null` em dois casos: se o contato tiver configurado a foto de perfil como privada ou se não houver nenhuma foto de perfil atribuída.
# Verificação de Números em Lote
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/utils/fetch-recipient-batch
POST /wa/instances/{instance_id}/recipients/batch
## Introdução
Este endpoint é similar ao [Verificação de Número](/pt-BR/v1/api-reference/utils/fetch-recipient), mas permite a verificação de **até 100 números** em uma única requisição, o que é ideal para quando você precisa verificar a existência de múltiplos números de WhatsApp de forma eficiente.
Para garantir o melhor uso dessa rota, por favor, consulte os [Pontos de Atenção](/pt-BR/v1/api-reference/utils/fetch-recipient#pontos-de-atencao), onde explicamos algumas nuances importantes sobre o `name` e `profile_picture`.
## Como funciona?
A resposta desse endpoint será sempre uma **lista de objetos**, onde cada objeto representará o status de um número enviado na requisição.
Cada número consultado será avaliado quanto à sua **existência no WhatsApp** e se o número corresponde a uma conta de **WhatsApp Business**. Além disso, caso o número seja inválido ou não encontrado, a resposta fornecerá detalhes sobre o erro.
Vamos supor que você informe dois números para a consulta. Se um dos números existir e o outro não, a resposta será algo parecido com o seguinte exemplo:
```json Exemplo de Resposta theme={null}
[
{
"exists": true,
"id": "551112341234",
"is_business": false,
"original": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
{
"error": {
"code": "recipient_not_found",
"message": "The specified recipient could not be found."
},
"exists": false,
"original": "5511998765432"
}
]
```
## Diferença entre `original` e `id`
Em alguns casos, o número informado na lista de consulta pode ser ajustado pelo WhatsApp. Isso geralmente acontece devido a variações regionais, como a inclusão ou exclusão do nono dígito para números de celular no Brasil. O campo `original` serve para garantir que você veja exatamente o número que foi enviado na sua requisição, enquanto o campo `id` mostra o número que o WhatsApp conseguiu encontrar após eventuais ajustes.
### Como Funciona?
* **`original`**: É o número exatamente como você o enviou na requisição, sem nenhuma alteração.
* **`id`**: É o número ajustado ou resolvido pelo WhatsApp, que pode ser diferente do original caso o WhatsApp tenha encontrado uma versão corrigida.
A seguir, mostramos três exemplos que ilustram diferentes cenários de consulta de números, usando os campos `original` e `id`.
```json Nono Dígito Adicionado theme={null}
{
"exists": true
"id": "5511998765432",
"original": "5511998765432",
}
```
```json Nono Dígito Removido theme={null}
{
"exists": true
"id": "5511998765432",
"original": "551198765432",
}
```
```json Número Não Encontrado theme={null}
{
"original": "551123456789",
"exists": false,
"error": {
"message": "The specified recipient could not be found.",
"code": "recipient_not_found"
}
}
```
# Atualização de Presença
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/utils/presence-update
PATCH /wa/instances/{instance_id}/presence
## Introdução
Este endpoint permite que você atualize o status de presença de um destinatário em uma instância específica do WhatsApp. Você pode definir se o destinatário verá uma indicação de que você está "digitando..." ou "gravando...".
Esta funcionalidade é útil para melhorar a experiência do usuário durante interações em tempo real, especialmente em aplicações que dependem de feedback instantâneo, como chats ao vivo ou integrações com IA.
## Casos de Uso
* **Integração com OpenAI**: Enquanto a IA está gerando uma resposta, você pode definir a presença como "digitando..." ou "gravando..." para simular a experiência de uma interação humana e manter o usuário informado sobre o processamento em andamento.
## Estratégias de Uso
* **Definindo a Presença de Curta Duração**: Utilize a estratégia `maximum_duration` para garantir que o status de "digitando..." ou "gravando..." seja exibido por um período específico de tempo. Esta estratégia é ideal para interações em que o tempo de resposta é previsível.
* **Até a Próxima Mensagem**: Use a estratégia `until_next_message` para manter o status ativo até que a próxima mensagem seja enviada, proporcionando uma transição suave entre o momento em que o usuário percebe a presença e a entrega da mensagem final. Isso é útil em cenários onde o tempo de processamento pode variar, como durante a geração de respostas por IA.
# Excluir Webhook
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/webhooks/delete-webhook
DELETE /webhooks/{webhook_id}
# Listar Webhooks
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/webhooks/list-webhooks
GET /webhooks
Este endpoint permite listar todos os **webhooks** cadastrados na conta do usuário. O retorno inclui informações detalhadas sobre cada webhook registrado, como **status**, **nome**, **URL de produção** e **data de criação**.
# Atualizar Webhook
Source: https://developer.zapsterapi.com/pt-BR/v1/api-reference/webhooks/update-webhook
PATCH /webhooks/{webhook_id}
Utilize este endpoint quando precisar atualizar dados do webhook.
**Atenção**: Toda e qualquer modificação utilizando este endpoint afetará todas as instâncias conectadas a este webhook.
# Quickstart para Agentes
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/agent-quickstart
Cole este prompt no seu agente (Claude Code, Codex, OpenClaw) e ele instala, configura e valida a CLI da Zapster automaticamente.
A CLI foi desenhada para ser configurada por agentes. Cole o bloco abaixo no Claude Code, Codex, OpenClaw ou qualquer agente que execute comandos shell, e ele cuida do resto:
````markdown theme={null}
Você vai configurar a CLI da Zapster (`@zapsterapi/cli`). Siga rigorosamente, e pare imediatamente se qualquer passo falhar.
1. Verifique se o Node.js 22+ está instalado: `node --version`. Se < 22, peça ao usuário para atualizar e pare.
2. Instale a CLI globalmente: `npm i -g @zapsterapi/cli`. Se falhar com EACCES, sugira `sudo npm i -g @zapsterapi/cli` ou um Node gerenciado pelo nvm.
3. Confirme com `zapsterapi --version`.
4. Pergunte ao usuário pelo token da Zapster API (ele pode gerar em https://app.zapsterapi.com/tokens). NÃO assuma nenhum valor.
5. Autentique: `zapsterapi auth login --token `.
6. Valide com `zapsterapi auth whoami`. Se falhar, peça um token novo e repita.
7. Liste as instâncias: `zapsterapi instance list --json`. Se a lista vier vazia, oriente o usuário a criar uma instância no dashboard antes de continuar.
8. Confirme: "CLI configurada. Pronto para enviar mensagens."
Após configurada, use a CLI assim:
```bash
zapsterapi message send --recipient 5511999999999 --text "olá"
zapsterapi recipient fetch --recipient 5511999999999 --json
zapsterapi instance list --json
```
Se o usuário tiver múltiplas contas, use `--profile ` em todos os comandos.
````
## Por que isso funciona bem com agentes
* **Saída JSON em todos os comandos** (`--json`). Agentes preferem JSON estruturado a parse de texto.
* **Códigos de erro estáveis** no envelope JSON (`error.code`). Permite o agente tomar decisões sem heurística textual.
* **Multi-profile via `~/.zapsterapi/credentials`**. O agente não precisa carregar tokens em variáveis ou flags.
* **Telemetria privacy-safe** que ajuda a melhorar a CLI sem expor dados do usuário.
## Atalhos copy-paste para agentes
* **`llms.txt`** ([download](/llms.txt)): índice de toda a documentação no formato [llmstxt.org](https://llmstxt.org/), pronto pra colar como contexto inicial num agente.
* **`SKILL.md`** ([copy-paste na doc](/pt-BR/v1/cli/skill)): skill no formato Claude Code que você cola em `~/.claude/skills/zapsterapi-cli/SKILL.md` pra que o agente saiba usar a CLI sem prompts adicionais.
## Próximos passos
* [Referência de comandos](/pt-BR/v1/cli/reference/auth)
* [Saída JSON em detalhe](/pt-BR/v1/cli/json-output)
* [Múltiplos perfis](/pt-BR/v1/cli/profiles)
# Exemplos
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/examples
Receitas práticas para usar a CLI da Zapster em scripts e automações.
## Disparar uma mensagem em CI
```bash theme={null}
#!/usr/bin/env bash
set -euo pipefail
zapsterapi auth login --token "$ZAPSTERAPI_TOKEN" >/dev/null
zapsterapi message send \
--recipient "$RECIPIENT" \
--text "Build $GITHUB_RUN_ID concluído com sucesso." \
--json
```
## Verificar disponibilidade antes de enviar
```bash theme={null}
exists=$(zapsterapi recipient fetch --recipient "$NUMERO" --json | jq '.data.exists')
if [ "$exists" = "true" ]; then
zapsterapi message send --recipient "$NUMERO" --text "Olá!"
else
echo "Número não está no WhatsApp"
fi
```
## Listar instâncias e iterar
```bash theme={null}
zapsterapi instance list --json | jq -r '.data.rows[] | select(.status=="connected") | .id' | while read -r id; do
echo "Instância conectada: $id"
done
```
## Alternar entre contas (cliente → time interno)
```bash theme={null}
zapsterapi auth login --token "$TOKEN_CLIENTE"
zapsterapi auth login --token "$TOKEN_INTERNO" --profile interno
zapsterapi message send --recipient 5511 --text "Para o cliente"
zapsterapi --profile interno message send --recipient 5511 --text "Para o time"
```
## Pedir pra um agente fazer
Veja o [Quickstart para Agentes](/pt-BR/v1/cli/agent-quickstart) — copie o prompt, cole no Claude Code, e o agente faz tudo.
# Instalação
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/installation
Como instalar e atualizar a CLI da Zapster.
## Pré-requisitos
* **Node.js 22 LTS+** (Node 18 e 20 já passaram do EOL ou estão prestes).
* **npm 10+** (vem com Node 22).
## Instalação global
```bash theme={null}
npm i -g @zapsterapi/cli
```
Confirme:
```bash theme={null}
zapsterapi --version
```
## Atualização
```bash theme={null}
npm update -g @zapsterapi/cli
```
## Desinstalação
```bash theme={null}
npm uninstall -g @zapsterapi/cli
rm -rf ~/.zapsterapi
```
## Outras formas de instalação
Em v1, apenas o npm registry é suportado. **Homebrew, binário standalone e Docker** estão no roadmap pós-v1.
## Solução de problemas
### `EACCES: permission denied`
Seu npm global está em diretório que precisa de root. Use [nvm](https://github.com/nvm-sh/nvm) para gerenciar Node sem sudo, ou:
```bash theme={null}
sudo npm i -g @zapsterapi/cli
```
### `command not found: zapsterapi`
O diretório do npm global não está no `$PATH`. Verifique com:
```bash theme={null}
npm config get prefix
```
Adicione `/bin` ao seu `$PATH`.
# CLI Zapster
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/introduction
Envie mensagens, gerencie instâncias e automatize fluxos da Zapster direto do shell.
A CLI Zapster (`zapsterapi`) é um wrapper fino sobre nossa REST API. Ela existe para dois cenários onde a UI do dashboard atrapalha:
* **Agentes de IA** que executam comandos shell (Claude Code, Codex, OpenClaw): copia o prompt, o agente instala e configura, e você manda mensagem em segundos.
* **Pipelines de CI** que precisam disparar mensagens, listar instâncias ou validar tokens sem abrir um browser.
A CLI **não substitui** a API nem o MCP server — ela é um atalho otimizado para shell e agentes.
Cole um prompt no Claude Code / Codex e o agente instala e configura tudo.
`npm i -g @zapsterapi/cli`. Requer Node.js 22+.
Estilo aws-cli — `--profile` e `ZAPSTERAPI_PROFILE` para alternar contas.
Toda saída em JSON estruturado com `--json`. Pronto para `jq` e agentes.
## Atalhos para agentes de IA
Índice da documentação no formato [llmstxt.org](https://llmstxt.org/). Cole como contexto inicial num agente — ele já fica orientado sobre toda a CLI sem precisar navegar página por página.
Skill no formato Claude Code, com botão de copy-paste pronto. Cole em `~/.claude/skills/zapsterapi-cli/SKILL.md` e o agente passa a usar a CLI sem prompts adicionais.
## O que está em v1
| Comando | O que faz |
| ---------------------------- | -------------------------------------------------- |
| `zapsterapi auth login` | Salva um token em `~/.zapsterapi/credentials`. |
| `zapsterapi auth logout` | Remove credenciais do perfil. |
| `zapsterapi auth whoami` | Verifica o token e mostra o perfil ativo. |
| `zapsterapi instance list` | Lista as instâncias da conta. |
| `zapsterapi message send` | Envia uma mensagem de texto. |
| `zapsterapi recipient fetch` | Verifica se um número está disponível no WhatsApp. |
Ficou de fora propositalmente: webhook tunneling estilo Stripe `listen`, mock server local, device-flow auth e plugins. Esses estão no roadmap pós-v1.
## Privacidade e telemetria
A CLI envia eventos privacy-safe ao PostHog (nome do comando, sucesso/falha, código de erro, versão do Node, OS). **Nenhum token, número ou conteúdo de mensagem é coletado**. Para opt-out:
```bash theme={null}
export ZAPSTERAPI_DISABLE_TELEMETRY=1
```
# Saída JSON
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/json-output
Como ler a saída estruturada da CLI da Zapster a partir de scripts e agentes.
Toda invocação da CLI aceita a flag global `--json`. Com ela, a saída é um único objeto JSON por linha, no envelope:
```json theme={null}
{ "ok": true, "data": }
```
ou, em erro:
```json theme={null}
{
"ok": false,
"error": {
"code": "invalid_token",
"message": "Token is invalid",
"hint": "Run `zapsterapi auth login --token ` first.",
"details": { "status": 401 }
}
}
```
A saída de sucesso vai para `stdout`. A saída de erro vai para `stderr` e o exit code é `1` (ou `2` para erros de uso, como flag desconhecida).
## Exemplos
### Listar instâncias e pegar o primeiro ID
```bash theme={null}
zapsterapi instance list --json | jq -r '.data.rows[0].id'
```
### Validar token em script
```bash theme={null}
if zapsterapi auth whoami --json > /dev/null 2>&1; then
echo "ok"
else
echo "token inválido"
fi
```
### Reagir ao código de erro
```bash theme={null}
output=$(zapsterapi message send --recipient 5511999999999 --text "oi" --json 2>&1)
code=$(echo "$output" | jq -r '.error.code // empty')
case "$code" in
invalid_token) echo "renove o token";;
invalid_recipient) echo "número errado";;
"") echo "enviado";;
*) echo "erro: $code";;
esac
```
## Garantias de estabilidade
* O envelope (`ok`, `data`, `error`) é estável dentro da major version `0.x` da CLI.
* Os campos dentro de `data` espelham a resposta da REST API correspondente — se a API adicionar um campo, ele aparece no JSON da CLI também.
* Os `error.code` são estáveis. Mensagens podem mudar entre versões.
# Múltiplos perfis
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/profiles
Gerencie várias contas Zapster com perfis no estilo aws-cli.
A CLI suporta múltiplos perfis para alternar entre contas Zapster (cliente, work, staging) sem reautenticar a cada comando.
## Como funciona
As credenciais ficam em `~/.zapsterapi/credentials` (formato INI), uma seção por perfil:
```ini theme={null}
[default]
token=tok_principal
[work]
token=tok_da_empresa
base_url=https://api.zapsterapi.com
```
## Criando perfis
```bash theme={null}
# Perfil padrão (default)
zapsterapi auth login --token tok_principal
# Um segundo perfil
zapsterapi auth login --token tok_da_empresa --profile work
```
## Usando um perfil
A CLI resolve o perfil ativo nesta ordem:
1. Flag `--profile ` na invocação.
2. Variável de ambiente `ZAPSTERAPI_PROFILE`.
3. Perfil `default`.
```bash theme={null}
# Forma 1: flag por comando
zapsterapi --profile work instance list
# Forma 2: ambiente para a sessão
export ZAPSTERAPI_PROFILE=work
zapsterapi instance list
```
## Removendo um perfil
```bash theme={null}
zapsterapi auth logout --profile work
```
Se for o único perfil, o arquivo `~/.zapsterapi/credentials` é removido.
## Permissões do arquivo
A CLI cria `~/.zapsterapi/` com `0700` e o arquivo de credenciais com `0600` (somente leitura/escrita para o seu usuário). Em Windows essa proteção depende da ACL do filesystem.
# auth
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/reference/auth
Autenticação e gerenciamento de credenciais.
## `zapsterapi auth login`
Salva um token Zapster em `~/.zapsterapi/credentials` para o perfil ativo.
```bash theme={null}
zapsterapi auth login --token [--profile ] [--base-url ]
```
| Flag | Obrigatório | Descrição |
| ------------------ | ----------- | ---------------------------------------------------------------------------------------------- |
| `--token ` | Sim | Token de API gerado em [https://app.zapsterapi.com/tokens](https://app.zapsterapi.com/tokens). |
| `--profile ` | Não | Nome do perfil. Default: `default`. |
| `--base-url ` | Não | API base URL alternativa (raramente necessária). |
**Validação**: a CLI faz `GET /v1/wa/instances?per_page=1` antes de gravar o token. Se a API responder 401, o token não é persistido.
**Exemplo**:
```bash theme={null}
zapsterapi auth login --token zap_live_xxxxx --profile work
```
## `zapsterapi auth logout`
Remove credenciais do perfil ativo.
```bash theme={null}
zapsterapi auth logout [--profile ]
```
Se for o único perfil no arquivo, o arquivo é apagado.
## `zapsterapi auth whoami`
Verifica o token do perfil ativo e mostra resumo.
```bash theme={null}
zapsterapi auth whoami [--profile ] [--json]
```
Saída JSON:
```json theme={null}
{
"ok": true,
"data": {
"profile": "default",
"base_url": "https://api.zapsterapi.com",
"token_suffix": "abcd",
"valid": true
}
}
```
# instance
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/reference/instance
Listagem e inspeção de instâncias WhatsApp.
## `zapsterapi instance list`
Lista as instâncias WhatsApp disponíveis para o perfil ativo.
```bash theme={null}
zapsterapi instance list \
[--status ] \
[--lookup-key ] \
[--page ] \
[--per-page ] \
[-q, --query ] \
[--profile ] \
[--json]
```
| Flag | Obrigatório | Descrição |
| ---------------------- | ----------- | ---------------------------------------------------------------------- |
| `--status ` | Não | Filtra por status: `connected`, `offline` ou `disconnected`. |
| `--lookup-key ` | Não | Filtra por `lookup_key` (chave externa que você associou à instância). |
| `--page ` | Não | Página (default: 1). |
| `--per-page ` | Não | Itens por página (default: 15, máx: 100). |
| `-q, --query ` | Não | Busca textual no nome da instância. |
Saída texto (default):
```
ID NAME STATUS CONNECTION
i_01HABC... Atendimento connected unofficial
i_01HXYZ... Marketing offline unofficial
```
Saída JSON:
```json theme={null}
{
"ok": true,
"data": {
"instances": [
{
"id": "i_01HABC...",
"name": "Atendimento",
"status": "connected",
"connection_type": "unofficial"
}
],
"total": 1
}
}
```
### Exemplos
```bash theme={null}
# Apenas instâncias conectadas
zapsterapi instance list --status connected
# Procurar por nome
zapsterapi instance list -q "atendimento"
# Paginação
zapsterapi instance list --page 2 --per-page 50
```
A v1 da CLI cobre apenas a listagem. Para criar, atualizar ou desligar instâncias, use a [REST API](/pt-BR/v1/api-reference/instance/list-instances).
# message
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/reference/message
Envio, agendamento, cancelamento e listagem de mensagens WhatsApp via CLI.
## `zapsterapi message send`
Envia uma mensagem para um destinatário no WhatsApp. Suporta texto, mídia, templates WABA, botões interativos, mentions, agendamento, reply, view-once e mais.
```bash theme={null}
zapsterapi message send \
--recipient \
[--text ] \
[--instance-id ] \
[--send-at ] \
[--media-url | --media-base64 ] \
[--media-caption ] [--media-filename ] \
[--ptt | --ptv | --sticker] \
[--template-name --template-language [--template-components ]] \
[--button '' ...] [--buttons-mode ] \
[--mention ... | --mention-everyone] \
[--reply-to ] \
[--view-once] [--no-link-preview] [--auto-mention] \
[--profile ] [--json]
```
### Flags principais
| Flag | Obrigatório | Descrição |
| ---------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `--recipient ` | Sim | Telefone E.164 sem `+` (ex: `5511999999999`) ou ID de grupo (`group:`). |
| `--text ` | Condicional | Conteúdo da mensagem. Pelo menos um de `--text`, `--media-*` ou `--template-*` é necessário. |
| `--instance-id ` | Não | Instância específica de envio. Se omitido e você só tiver **uma instância conectada**, a CLI usa ela; com mais de uma, a flag é obrigatória. |
| `--send-at ` | Não | Agenda a mensagem (ISO 8601, ex: `2026-05-15T10:00:00Z`). Mínimo 1 minuto no futuro. |
### Mídia (`--media-*`)
Use `--media-url` sempre que possível — `--media-base64` carrega o arquivo no payload e fica reservado pra quando a URL não estiver acessível.
| Flag | Descrição |
| ------------------------- | ----------------------------------------------------- |
| `--media-url ` | URL pública/assinada do arquivo. **Preferida.** |
| `--media-base64 ` | Conteúdo em base64. Use só quando URL não for viável. |
| `--media-caption ` | Legenda (imagem/vídeo) ou texto sob o documento. |
| `--media-filename ` | Nome de arquivo (ex: `relatorio.pdf`). |
| `--ptt` | Marca o áudio como push-to-talk (mensagem de voz). |
| `--ptv` | Marca o vídeo como push-to-view (efêmero). |
| `--sticker` | Envia a mídia como figurinha. |
Exatamente um de `--media-url` ou `--media-base64` é necessário quando enviar mídia.
### Templates WABA (`--template-*`)
Templates são exclusivos de instâncias WABA (Meta oficial). **Mutuamente exclusivos com `--text` e `--media-*`.**
| Flag | Descrição |
| ------------------------------ | -------------------------------------------------------------------- |
| `--template-name ` | Nome do template aprovado na Meta. |
| `--template-language ` | Código de idioma (ex: `en_US`, `pt_BR`). |
| `--template-components ` | Array JSON de components com `header`/`body`/`buttons` e parâmetros. |
### Botões interativos (`--button`, `--buttons-mode`)
Repita `--button` até **3 vezes**. Cada valor é JSON com `type` + campos do tipo. Veja o [guia de botões](/pt-BR/v1/guides/messages-with-buttons) pra detalhes de cada tipo.
```bash theme={null}
--button '{"type":"reply","label":"Sim"}' \
--button '{"type":"call","label":"Ligar","phone_number":"+5511999999999"}' \
--button '{"type":"url","label":"Abrir","url":"https://exemplo.com"}'
```
| Tipo | Campos obrigatórios |
| ---------- | --------------------------------------- |
| `reply` | `label` |
| `call` | `label`, `phone_number` (E.164 com `+`) |
| `url` | `label`, `url` |
| `copyable` | `label`, `copy_code` |
`--buttons-mode ` é opcional (default `auto`). Use `interactive` pra forçar visual rico mesmo só com `reply`.
### Mentions (`--mention`, `--mention-everyone`)
| Flag | Descrição |
| -------------------- | -------------------------------------------- |
| `--mention ` | Telefone/JID a ser mencionado. Pode repetir. |
| `--mention-everyone` | Menciona @todos no grupo. |
`--mention` e `--mention-everyone` são **mutuamente exclusivos**.
### Outros
| Flag | Descrição |
| ------------------------- | ----------------------------------------------------- |
| `--reply-to ` | Responde a uma mensagem existente (limite de 7 dias). |
| `--view-once` | Marca como mensagem efêmera (some após visualizar). |
| `--no-link-preview` | Desativa o preview de URLs (default: ativo). |
| `--auto-mention` | Habilita auto-mention. |
### Saída — envio imediato (não-oficial / Baileys)
```json theme={null}
{
"ok": true,
"data": {
"kind": "immediate",
"message_id": "3EB0C68ECE69F2DF660423",
"message_trace_id": "x7jCGxw83jXOjaXR60qJQ24Zkrs4MacA"
}
}
```
### Saída — envio imediato (oficial / WABA)
```json theme={null}
{
"ok": true,
"data": {
"kind": "immediate",
"message_id": "wamid.HBgMNTU4NzgxMTcwMjYxFQIAERgSNDQyQzhBOTY1OEI5Mzk2MzI3AA=="
}
}
```
### Saída — agendamento (`--send-at` definido)
```json theme={null}
{
"ok": true,
"data": {
"kind": "scheduled",
"message_id": "msg_4rajud08wyl9pmi6bhnwr",
"send_at": "2026-05-15T10:00:00.000Z",
"status": "scheduled"
}
}
```
### Exemplos
**Texto simples:**
```bash theme={null}
zapsterapi message send --recipient 5511999999999 --text "olá"
```
**Texto + mídia + caption:**
```bash theme={null}
zapsterapi message send --recipient 5511999999999 \
--text "veja o relatório anexo" \
--media-url https://exemplo.com/relatorio.pdf \
--media-filename relatorio.pdf
```
**Botões interativos:**
```bash theme={null}
zapsterapi message send --recipient 5511999999999 \
--text "Como podemos te ajudar?" \
--button '{"type":"reply","label":"Suporte"}' \
--button '{"type":"reply","label":"Vendas"}' \
--buttons-mode interactive
```
**Template WABA:**
```bash theme={null}
zapsterapi message send --recipient 5511999999999 \
--template-name welcome --template-language pt_BR
```
**Mensagem em grupo com mention everyone:**
```bash theme={null}
zapsterapi message send --recipient group:120363021234567890 \
--text "Reunião em 10min @everyone" --mention-everyone
```
**Reply + view-once:**
```bash theme={null}
zapsterapi message send --recipient 5511999999999 \
--text "Aqui está a senha temporária" \
--reply-to msg_4rajud08wyl9pmi6bhnwr \
--view-once
```
**Agendamento:**
```bash theme={null}
zapsterapi message send --recipient 5511999999999 \
--text "Bom dia!" --send-at 2026-05-16T08:00:00-03:00
```
***
## `zapsterapi message cancel `
Cancela uma mensagem **agendada** (`scheduled`) ou **pendente** (`pending`). Mensagens já enviadas não podem ser canceladas.
```bash theme={null}
zapsterapi message cancel msg_4rajud08wyl9pmi6bhnwr [--profile ] [--json]
```
### Saída
```json theme={null}
{
"ok": true,
"data": {
"id": "msg_4rajud08wyl9pmi6bhnwr",
"status": "canceled"
}
}
```
### Códigos de erro específicos
| `error.code` | Causa |
| ----------------------- | ------------------------------------------------- |
| `message_not_found` | ID não existe ou não pertence à conta. |
| `message_cannot_cancel` | Mensagem já saiu do estado `scheduled`/`pending`. |
***
## `zapsterapi message list`
Lista mensagens dentro de uma janela de tempo. Útil pra auditoria, dashboards e agentes que precisam reconciliar status.
```bash theme={null}
zapsterapi message list \
--from \
--to \
[--status ] \
[--instance-id ] \
[--recipient ] \
[--message-id ] \
[--connection-type ] \
[--limit ] \
[--after ] \
[--profile ] \
[--json]
```
| Flag | Obrigatório | Descrição |
| -------------------------- | ----------- | ------------------------------------------------------------ |
| `--from ` | Sim | Início da janela. ISO 8601. |
| `--to ` | Sim | Fim da janela. ISO 8601. **Janela máxima de 90 dias.** |
| `--status ` | Não | Filtra por status. |
| `--instance-id ` | Não | Filtra por instância. |
| `--recipient ` | Não | Filtra por destinatário. |
| `--message-id ` | Não | Filtra por ID de mensagem (wamid ou `msg_...`). |
| `--connection-type ` | Não | `waba` ou `unofficial`. |
| `--limit ` | Não | 1–100, default 20. |
| `--after ` | Não | Cursor de paginação (`meta.next_cursor` da página anterior). |
### Saída
```json theme={null}
{
"ok": true,
"data": {
"data": [
{
"id": "msg_01HABC...",
"message_id": "wamid.HBg...",
"recipient": "5511999999999",
"status": "sent",
"connection_type": "waba",
"instance_id": "i_xyz1234abc",
"send_at": null,
"sent_at": "2026-05-08T10:00:00Z",
"canceled_at": null,
"errors": null
}
],
"meta": {
"next_cursor": null,
"has_more": false,
"limit": 20
}
}
}
```
### Códigos de erro específicos
| `error.code` | Causa |
| ------------------ | ----------------------------------------- |
| `from_after_to` | `--from` igual ou maior que `--to`. |
| `window_too_large` | Janela excede 90 dias. |
| `invalid_argument` | `--from` ou `--to` não é ISO 8601 válido. |
***
## Códigos de erro comuns
| `error.code` | Causa |
| ----------------------- | ------------------------------------------------------------------------------------ |
| `missing_recipient` | Flag `--recipient` ausente ou vazia. |
| `missing_text` | Nenhum de `--text`, `--media-*` ou `--template-*` foi informado. |
| `incompatible_content` | `--template-*` combinado com `--text` ou `--media-*` (são mutuamente exclusivos). |
| `invalid_media` | `--media-url` e `--media-base64` ambos presentes, ou nenhum dos dois. |
| `invalid_button` | JSON inválido em `--button`, mais de 3 botões, ou campo obrigatório do tipo ausente. |
| `invalid_template` | `--template-name` ou `--template-language` ausente. |
| `invalid_mentions` | `--mention` e `--mention-everyone` foram passados juntos. |
| `invalid_send_at` | `--send-at` não é ISO 8601 válido. |
| `invalid_token` | Token inválido ou expirado. |
| `invalid_recipient` | Número não é WhatsApp válido. |
| `instance_not_found` | `--instance-id` não pertence à conta. |
| `no_connected_instance` | `--instance-id` omitido e nenhuma instância está conectada. |
| `instance_id_required` | `--instance-id` omitido e há múltiplas instâncias conectadas. |
Para a referência completa do payload (todos os campos, validações cross-field, edge cases), veja a [REST API](/pt-BR/v1/api-reference/messages/sending) e o [guia de botões](/pt-BR/v1/guides/messages-with-buttons).
# recipient
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/reference/recipient
Verifica disponibilidade de números no WhatsApp.
## `zapsterapi recipient fetch`
Verifica se um número de telefone está disponível no WhatsApp e devolve o ID interno (jid/lid).
```bash theme={null}
zapsterapi recipient fetch \
--recipient \
[--instance-id ] \
[--profile ] \
[--json]
```
Se você só tiver uma instância ativa, a CLI auto-resolve o `--instance-id`. Com mais de uma, a flag é obrigatória.
Saída JSON:
```json theme={null}
{
"ok": true,
"data": {
"exists": true,
"id": "5511999999999@s.whatsapp.net",
"lid": null,
"original": "5511999999999"
}
}
```
| `error.code` | Causa |
| ---------------------- | ------------------------------------------------------------ |
| `missing_recipient` | `--recipient` ausente. |
| `instance_id_required` | Mais de uma instância e nenhuma `--instance-id` foi passada. |
| `invalid_token` | Token inválido. |
# SKILL para agentes
Source: https://developer.zapsterapi.com/pt-BR/v1/cli/skill
Skill copy-paste para Claude Code, Codex e qualquer agente compatível com o formato Claude — depois de instalada, o agente passa a usar a CLI sem prompts adicionais.
## O que é
A SKILL é um arquivo no formato [Claude Code Skills](https://docs.claude.com/) que descreve, em prosa otimizada para agentes, **quando** usar a CLI da Zapster, **como** se autenticar, **quais** comandos chamar para cada cenário e **como** interpretar os erros. Quando colada na pasta de skills do agente, ela vira parte do contexto permanente — o agente não precisa mais de prompt explicando como usar a `zapsterapi`.
Funciona com Claude Code (CLI ou IDE), Codex CLI e qualquer agente que respeite o formato `~/.claude/skills//SKILL.md`.
## Como instalar
```bash theme={null}
mkdir -p ~/.claude/skills/zapsterapi-cli
```
Use o botão "Copy" do bloco mais abaixo e salve em `~/.claude/skills/zapsterapi-cli/SKILL.md`.
Skills são carregadas no startup. Da próxima conversa, o agente já reconhece a CLI da Zapster e segue as convenções abaixo automaticamente.
Pré-requisito: a CLI precisa estar instalada (`npm i -g @zapsterapi/cli`). A skill assume Node.js 22+ e que o token está em `~/.zapsterapi/credentials` (use `zapsterapi auth login --token ` antes do primeiro uso).
## Conteúdo da skill
```markdown theme={null}
---
name: zapsterapi-cli
description: Send and schedule WhatsApp messages, cancel and list scheduled messages, check whether a phone number is on WhatsApp, and list instances using the @zapsterapi/cli command-line tool. Use when the user asks to send a WhatsApp message via Zapster, schedule a message for later, cancel a scheduled message, check if a phone number is on WhatsApp, or list Zapster instances from a shell or agent loop.
---
# zapsterapi-cli
## Pre-flight
Run these once per machine, in order:
1. Verify Node.js >= 22: `node --version`. Abort if older.
2. Check install: `zapsterapi --version`. If the binary is missing, install: `npm install -g @zapsterapi/cli`.
3. Authenticate. Ask the user for their token from https://app.zapsterapi.com/tokens. Do NOT echo the token back into chat or logs. Run: `zapsterapi auth login --token [--profile ]`. Login validates by calling `GET /v1/wa/instances?per_page=1`; a 401 aborts without persisting.
4. Confirm: `zapsterapi auth whoami --json`. Expect `data.valid: true`.
## Output discipline
Always pass `--json` when parsing programmatically. Every command returns the same envelope:
- Success: `{ "ok": true, "data": }`
- Failure: `{ "ok": false, "error": { "code": "", "message": "", "hint": "" } }`
Branch on `ok`. Never grep stdout text; the table format is for humans.
## Command catalog
### auth
| Command | Use when |
|---|---|
| `zapsterapi auth login --token [--profile ] [--base-url ]` | Persist credentials for a profile. |
| `zapsterapi auth logout [--profile ]` | Drop credentials for the active profile. Deletes the file if it was the last profile. |
| `zapsterapi auth whoami [--profile ] [--json]` | Verify the active token and print profile/base-url/token-suffix. |
### message
| Command | Use when |
|---|---|
| `zapsterapi message send --recipient --text [--instance-id ] [--send-at ] [--profile ] [--json]` | Send a text message now, or schedule for later by passing `--send-at`. `--instance-id` is auto-resolved when exactly one instance is connected. |
| `zapsterapi message cancel [--profile ] [--json]` | Cancel a `scheduled` or `pending` message by ID. Already-sent messages cannot be canceled. |
| `zapsterapi message list --from --to [--status ] [--instance-id ] [--recipient ] [--message-id ] [--connection-type ] [--limit ] [--after ] [--profile ] [--json]` | Audit/reconcile messages in a window. Window <= 90 days. Default `--limit` 20, max 100. Page with `--after meta.next_cursor`. |
Send response shapes:
- Immediate (Baileys): `data.kind = "immediate"`, `message_id`, `message_trace_id`.
- Immediate (WABA): `data.kind = "immediate"`, `message_id` (`wamid....`).
- Scheduled: `data.kind = "scheduled"`, `message_id` (`msg_...`), `send_at`, `status: "scheduled"`.
v1 covers text only. For media, buttons, or templates use the REST API.
### recipient
| Command | Use when |
|---|---|
| `zapsterapi recipient fetch --recipient [--instance-id ] [--profile ] [--json]` | Check whether a phone number is on WhatsApp before sending. Returns `{ id, lid, is_business, profile_picture }`. Auto-resolves `--instance-id` when exactly one instance is active. A 404 surfaces as `recipient_not_found`. |
### instance
| Command | Use when |
|---|---|
| `zapsterapi instance list [--status ] [--lookup-key ] [--page ] [--per-page ] [-q, --query ] [--profile ] [--json]` | Discover instance IDs, filter by status/lookup_key, or search by name. `--per-page` max 100. Create/update/delete are not in v1 — use the REST API. |
## Error code map
| `error.code` | Meaning | Agent action |
|---|---|---|
| `unauthorized` / `invalid_token` | Missing or expired token. | Re-run `auth login`; do not retry blindly. |
| `no_connected_instance` | `--instance-id` omitted and zero instances connected. | Run `instance list --status connected --json`; surface to user if empty. |
| `instance_id_required` | `--instance-id` omitted and >1 connected instance. | Pick one via `instance list` and pass `--instance-id` explicitly. |
| `instance_not_found` | ID does not belong to the account. | Re-list and confirm. |
| `missing_recipient` | `--recipient` empty/absent. | Stop and ask user. |
| `missing_text` | `--text` empty/absent. | Stop and ask user. |
| `invalid_recipient` / `recipient_not_found` | Number is not on WhatsApp. | Verify via `recipient fetch` first. |
| `invalid_send_at` | `--send-at` is not valid ISO 8601. | Reformat (e.g. `2026-05-15T10:00:00Z`). |
| `invalid_button` | Button payload rejected. | Drop to REST API; CLI v1 is text only. |
| `invalid_mentions` | Mentions payload rejected. | Drop to REST API. |
| `from_after_to` | `--from >= --to` on `message list`. | Swap or fix the bounds. |
| `window_too_large` | `message list` window > 90 days. | Page over multiple <=90d windows. |
| `message_not_found` | Cancel target does not exist on this account. | Verify ID; check profile. |
| `message_cannot_cancel` | Message already left `scheduled`/`pending`. | Surface to user; do not retry. |
| `network_error` | Transport-level failure. | Retry with backoff (max 3); then surface. |
## Multi-profile
Pass `--profile ` on any command, or set `ZAPSTERAPI_PROFILE=`. Default is `default`. Credentials live in `~/.zapsterapi/credentials`.
## Privacy
Never echo tokens, recipient phone numbers, or message bodies back into the chat or log files. When reporting results, redact (e.g. `5511******999`). Disable telemetry with `ZAPSTERAPI_DISABLE_TELEMETRY=1`.
```
## Próximos passos
* [Quickstart para agentes](/pt-BR/v1/cli/agent-quickstart) — prompt copy-paste pra primeira instalação automatizada.
* [Referência de comandos](/pt-BR/v1/cli/reference/auth) — detalhes de flags por comando.
* [Saída JSON](/pt-BR/v1/cli/json-output) — formato do envelope `{ ok, data, error }`.
# Instâncias
Source: https://developer.zapsterapi.com/pt-BR/v1/concepts/instances
O que é, o que faz e como funcionam
### O que é uma Instância?
Uma **Instância** é um conceito fundamental dentro das APIs para WhatsApp, representando uma unidade individual de conexão ao serviço do WhatsApp. Essencialmente, uma instância é como um "cliente" que se comunica com a API do WhatsApp, permitindo que você envie e receba mensagens, gerencie contatos, e realize outras operações relacionadas.
### O que uma Instância faz?
A Instância é responsável por gerenciar a comunicação entre a sua aplicação e o WhatsApp. Algumas das principais funcionalidades de uma instância incluem:
* **Envio e Recebimento de Mensagens**: Uma instância pode enviar e receber mensagens de texto, imagens, áudios, e outros tipos de mídia através da API.
* **Webhooks**: A instância também pode ser configurada para disparar webhooks, notificando a sua aplicação sobre eventos como o recebimento de novas mensagens ou mudanças de status.
### Como as Instâncias Funcionam?
Cada instância é autenticada com um número de telefone único e, uma vez conectada, ela mantém uma sessão ativa com os servidores do WhatsApp. Esta sessão é essencial para garantir que a instância possa enviar e receber mensagens em tempo real.
1. **Autenticação**: Para iniciar, a instância precisa ser autenticada com o WhatsApp. Isso geralmente envolve o escaneamento de um código QR ou o uso de credenciais específicas.
2. **Manutenção da Conexão**: Após a autenticação, a instância estabelece uma conexão persistente com o WhatsApp. Essa conexão deve ser mantida ativa para que a instância continue a funcionar corretamente.
3. **Interação com a API**: Uma vez conectada, a instância pode interagir com a API do WhatsApp para executar diversas operações, como o envio de mensagens, verificação do status dos contatos, e muito mais.
4. **Webhooks e Eventos**: A instância pode ser configurada para enviar notificações para a sua aplicação via webhooks quando certos eventos ocorrem, como a chegada de uma nova mensagem ou a mudança no status de um contato.
### Conclusão
Instâncias são essenciais para qualquer aplicação que precisa interagir com o WhatsApp através de uma API. Elas não só facilitam a comunicação bidirecional em tempo real, mas também oferecem ferramentas para gerenciar eventos de forma eficaz. Compreender como configurar e manter uma instância é crucial para o sucesso na integração com o WhatsApp.
## Tipos de conexão
Na Zapster, uma instância pode se conectar ao WhatsApp de duas formas: via QR code (não oficial) ou via API oficial da Meta (WABA). Ambas usam os mesmos endpoints para enviar e receber mensagens.
### Não oficial (QR code)
É o modo padrão. Você cria a instância, escaneia o QR code (ou usa o código de pareamento) e o número fica conectado. Por trás, a Zapster mantém uma conexão persistente com os servidores do WhatsApp.
Funciona bem para a maioria dos casos: automações, chatbots, envio de notificações. O risco é que, por não ser a API oficial, envios em volume muito alto ou práticas inadequadas podem gerar restrições no número.
### Oficial (WABA)
Usa a Cloud API da Meta, o canal oficial do WhatsApp para empresas. A conexão é feita via OAuth (Embedded Signup) ou token manual. Não precisa de QR code nem de dispositivo conectado.
As vantagens: estabilidade garantida pela Meta, sem risco de banimento por uso da API, suporte a templates de mensagem, e status de entrega/leitura confiáveis.
As limitações: a Meta cobra por conversa (o preço varia por categoria e país), não suporta envio para grupos, e o setup inicial é mais envolvido.
### Comparativo
| Característica | Não oficial (QR code) | Oficial (WABA) |
| ------------------ | ----------------------------------- | -------------------------------------------- |
| Conexão | QR code ou código de pareamento | OAuth com Meta ou token manual |
| Estabilidade | Boa | Alta (garantida pela Meta) |
| Risco de banimento | Existe, se usar de forma inadequada | Baixo (uso aprovado pela Meta) |
| Templates | Não suporta | Suporta (marketing, utility, authentication) |
| Custo por mensagem | Sem custo adicional | Meta cobra por conversa |
| Grupos | Suporta | Não suporta |
| Setup | Escanear QR code | Conectar conta Meta ou inserir token |
### Sobre migração
Atualmente não é possível converter uma instância não oficial para WABA (ou vice-versa). Esse recurso está em desenvolvimento. Quando disponível, a migração será transparente: seus webhooks e integrações continuarão funcionando sem alterações.
Para saber qual tipo escolher e como conectar uma instância WABA, veja o [guia de conexão WABA](/pt-BR/v1/guides/connect-waba-instance) e o [comparativo detalhado](/pt-BR/v1/guides/waba-vs-unofficial).
# Ciclo de Vida das Mensagens
Source: https://developer.zapsterapi.com/pt-BR/v1/concepts/message-lifecycle
Entenda os status e timestamps que acompanham cada mensagem
## Status de uma mensagem
Cada mensagem enviada pela Zapster passa por um ciclo de vida com status bem definidos. A tabela abaixo mostra todos os status possíveis:
| Status | Descrição | Quando acontece |
| ----------- | --------------------------------------- | -------------------------------------- |
| `pending` | Mensagem imediata sendo processada | Ao enviar sem `send_at` |
| `scheduled` | Agendada, aguardando o horário de envio | Ao enviar com `send_at` |
| `sent` | Enviada com sucesso ao WhatsApp | Envio confirmado pela instância |
| `failed` | Falha no envio | Após 3 tentativas sem sucesso |
| `canceled` | Cancelada pelo usuário | Ao chamar `DELETE /v1/wa/messages/:id` |
Quando uma mensagem chega em `sent`, `failed` ou `canceled`, o status é final. Não muda mais.
## Timestamps
Além do status, cada mensagem carrega timestamps que indicam o que aconteceu e quando. Nem todos são preenchidos em todas as mensagens — depende do tipo de envio e do que aconteceu depois.
| Campo | Preenchido quando | Observação |
| -------------- | ------------------------------ | -------------------------------------------------- |
| `created_at` | A mensagem é criada | Sempre preenchido |
| `send_at` | Definido pelo usuário | Só existe em mensagens agendadas |
| `sent_at` | Mensagem enviada com sucesso | Preenchido quando o WhatsApp aceita o envio |
| `delivered_at` | Entrega confirmada no aparelho | Quando a mensagem chega no celular do destinatário |
| `read_at` | Destinatário leu a mensagem | Quando o destinatário abre a conversa |
| `canceled_at` | Mensagem cancelada | Quando o usuário chama `DELETE` antes do envio |
## Sobre entrega e leitura
Os campos `delivered_at` e `read_at` dependem de fatores que estão fora do controle da Zapster:
* Se o destinatário desativou a confirmação de leitura nas configurações do WhatsApp, `read_at` nunca vai ser preenchido
* Se o celular do destinatário está sem internet, `delivered_at` pode demorar até ele ficar online de novo
* Esses campos não alteram o status da mensagem. Uma vez que o status é `sent`, ele permanece `sent`. Entrega e leitura são informações extras, registradas apenas nos timestamps
Na prática, você pode usar `delivered_at` e `read_at` para montar relatórios de entrega e leitura, mas não conte com eles para fluxos críticos. Nem todo destinatário vai gerar esses eventos.
## Quando uma mensagem falha
Se o status de uma mensagem é `failed`, o campo `errors` traz uma lista com os detalhes do que deu errado. A estrutura do erro varia um pouco dependendo do tipo de instância.
Para **instâncias oficiais (WABA)**, o `errors` inclui o código de erro da Meta e um link direto para a documentação deles:
```json theme={null}
{
"errors": [
{
"code": 131047,
"title": "Re-engagement message",
"details": "Mais de 24 horas se passaram desde a última resposta do destinatário.",
"href": "https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/"
}
]
}
```
Alguns erros comuns em instâncias WABA:
* **131047**: Janela de 24 horas expirada. O destinatário não respondeu nas últimas 24h e você tentou enviar uma mensagem que não é template.
* **132000**: Template não encontrado. Verifique se o nome e o idioma do template estão corretos.
* **131026**: Número não está no WhatsApp ou é inválido.
Para **instâncias não oficiais (QR code)**, os erros mais comuns são:
* Instância offline (o celular perdeu conexão ou a sessão expirou)
* Número bloqueado ou inexistente no WhatsApp
* Limite de envio atingido pelo WhatsApp
Em todos os casos, o campo `errors` traz informações suficientes para você entender o que aconteceu e decidir se vale tentar novamente.
# Cobrança de mensagens no WhatsApp oficial (WABA)
Source: https://developer.zapsterapi.com/pt-BR/v1/concepts/message-pricing
Como funciona a cobrança da Meta no canal oficial do WhatsApp (WABA), o que muda em 2026 nas mensagens de serviço e onde entram os templates de marketing, utilidade e autenticação
O canal oficial do WhatsApp (WABA) é pago, e quem cobra pelas mensagens é a **Meta**, não a Zapster. São duas coisas separadas: a assinatura da sua instância na Zapster, de um lado, e o que a Meta cobra pelo envio das mensagens, do outro. A cobrança da Meta é feita através da conta de WhatsApp Business ligada ao seu número.
Esta cobrança vale **apenas para o canal oficial (WABA)**. Instâncias não oficiais (QR code) não passam por essa cobrança da Meta. Se você ainda está decidindo entre os dois tipos, veja o comparativo em [WABA vs não oficial](/pt-BR/v1/guides/waba-vs-unofficial).
## Os dois grupos de mensagens
No canal oficial, o que a Meta cobra depende do tipo de mensagem que você envia:
* **Mensagens livres (de serviço)**: texto, mídia ou botões enviados em resposta a um cliente, dentro da janela de conversa de 24 horas. Pela definição da Meta, é qualquer mensagem que não seja um template.
* **Templates**: mensagens aprovadas pela Meta, usadas para iniciar conversa ou enviar fora da janela de 24 horas. Cada categoria de template (marketing, utilidade e autenticação) tem cobrança própria, que varia conforme o país do destinatário. Consulte a [tabela de preços da Meta](https://developers.facebook.com/docs/whatsapp/pricing) para os valores por categoria.
O restante desta página foca nas mensagens livres (de serviço), que são as que mais mudam em 2026.
## O que é uma "mensagem de serviço"
É toda mensagem livre (texto, mídia ou botões) que você envia em resposta a um cliente, dentro da janela de 24 horas. Pela definição da Meta, é qualquer mensagem que não seja um template. Até hoje elas são **gratuitas**, assim desde novembro de 2024.
## O que muda em 2026 e quando
| Data | O que passa a ser cobrado |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **1 de agosto de 2026** | Mensagens do **Meta Business Agent** (respostas geradas pela inteligência artificial da Meta) passam a ser cobradas por token: US\$ 2,00 a cada 1 milhão de tokens, o que dá por volta de 4 a 5 centavos de dólar por mensagem. Isso só vale se você usar o agente de IA da Meta. |
| **1 de outubro de 2026** | As **mensagens de serviço** (as mensagens livres) passam a ser cobradas por mensagem enviada. Elas eram gratuitas desde novembro de 2024. No mesmo dia, mensagens de utilidade enviadas dentro da janela de 24 horas, gratuitas desde 1 de julho de 2025, também passam a ser cobradas. |
## Quanto vai custar
A Meta ainda não publicou os valores. Segundo a documentação, os preços que entram em vigor em 1 de outubro de 2026 serão anunciados **até 1 de setembro de 2026**. O preço de uma mensagem de serviço vai acompanhar o preço já usado para mensagens de utilidade e autenticação, que **varia conforme o país** do cliente. A Meta informou que não haverá desconto por volume para mensagens de serviço.
## O que continua igual
* A regra da janela de 24 horas não muda: mensagens livres só saem com a janela aberta. O que muda é que elas deixam de ser gratuitas.
* Os templates já eram pagos e seguem com a cobrança própria deles.
* Essa cobrança é só do canal **oficial** (WABA). Instâncias não oficiais (QR code) não passam por essa cobrança da Meta.
## Em resumo
Hoje, responder um cliente dentro da janela de 24 horas não custa nada. A partir de **1 de outubro de 2026**, cada uma dessas respostas passa a ter um custo cobrado pela Meta. Se você envia muitas mensagens de atendimento, vale acompanhar o anúncio de preços de setembro de 2026 e já incluir esse custo no seu planejamento.
Fonte: [WhatsApp Business Platform: Non-Template Messages Pricing](https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing/non-template-messages), documentação oficial da Meta. As datas e os valores são definidos pela Meta e podem mudar.
# Rate limit
Source: https://developer.zapsterapi.com/pt-BR/v1/concepts/rate-limit
Limite de requisições da API da Zapster (3 req/s por token), headers RateLimit-Limit, RateLimit-Remaining e RateLimit-Reset, resposta 429 rate_limited e como tratar com backoff e fila.
O **rate limit** (limite de requisições) controla quantas chamadas você pode fazer à API da Zapster em um intervalo de tempo. Quando você passa desse limite, a API responde com o status `429 Too Many Requests` em vez de processar a requisição.
## Por que o rate limit existe
O limite protege duas coisas ao mesmo tempo:
* **A plataforma**, mantendo a API estável e justa para todos os clientes, sem que um único integrador consiga sobrecarregar o serviço.
* **O seu número de WhatsApp**, evitando rajadas de envio que o WhatsApp interpreta como comportamento de spam. Enviar devagar e de forma constante é mais seguro para a saúde do seu número do que disparar tudo de uma vez.
## Limite padrão
O limite padrão é de **3 requisições por segundo**, contadas por token de acesso (ou seja, por conta). Como toda chamada à API é autenticada, a cota é sempre atrelada ao seu token.
O limite é aplicado a **todas** as rotas da API, não só ao envio de mensagens. As chamadas de listagem, consulta de destinatário e gestão de instância também consomem a mesma cota.
### Flexibilidade por plano
O limite padrão atende à maioria das integrações. Se o seu volume exige mais, a cota da sua conta pode ser ampliada de acordo com o seu plano ou mediante contratação. [Fale com o suporte](https://wa.me/5587999079455?text=Olá,%20preciso%20aumentar%20o%20rate%20limit%20da%20minha%20conta) para avaliarmos o limite ideal e a melhor condição para o seu caso.
Antes de pedir um limite maior, trate o rate limit no seu lado. O jeito mais robusto de integrar é **nunca depender do 429**: controle o ritmo de envio no seu código (fila e throttling) para se manter dentro do limite. Um limite maior ajuda em picos, mas não substitui o controle de ritmo no cliente.
## Headers de rate limit
Toda resposta da API traz headers de rate limit que informam o estado atual da sua cota. Eles seguem o padrão de cabeçalhos [RateLimit para HTTP](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/) proposto pela IETF.
| Header | Descrição |
| --------------------- | -------------------------------------------------------------------------------------------------- |
| `RateLimit-Limit` | Número máximo de requisições permitidas na janela atual (ex.: `3`). |
| `RateLimit-Remaining` | Quantas requisições ainda restam na janela atual. |
| `RateLimit-Reset` | Quantos **segundos** faltam até a janela reiniciar (é um tempo relativo, não um timestamp). |
| `RateLimit-Policy` | A política aplicada, no formato `limite;w=janela` (ex.: `3;w=1` = 3 requisições a cada 1 segundo). |
| `Retry-After` | Presente **apenas na resposta 429**. Quantos **segundos** esperar antes de tentar de novo. |
### Exemplo de resposta 200
Uma requisição bem-sucedida, ainda dentro da cota:
```http theme={null}
HTTP/1.1 200 OK
Content-Type: application/json
RateLimit-Policy: 3;w=1
RateLimit-Limit: 3
RateLimit-Remaining: 2
RateLimit-Reset: 1
```
### Exemplo de resposta 429
Quando você passa do limite, a API responde:
```http theme={null}
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
RateLimit-Policy: 3;w=1
RateLimit-Limit: 3
RateLimit-Remaining: 0
RateLimit-Reset: 1
Retry-After: 1
{
"errors": [
{
"code": "rate_limited",
"messages": "You can only make 3 requests every 1 seconds."
}
]
}
```
O campo `code` é sempre `rate_limited`, e o texto de `messages` reflete o limite atual da sua conta e o tamanho da janela.
## Como tratar o rate limit
A estratégia recomendada tem duas camadas.
**1. Controle o ritmo antes de enviar (preferencial).** Para integrações de alto volume (disparos em lote, filas de mensagens), limite o seu próprio ritmo de saída para nunca ultrapassar o limite. Use uma fila com throttling (por exemplo, `bottleneck` ou `p-queue` no Node.js, ou `rate.Limiter` em Go) configurada para o mesmo teto da sua conta. Assim você não depende de receber um 429.
**2. Trate o 429 quando ele acontecer (rede de segurança).** Mesmo com throttling, mantenha um retry:
* Ao receber `429`, espere o número de segundos indicado em `Retry-After` (ou, na falta dele, em `RateLimit-Reset`) e tente de novo.
* Se não houver header, use um **backoff exponencial** com jitter (espere 1s, depois 2s, 4s, e assim por diante, com um teto).
* Antes de enviar, você também pode olhar `RateLimit-Remaining`: se estiver perto de zero, aguarde `RateLimit-Reset` segundos antes da próxima chamada.
## Exemplos de código
Os exemplos abaixo enviam uma mensagem e tratam o `429` respeitando os headers. Troque `YOUR_API_TOKEN` pelo seu token e `YOUR_INSTANCE_ID` pelo ID da instância.
```javascript Node.js (cliente, fetch + backoff) theme={null}
// Cliente resiliente: respeita Retry-After/RateLimit-Reset e faz backoff.
async function sendWithRetry(payload, { maxRetries = 5 } = {}) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify(payload),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
if (res.status !== 429) return res
// Retry-After e RateLimit-Reset vêm em segundos.
const hint =
Number(res.headers.get('retry-after')) ||
Number(res.headers.get('ratelimit-reset')) ||
0
// Se o servidor não mandar dica, usa backoff exponencial (teto de 30s).
const backoff = Math.min(2 ** attempt, 30)
const delayMs = (Math.max(hint, backoff) + Math.random() * 0.25) * 1000
await new Promise((resolve) => setTimeout(resolve, delayMs))
}
throw new Error('Rate limit: tentativas esgotadas')
}
const res = await sendWithRetry({
recipient: '5511999999999',
text: 'Olá! Seu pedido foi confirmado.',
})
console.log((await res.json()).message_id)
```
```javascript Node.js (servidor, fila com throttling) theme={null}
// Para disparos em lote: limite a saída a 3 req/s com bottleneck,
// assim você nunca chega no 429.
const Bottleneck = require('bottleneck')
const limiter = new Bottleneck({
maxConcurrent: 3,
minTime: 334, // ~1 requisição a cada 334ms = 3 por segundo
reservoir: 3,
reservoirRefreshAmount: 3,
reservoirRefreshInterval: 1000,
})
async function sendMessage(payload) {
const res = await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify(payload),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
if (!res.ok) throw new Error(`HTTP ${res.status}`)
return res.json()
}
// Toda chamada passa pela fila, respeitando o teto de 3 req/s.
const send = limiter.wrap(sendMessage)
const recipients = ['5511999999999', '5511888888888', '5511777777777']
await Promise.all(recipients.map((r) => send({ recipient: r, text: 'Olá!' })))
```
```python Python (requests + backoff) theme={null}
import random
import time
import requests
URL = "https://api.zapsterapi.com/v1/wa/messages"
HEADERS = {
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
}
def send_with_retry(payload, max_retries=5):
delay = 1.0 # backoff usado só se o servidor não mandar dica
for _ in range(max_retries + 1):
res = requests.post(URL, headers=HEADERS, json=payload, timeout=30)
if res.status_code != 429:
res.raise_for_status()
return res.json()
# Retry-After e RateLimit-Reset vêm em segundos.
hint = res.headers.get("Retry-After") or res.headers.get("RateLimit-Reset")
sleep_for = float(hint) if hint else delay
time.sleep(sleep_for + random.uniform(0, 0.25))
delay = min(delay * 2, 30)
raise RuntimeError("Rate limit: tentativas esgotadas")
print(send_with_retry({"recipient": "5511999999999", "text": "Olá!"}))
```
```go Go (rate.Limiter + backoff) theme={null}
package main
import (
"bytes"
"context"
"fmt"
"net/http"
"strconv"
"time"
"golang.org/x/time/rate"
)
// 3 requisições por segundo, igual ao limite padrão da conta.
var limiter = rate.NewLimiter(rate.Every(time.Second/3), 3)
func send(ctx context.Context, payload []byte) (*http.Response, error) {
const maxRetries = 5
for attempt := 0; attempt <= maxRetries; attempt++ {
// Segura o ritmo antes de sair: mantém 3 req/s.
if err := limiter.Wait(ctx); err != nil {
return nil, err
}
req, _ := http.NewRequestWithContext(ctx, http.MethodPost,
"https://api.zapsterapi.com/v1/wa/messages", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusTooManyRequests {
return res, nil
}
res.Body.Close()
// Retry-After e RateLimit-Reset vêm em segundos.
wait := time.Second
if v := res.Header.Get("Retry-After"); v != "" {
if s, convErr := strconv.Atoi(v); convErr == nil {
wait = time.Duration(s) * time.Second
}
}
select {
case <-time.After(wait):
case <-ctx.Done():
return nil, ctx.Err()
}
}
return nil, fmt.Errorf("rate limited: tentativas esgotadas")
}
func main() {
payload := []byte(`{"recipient":"5511999999999","text":"Olá!"}`)
res, err := send(context.Background(), payload)
if err != nil {
panic(err)
}
defer res.Body.Close()
fmt.Println(res.Status)
}
```
```bash cURL / bash theme={null}
# Opção A: curl repete sozinho e respeita o Retry-After do 429.
curl --retry 5 --retry-all-errors --retry-delay 1 \
-X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{"recipient":"5511999999999","text":"Olá!"}'
# Opção B: controle manual lendo os headers e dormindo até a janela reiniciar.
url="https://api.zapsterapi.com/v1/wa/messages"
for attempt in $(seq 1 5); do
# -D salva os headers; -w retorna o status HTTP.
status=$(curl -sS -o response.json -D headers.txt -w '%{http_code}' \
-X POST "$url" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{"recipient":"5511999999999","text":"Olá!"}')
if [ "$status" != "429" ]; then
cat response.json
break
fi
# RateLimit-Reset é o número de segundos até a janela reiniciar.
reset=$(grep -i '^ratelimit-reset:' headers.txt | tr -d '\r' | awk '{print $2}')
echo "Rate limited. Aguardando ${reset:-1}s..."
sleep "${reset:-1}"
done
```
## Em resumo
* O padrão é **3 requisições por segundo** por token de acesso, válido para toda a API.
* Toda resposta traz `RateLimit-Limit`, `RateLimit-Remaining` e `RateLimit-Reset`; o 429 traz também `Retry-After`. `RateLimit-Reset` e `Retry-After` são contados em segundos.
* O 429 devolve `{ "errors": [{ "code": "rate_limited", ... }] }`.
* Controle o ritmo no seu código (fila e throttling) para não depender do 429, e mantenha um retry com backoff como rede de segurança.
* Precisa de mais volume? [Fale com o suporte](https://wa.me/5587999079455?text=Olá,%20preciso%20aumentar%20o%20rate%20limit%20da%20minha%20conta) para avaliar um limite maior.
# Mensagens Agendadas
Source: https://developer.zapsterapi.com/pt-BR/v1/concepts/scheduled-messages
Como agendar o envio de mensagens do WhatsApp para uma data e hora futura
## O que são mensagens agendadas
Mensagens agendadas permitem que você envie uma mensagem via API hoje, mas ela só será entregue ao destinatário em uma data e hora que você escolher. Basta incluir o campo `send_at` na requisição de envio e a Zapster cuida do resto.
Isso funciona para qualquer tipo de mensagem: texto, mídia (imagem, áudio, vídeo, documento), templates e mensagens com botões. Você não precisa montar cron jobs, filas ou timers no seu sistema. A Zapster armazena a mensagem e garante o envio no horário certo.
Na prática, é como deixar uma mensagem programada no WhatsApp, só que via API e com controle total sobre o que acontece em cada etapa.
## Casos de uso
* **Lembretes de pagamento**: agendar uma cobrança para o dia do vencimento da fatura
* **Follow-ups de venda**: mandar uma mensagem 2 dias após o primeiro contato com um lead
* **Campanhas com horário definido**: preparar tudo na segunda-feira e distribuir os envios ao longo da semana
* **Confirmações de consulta**: lembrar o paciente 1 dia antes do agendamento
* **Onboarding de clientes**: enviar dicas de uso nos primeiros dias após o cadastro
* **Pesquisas de satisfação**: disparar NPS alguns dias depois de uma compra ou atendimento
## Como funciona
O fluxo é direto:
1. Você envia um `POST /v1/wa/messages` com o campo `send_at` preenchido com a data e hora desejada
2. A Zapster armazena a mensagem e cria um agendamento interno
3. No horário definido, a mensagem é enviada automaticamente pela instância configurada
Se o envio falhar (instância offline, número bloqueado, problema de rede), o sistema faz até 3 tentativas. Se todas falharem, o status da mensagem vai para `failed` e o campo `errors` traz os detalhes do problema.
## Ciclo de vida da mensagem
Toda mensagem agendada passa pelos seguintes estados:
| De | Para | Quando acontece |
| ----------- | ----------- | ------------------------------------------------------- |
| — | `scheduled` | Mensagem criada via API com `send_at` |
| `scheduled` | `sent` | Enviada com sucesso no horário agendado |
| `scheduled` | `failed` | Falha no envio após 3 tentativas |
| `scheduled` | `canceled` | Cancelada pelo usuário via `DELETE /v1/wa/messages/:id` |
Depois que a mensagem atinge o status `sent`, o sistema também registra os timestamps `delivered_at` (entrega confirmada no aparelho) e `read_at` (destinatário leu a mensagem). Mas o status continua como `sent` — entrega e leitura são rastreadas apenas por timestamps.
## Limites por plano
| | Essential | Pro | Enterprise |
| --------------------- | --------- | ------- | ---------- |
| Agendadas simultâneas | 10 | 500 | 10.000 |
| Antecedência máxima | 7 dias | 1 ano | Sem limite |
| Retenção do histórico | 24 horas | 30 dias | 180 dias |
Explicando cada linha:
* **Agendadas simultâneas**: é o número de mensagens com status `scheduled` que podem existir ao mesmo tempo na sua conta. Se você tem 10 mensagens pendentes no plano Essential, precisa esperar uma ser enviada (ou cancelar alguma) antes de agendar outra.
* **Antecedência máxima**: é o quão longe no futuro você pode agendar. No plano Essential, até 7 dias. No Pro, até 1 ano.
* **Retenção do histórico**: por quanto tempo você consegue consultar mensagens já enviadas. No Essential, apenas as últimas 24 horas ficam disponíveis para consulta.
## Compatibilidade
Funciona com instâncias oficiais (WABA) e não oficiais (QR code). Não precisa mudar nada na configuração da sua instância para usar agendamento.
## Sobre timezones
O campo `send_at` aceita datas no formato ISO 8601, que inclui informação de timezone. Na prática, você tem duas opções:
* Enviar com timezone explícito: `"2026-03-30T09:00:00-03:00"` (horário de Brasília)
* Enviar em UTC: `"2026-03-30T12:00:00Z"`
Os dois exemplos acima representam o mesmo momento. A diferença é só a forma de escrever.
A resposta da API sempre retorna datas em UTC, independente do timezone que você usou no envio.
Se você está no Brasil e não quer fazer conta de fuso horário, envie a data no horário local com `-03:00` no final. Exemplo: `"2026-03-30T09:00:00-03:00"` para enviar às 9h da manhã no horário de Brasília.
# Tokens
Source: https://developer.zapsterapi.com/pt-BR/v1/concepts/tokens
### O que são Tokens?
**Tokens** são unidades de dados que representam uma permissão ou um acesso. No contexto da **Zapster API**, tokens são utilizados como uma maneira segura de autenticar e autorizar o acesso a recursos protegidos. Eles são uma alternativa aos métodos tradicionais de autenticação, como o uso de nome de usuário e senha, oferecendo uma forma mais eficiente e segura de gerenciar o acesso à **Zapster API**.
### O que os Tokens fazem?
Os tokens desempenham um papel crucial na autenticação e autorização dentro da **Zapster API**. Algumas das principais funcionalidades dos tokens incluem:
* **Autenticação**: Tokens são usados para verificar a identidade de um cliente da **Zapster API**. Após a autenticação inicial, um token é gerado e pode ser utilizado para acessar recursos protegidos da API sem a necessidade de reenviar credenciais sensíveis como senhas.
* **Autorização**: Além de autenticar, tokens também contêm informações sobre os direitos e permissões de um cliente, determinando quais recursos ou operações ele pode acessar ou executar na **Zapster API**.
* **Sessões Sem Estado (Stateless)**: Como os tokens contêm todas as informações necessárias para autenticação e autorização, o servidor da **Zapster API** pode validar as requisições sem precisar manter o estado da sessão do cliente, o que melhora a escalabilidade da API.
### Como os Tokens funcionam na Zapster API?
1. **Geração do Token (JWT)**: O cliente da **Zapster API** gera um token JWT (JSON Web Token) através do painel de gestão de tokens disponível em [https://app.zapsterapi.com/tokens](https://app.zapsterapi.com/tokens).
2. **Uso do Token**: O cliente armazena o token e o envia junto com todas as requisições subsequentes para acessar recursos protegidos da **Zapster API**.
3. **Validação do Token**: A cada requisição recebida, o servidor da **Zapster API** valida o token JWT. Se o token for válido e não expirou, o servidor processa a requisição e retorna os dados solicitados. Se o token for inválido ou expirou, o acesso é negado.
```mermaid theme={null}
sequenceDiagram
participant Cliente as Cliente da Zapster API
participant ZapsterAPI as Zapster API
Cliente->>ZapsterAPI: Gera Token JWT
Cliente->>ZapsterAPI: Requisição com Token JWT
ZapsterAPI-->>Cliente: Valida e Retorna Dados
```
# Webhooks
Source: https://developer.zapsterapi.com/pt-BR/v1/concepts/webhooks
### O que são Webhooks?
**Webhooks** são uma maneira eficiente e automatizada de uma aplicação enviar dados em tempo real para outra aplicação. Eles permitem que sistemas diferentes comuniquem eventos específicos sem a necessidade de uma solicitação ativa da aplicação receptora. Em vez disso, a aplicação que gera o evento envia uma notificação, normalmente na forma de uma solicitação HTTP POST, para uma URL previamente configurada pela aplicação receptora.
### O que os Webhooks fazem?
Os Webhooks são usados para notificar sua aplicação sobre eventos que ocorrem em outra aplicação ou serviço. Algumas das tarefas comuns realizadas por Webhooks incluem:
* **Notificações em Tempo Real**: A aplicação receptora é imediatamente notificada quando algo acontece, como a criação de um novo pedido, uma mudança de status, ou uma nova mensagem.
* **Automação de Processos**: Permitem automatizar respostas ou ações em sua aplicação quando certos eventos ocorrem, sem a necessidade de consultas constantes à API.
* **Integração entre Sistemas**: Facilitam a integração entre sistemas diferentes, permitindo que eventos em um sistema desencadeiem ações automáticas em outro.
### Como os Webhooks funcionam?
1. **Configuração**: Primeiro, a aplicação receptora deve configurar um endpoint (uma URL pública) que estará pronto para receber as notificações via Webhook.
2. **Registro do Webhook**: A aplicação emissora precisa ser configurada para enviar notificações para o endpoint do Webhook sempre que um evento específico ocorrer.
3. **Envio do Evento**: Quando o evento configurado ocorre, a aplicação emissora envia uma solicitação HTTP POST para o endpoint do Webhook, incluindo no corpo da requisição os dados relevantes sobre o evento.
4. **Processamento do Evento**: A aplicação receptora processa a informação recebida e pode executar várias ações em resposta ao evento, como atualizar um banco de dados, enviar um e-mail, ou disparar outro processo interno.
```mermaid theme={null}
sequenceDiagram
participant Zapster as Zapster API
participant Webhook as Endpoint Webhook
Zapster->>Webhook: Envia Evento (HTTP POST)
Webhook-->>Zapster: Resposta (200 OK / Erro >= 400)
Zapster->>Webhook: Reenvio em caso de erro (até 5 vezes)
```
### Um webhook, várias instâncias
Um webhook na Zapster é um destino que você cadastra uma vez (a URL que vai receber os eventos) e reaproveita em quantas instâncias quiser. Cada instância decide, por conta própria, quais eventos quer receber naquele destino.
Vale entender dois conceitos que trabalham juntos:
* **O webhook (na sua conta)**: guarda a URL, um nome e o status (ligado ou desligado). É o endereço para onde as notificações são enviadas. Ele pertence à sua conta, não a uma instância específica.
* **A associação com cada instância**: toda instância que usa o webhook ganha sua própria associação. É nela que ficam os eventos assinados e os ajustes daquela instância (ativar/desativar, modo de teste). Um mesmo webhook pode estar associado a várias instâncias ao mesmo tempo.
```mermaid theme={null}
flowchart LR
W["Webhook
(URL + nome + status)"]
W --> A["Instância A
eventos: message.received"]
W --> B["Instância B
eventos: message.sent, message.read"]
W --> C["Instância C
eventos: instance.connected"]
```
#### Por que compartilhar um webhook
O principal motivo é manutenção centralizada. Se você tem dezenas de instâncias enviando eventos para o mesmo sistema, cadastrar a URL uma única vez e reutilizá-la evita repetir configuração. Quando a URL precisar mudar (troca de servidor, novo domínio, ajuste de rota), você altera em um só lugar e a mudança vale para todas as instâncias que usam aquele webhook.
```mermaid theme={null}
flowchart LR
E["Você edita a URL
uma única vez"] --> W["Webhook"]
W --> A["Instância A"]
W --> B["Instância B"]
W --> C["Instância C"]
```
#### Como fazer na prática
O mesmo endpoint (`POST /wa/instances/:id/webhooks`) cobre os dois caminhos. A diferença está no corpo da requisição:
* Envie **`url`** para criar um webhook novo e já associá-lo à instância. Use na primeira instância.
* Envie **`webhook_id`** para reutilizar um webhook que já existe. Use nas demais instâncias.
O corpo aceita **`url`** OU **`webhook_id`**, nunca os dois juntos. Se ambos forem enviados, a Zapster prioriza o `webhook_id`. O campo `events` é sempre obrigatório e precisa ter pelo menos um evento.
**1. Primeira instância: crie o webhook com `url`**
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/instances/PRIMEIRA_INSTANCIA/webhooks \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://sua-app.com/webhook",
"name": "Webhook de produção",
"events": ["message.received", "message.sent"]
}'
```
```javascript JavaScript (client) theme={null}
const response = await fetch(
'https://api.zapsterapi.com/v1/wa/instances/PRIMEIRA_INSTANCIA/webhooks',
{
method: 'POST',
headers: {
'Authorization': 'Bearer SEU_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://sua-app.com/webhook',
name: 'Webhook de produção',
events: ['message.received', 'message.sent'],
}),
},
);
const data = await response.json();
console.log(data);
// A resposta traz o id do webhook criado, que você reaproveita nas próximas instâncias.
// { "webhook_id": "2nenz69l0xbf0m3uu9tfo", ... }
```
```javascript JavaScript (server) theme={null}
// Node.js 18+ (fetch nativo). Guarde o token em variável de ambiente.
const response = await fetch(
'https://api.zapsterapi.com/v1/wa/instances/PRIMEIRA_INSTANCIA/webhooks',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ZAPSTER_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://sua-app.com/webhook',
name: 'Webhook de produção',
events: ['message.received', 'message.sent'],
}),
},
);
const { webhook_id } = await response.json();
console.log('Webhook criado:', webhook_id);
```
```php PHP theme={null}
true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer SEU_TOKEN',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'url' => 'https://sua-app.com/webhook',
'name' => 'Webhook de produção',
'events' => ['message.received', 'message.sent'],
]),
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo $data['webhook_id'];
```
```go Go theme={null}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"url": "https://sua-app.com/webhook",
"name": "Webhook de produção",
"events": []string{"message.received", "message.sent"},
})
req, _ := http.NewRequest(
http.MethodPost,
"https://api.zapsterapi.com/v1/wa/instances/PRIMEIRA_INSTANCIA/webhooks",
bytes.NewReader(body),
)
req.Header.Set("Authorization", "Bearer SEU_TOKEN")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.zapsterapi.com/v1/wa/instances/PRIMEIRA_INSTANCIA/webhooks",
headers={"Authorization": "Bearer SEU_TOKEN"},
json={
"url": "https://sua-app.com/webhook",
"name": "Webhook de produção",
"events": ["message.received", "message.sent"],
},
)
data = response.json()
print(data["webhook_id"])
```
```java Java theme={null}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class CreateWebhook {
public static void main(String[] args) throws Exception {
String body = """
{
"url": "https://sua-app.com/webhook",
"name": "Webhook de produção",
"events": ["message.received", "message.sent"]
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.zapsterapi.com/v1/wa/instances/PRIMEIRA_INSTANCIA/webhooks"))
.header("Authorization", "Bearer SEU_TOKEN")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
```
```ruby Ruby theme={null}
require "net/http"
require "json"
require "uri"
uri = URI("https://api.zapsterapi.com/v1/wa/instances/PRIMEIRA_INSTANCIA/webhooks")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer SEU_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
url: "https://sua-app.com/webhook",
name: "Webhook de produção",
events: ["message.received", "message.sent"]
}.to_json
response = http.request(request)
data = JSON.parse(response.body)
puts data["webhook_id"]
```
**2. Demais instâncias: reutilize com `webhook_id`**
Use o `webhook_id` devolvido no passo anterior para associar o mesmo webhook a outra instância. Note que os eventos podem ser diferentes: cada instância assina o que faz sentido para ela.
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/instances/SEGUNDA_INSTANCIA/webhooks \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"webhook_id": "2nenz69l0xbf0m3uu9tfo",
"events": ["message.received"]
}'
```
```javascript JavaScript (client) theme={null}
const response = await fetch(
'https://api.zapsterapi.com/v1/wa/instances/SEGUNDA_INSTANCIA/webhooks',
{
method: 'POST',
headers: {
'Authorization': 'Bearer SEU_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
webhook_id: '2nenz69l0xbf0m3uu9tfo',
events: ['message.received'],
}),
},
);
const data = await response.json();
console.log(data);
```
```javascript JavaScript (server) theme={null}
// Node.js 18+ (fetch nativo).
const response = await fetch(
'https://api.zapsterapi.com/v1/wa/instances/SEGUNDA_INSTANCIA/webhooks',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ZAPSTER_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
webhook_id: '2nenz69l0xbf0m3uu9tfo',
events: ['message.received'],
}),
},
);
console.log(await response.json());
```
```php PHP theme={null}
true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer SEU_TOKEN',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'webhook_id' => '2nenz69l0xbf0m3uu9tfo',
'events' => ['message.received'],
]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
```
```go Go theme={null}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"webhook_id": "2nenz69l0xbf0m3uu9tfo",
"events": []string{"message.received"},
})
req, _ := http.NewRequest(
http.MethodPost,
"https://api.zapsterapi.com/v1/wa/instances/SEGUNDA_INSTANCIA/webhooks",
bytes.NewReader(body),
)
req.Header.Set("Authorization", "Bearer SEU_TOKEN")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.zapsterapi.com/v1/wa/instances/SEGUNDA_INSTANCIA/webhooks",
headers={"Authorization": "Bearer SEU_TOKEN"},
json={
"webhook_id": "2nenz69l0xbf0m3uu9tfo",
"events": ["message.received"],
},
)
print(response.json())
```
```java Java theme={null}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ReuseWebhook {
public static void main(String[] args) throws Exception {
String body = """
{
"webhook_id": "2nenz69l0xbf0m3uu9tfo",
"events": ["message.received"]
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.zapsterapi.com/v1/wa/instances/SEGUNDA_INSTANCIA/webhooks"))
.header("Authorization", "Bearer SEU_TOKEN")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
```
```ruby Ruby theme={null}
require "net/http"
require "json"
require "uri"
uri = URI("https://api.zapsterapi.com/v1/wa/instances/SEGUNDA_INSTANCIA/webhooks")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer SEU_TOKEN"
request["Content-Type"] = "application/json"
request.body = {
webhook_id: "2nenz69l0xbf0m3uu9tfo",
events: ["message.received"]
}.to_json
puts http.request(request).body
```
#### Editar e remover: o que muda
Como o webhook e a associação são coisas distintas, editar ou remover tem escopos diferentes. Vale conhecer cada operação antes de aplicar mudanças em produção.
| Operação | Endpoint | Escopo | Efeito |
| --------------------- | -------------------------------------------------------------------- | --------- | ---------------------------------------------------- |
| Criar + associar novo | `POST /wa/instances/:id/webhooks` com `url` | Instância | Cria um webhook novo e associa à instância |
| Reusar existente | `POST /wa/instances/:id/webhooks` com `webhook_id` | Instância | Associa um webhook já existente a mais uma instância |
| Editar o webhook | `PATCH /webhooks/:id` (url/name/enabled) | Conta | Propaga para TODAS as instâncias associadas |
| Editar a associação | `PATCH /wa/instances/:id/webhooks/:whId` (events/enabled/test\_mode) | Instância | Muda só a assinatura daquela instância |
| Desassociar | `DELETE /wa/instances/:id/webhooks/:whId` | Instância | Só desliga daquela instância; segue ativo nas demais |
| Excluir | `DELETE /webhooks/:id` | Conta | Remove de TODAS as instâncias |
**Editar o webhook propaga para todo mundo.** Alterar a URL ou o nome pelo endpoint de conta (`PATCH /webhooks/:id`) afeta todas as instâncias associadas. Se você precisa de uma URL diferente para apenas uma instância, crie um webhook novo em vez de editar o existente.
**Desassociar não é o mesmo que excluir.** `DELETE /wa/instances/:id/webhooks/:whId` apenas desliga o webhook daquela instância; ele continua ativo nas outras e na sua conta. Para apagar o webhook de vez, use `DELETE /webhooks/:id`.
#### Como diferenciar a origem no receptor
Cada instância entrega os eventos de forma independente, mesmo quando compartilham o mesmo webhook. Para saber de onde veio cada notificação, use os cabeçalhos HTTP:
* **`X-Instance-ID`**: identifica a instância que gerou o evento (a origem real).
* **`X-Webhook-ID`**: identifica o webhook compartilhado que entregou a notificação.
Como os eventos assinados podem ser diferentes em cada instância, o mesmo webhook pode receber `message.received` de uma instância e `message.sent` de outra. Sempre olhe o `X-Instance-ID` para rotear ou registrar o evento corretamente.
#### Quando compartilhar e quando separar
Compartilhar um webhook faz sentido quando:
* Todas as instâncias entregam para o mesmo sistema (um CRM, uma fila, um endpoint central).
* Você quer trocar a URL de destino em um só lugar no futuro.
* O processamento no receptor já usa o `X-Instance-ID` para separar as origens.
Webhooks distintos por instância fazem mais sentido quando:
* Cada instância pertence a um cliente ou produto diferente, com URL própria.
* Você precisa ligar ou desligar o destino de uma instância sem tocar nas outras.
* Ambientes separados (produção e homologação) não devem se misturar.
#### Boas práticas
* Guarde o `webhook_id` retornado na criação; é ele que você reutiliza nas próximas instâncias.
* Use o `name` do webhook para deixar claro o propósito (por exemplo, "CRM produção").
* No receptor, trate `X-Instance-ID` como a fonte da verdade sobre a origem do evento.
* Antes de editar a URL de um webhook compartilhado, confirme quais instâncias serão afetadas com o endpoint de [listagem de webhooks](/pt-BR/v1/api-reference/webhooks/list-webhooks).
#### Perguntas frequentes
Não pelo endpoint de edição do webhook, que é de conta e propaga para todas as instâncias associadas. Para uma URL exclusiva, crie um webhook novo enviando `url` na criação e associe apenas à instância desejada.
Não. `DELETE /wa/instances/:id/webhooks/:whId` só desliga o webhook daquela instância. Ele continua ativo nas demais e na sua conta. Para apagar de vez, use `DELETE /webhooks/:id`.
Não. Os eventos são definidos por instância, na associação. Uma pode assinar `message.received` e outra `message.sent`, mesmo apontando para o mesmo webhook.
Pelo cabeçalho `X-Instance-ID`, presente em toda notificação. O `X-Webhook-ID` indica o webhook que fez a entrega.
Envie apenas um dos dois. Se ambos forem informados, a Zapster prioriza o `webhook_id` e ignora a `url`.
Para os detalhes de cada endpoint, consulte a referência da API: [criar/associar webhook](/pt-BR/v1/api-reference/instance/create-webhook), [editar associação da instância](/pt-BR/v1/api-reference/instance/update-webhook), [desassociar da instância](/pt-BR/v1/api-reference/instance/delete-webhook), [editar o webhook](/pt-BR/v1/api-reference/webhooks/update-webhook) e [excluir o webhook](/pt-BR/v1/api-reference/webhooks/delete-webhook).
### Tratamento de Falhas e Retentativas
Em um cenário ideal, a aplicação receptora recebe e processa a solicitação do Webhook sem problemas. No entanto, falhas podem ocorrer devido a vários fatores, como indisponibilidade do servidor, problemas de rede, ou erros de processamento.
Para garantir que as notificações importantes não sejam perdidas, implementamos um mecanismo de **retentativa**. Se a aplicação receptora responder com um código de status HTTP maior que 400 (indicando um erro), a aplicação emissora tentará reenviar a notificação do Webhook até **5 vezes**.
#### Detalhes da Retentativa
* **Critério de Falha**: Qualquer resposta com código de status HTTP maior ou igual que 400.
* **Número de Retentativas**: Até 5 tentativas.
* **Intervalo entre Retentativas**: O intervalo entre cada retentativa aumenta progressivamente usando um fator de 2,5. Os intervalos em segundos são os seguintes:
* **1ª Tentativa:** 2,5 segundos (`2.5^1`)
* **2ª Tentativa:** \~6 segundos (`2.5^2`)
* **3ª Tentativa:** \~15 segundos (`2.5^3`)
* **4ª Tentativa:** \~39 segundos (`2.5^4`)
* **5ª Tentativa:** \~97 segundos (`2.5^5`)
Cada intervalo é calculado como `2,5^n`, onde `n` é o número da tentativa.
### Cabeçalhos HTTP Personalizados
Todas as notificações de webhook enviadas pela Zapster API incluem cabeçalhos HTTP personalizados que identificam a origem e o contexto do evento. Esses cabeçalhos são úteis para validação, logging e configuração de regras de firewall.
| Cabeçalho | Tipo | Descrição | Exemplo | Presente em |
| ----------------- | ------ | ---------------------------------- | ------------------ | ------------------------------ |
| `X-Instance-ID` | string | ID da instância que gerou o evento | `inst_abc123` | Todas as notificações |
| `X-Message-ID` | string | ID único da notificação | `msg_xyz789` | Todas as notificações |
| `X-Webhook-ID` | string | ID do webhook registrado | `whk_def456` | Quando webhook está registrado |
| `X-Attempt-Count` | number | Número da tentativa (1-5) | `1` | Todas as notificações |
| `User-Agent` | string | Identificador do emissor | `Zapsterapi/1.2.3` | Todas as notificações |
### Validação e Allowlisting
Você pode utilizar os cabeçalhos HTTP personalizados para validar a origem das notificações recebidas. Como o webhook é entregue via `POST` no seu servidor, os exemplos abaixo mostram o endpoint receptor em cada linguagem (cURL e código de navegador não recebem webhooks, por isso não aparecem aqui):
```javascript JavaScript (server) theme={null}
// Node.js + Express
app.post('/webhook', (req, res) => {
const instanceId = req.headers['x-instance-id']
const messageId = req.headers['x-message-id']
const attemptCount = req.headers['x-attempt-count']
console.log(`Notificação recebida da instância ${instanceId}`)
console.log(`ID da mensagem: ${messageId}, tentativa: ${attemptCount}`)
// Valide a origem antes de processar
if (!instanceId) {
return res.status(400).json({ error: 'Cabeçalho X-Instance-ID ausente' })
}
// Processe o evento
const event = req.body
console.log(`Evento: ${event.type}`, event.data)
res.status(200).json({ received: true })
})
```
```php PHP theme={null}
'Cabeçalho X-Instance-ID ausente']);
exit;
}
// Processe o evento
$event = json_decode(file_get_contents('php://input'), true);
error_log("Evento: {$event['type']}");
http_response_code(200);
echo json_encode(['received' => true]);
```
```go Go theme={null}
package main
import (
"encoding/json"
"log"
"net/http"
)
func webhookHandler(w http.ResponseWriter, r *http.Request) {
instanceID := r.Header.Get("X-Instance-ID")
messageID := r.Header.Get("X-Message-ID")
attemptCount := r.Header.Get("X-Attempt-Count")
log.Printf("Notificação recebida da instância %s", instanceID)
log.Printf("ID da mensagem: %s, tentativa: %s", messageID, attemptCount)
// Valide a origem antes de processar
if instanceID == "" {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "Cabeçalho X-Instance-ID ausente"})
return
}
// Processe o evento
var event map[string]any
json.NewDecoder(r.Body).Decode(&event)
log.Printf("Evento: %v", event["type"])
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]bool{"received": true})
}
```
```python Python theme={null}
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.post("/webhook")
def webhook():
instance_id = request.headers.get("X-Instance-ID")
message_id = request.headers.get("X-Message-ID")
attempt_count = request.headers.get("X-Attempt-Count")
print(f"Notificação recebida da instância {instance_id}")
print(f"ID da mensagem: {message_id}, tentativa: {attempt_count}")
# Valide a origem antes de processar
if not instance_id:
return jsonify(error="Cabeçalho X-Instance-ID ausente"), 400
# Processe o evento
event = request.get_json()
print(f"Evento: {event['type']}", event["data"])
return jsonify(received=True), 200
```
```java Java theme={null}
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
public class WebhookController {
@PostMapping("/webhook")
public ResponseEntity> receive(
@RequestHeader(value = "X-Instance-ID", required = false) String instanceId,
@RequestHeader(value = "X-Message-ID", required = false) String messageId,
@RequestHeader(value = "X-Attempt-Count", required = false) String attemptCount,
@RequestBody Map event) {
System.out.printf("Notificação recebida da instância %s%n", instanceId);
System.out.printf("ID da mensagem: %s, tentativa: %s%n", messageId, attemptCount);
// Valide a origem antes de processar
if (instanceId == null) {
return ResponseEntity.badRequest().body(Map.of("error", "Cabeçalho X-Instance-ID ausente"));
}
// Processe o evento
System.out.println("Evento: " + event.get("type"));
return ResponseEntity.ok(Map.of("received", true));
}
}
```
```ruby Ruby theme={null}
require "sinatra"
require "json"
post "/webhook" do
instance_id = request.env["HTTP_X_INSTANCE_ID"]
message_id = request.env["HTTP_X_MESSAGE_ID"]
attempt_count = request.env["HTTP_X_ATTEMPT_COUNT"]
puts "Notificação recebida da instância #{instance_id}"
puts "ID da mensagem: #{message_id}, tentativa: #{attempt_count}"
# Valide a origem antes de processar
halt 400, { error: "Cabeçalho X-Instance-ID ausente" }.to_json if instance_id.nil?
# Processe o evento
event = JSON.parse(request.body.read)
puts "Evento: #{event['type']}"
content_type :json
{ received: true }.to_json
end
```
**Allowlisting em WAF/Firewall:** Se você utiliza um Web Application Firewall (WAF) ou regras de firewall, configure-o para aceitar requisições `POST` que contenham os cabeçalhos `X-Instance-ID`, `X-Message-ID`, `X-Attempt-Count` e `User-Agent` com o prefixo `Zapsterapi/`.
# Saúde do número: boas práticas e restrições
Source: https://developer.zapsterapi.com/pt-BR/v1/guides/best-practices
Como manter seu número saudável e evitar restrições no WhatsApp
O WhatsApp usa algoritmos para detectar comportamento automatizado. Quando o sistema entende que um número está enviando mensagens de forma não natural, ele pode restringir ou banir o número. As boas práticas abaixo ajudam a manter seu número funcionando por mais tempo.
A lógica é simples: quanto mais o seu uso se parecer com o de uma pessoa real, menor o risco de restrição.
Se você caiu aqui procurando por que seu WhatsApp Business bloqueou ou como evitar banimento no WhatsApp, comece pelo modelo mental do WhatsApp Web na próxima seção. É o que mais reduz banimento na prática.
Estas recomendações se aplicam principalmente a instâncias não oficiais (QR code). Instâncias WABA (oficiais) seguem as políticas da Meta diretamente e têm risco muito menor de banimento. Ainda assim, boas práticas de conteúdo e opt-in valem para os dois tipos.
## Perfil completo
Preencha o perfil do WhatsApp Business com o máximo de informações possíveis:
* Foto de perfil (logotipo ou foto profissional)
* Nome comercial
* Descrição do negócio
* Endereço
* Horário de funcionamento
* E-mail de contato
* Site
Um perfil completo aumenta a confiança do algoritmo no número. Perfis vazios ou incompletos são um sinal de conta descartável.
Ative o PIN de segurança (verificação em duas etapas) no WhatsApp. Além de proteger contra clonagem, indica para o sistema que é uma conta legítima que se preocupa com segurança.
## Pense como o WhatsApp Web: múltiplas conexões por número
A maior parte dos problemas de banimento não vem da API. Vem de tentar fazer um único número se comportar como dezenas de pessoas ao mesmo tempo. Para evitar isso, vale entender como o próprio WhatsApp foi desenhado.
O WhatsApp permite vincular **até 4 dispositivos** a um mesmo número, além do celular principal. É o mecanismo do WhatsApp Web e do WhatsApp Desktop: você abre o mesmo número no notebook do trabalho, no computador de casa e no tablet, e todos conversam pela mesma conta. Isso é uso legítimo e esperado.
Cada conexão dessas é uma **instância** do ponto de vista da rede do WhatsApp. Quando você cria uma instância na Zapster, está ocupando um desses espaços de dispositivo vinculado.
O problema aparece quando uma única instância tenta atender muita gente. Para o algoritmo, uma instância respondendo 400 conversas por dia parece **uma pessoa sobrecarregada de forma impossível**, e isso é um sinal clássico de automação abusiva. Ninguém digita para 400 contatos sozinho num dia sem parar.
A boa prática é distribuir. Abra de 2 a 4 instâncias do mesmo número na Zapster e divida as conversas entre elas. Cada instância passa a funcionar como um "agente" virtual:
* ❌ **1 instância** atendendo sozinha 400 conversas/dia → parece um robô.
* ✅ **4 instâncias** do mesmo número atendendo 100 conversas/dia cada → parece uma equipe de 4 atendentes humanos usando o WhatsApp Web.
O volume total é o mesmo. O que muda é a distribuição: em vez de um humano impossível, o padrão fica parecido com vários humanos plausíveis.
Para automatizar esse balanceamento, está em desenvolvimento o **Smart Sending Mode** com pool de instâncias, que distribui as conversas entre as instâncias do mesmo número de forma automática. Enquanto ele não chega, você consegue o mesmo efeito criando as instâncias manualmente e roteando no seu código. Veja [Instâncias](/pt-BR/v1/concepts/instances) para entender os tipos de conexão.
## O erro mais comum: conectar e já sair enviando
Este é o erro que mais gera restrição em número novo, e quase ninguém enxerga como erro: criar a instância, ler o QR code e, no mesmo minuto, disparar mensagens para uma lista de contatos que nunca falaram com você. Do seu ponto de vista, o número "está funcionando". Do ponto de vista do WhatsApp, um número que acabou de aparecer já saiu abordando dezenas de estranhos, que é exatamente o padrão de uma conta criada para spam.
### Responder é seguro, iniciar conversa nova é onde mora o risco
O WhatsApp trata duas coisas de formas muito diferentes:
* **Responder quem te procurou** — alguém te mandou mensagem e você respondeu. Risco baixíssimo. É o uso mais natural que existe.
* **Iniciar conversa com contato novo** (o "reach-out") — você aborda alguém que nunca te escreveu. É aqui que o algoritmo presta atenção, porque é o que um spammer faz.
Quando um número está "sob suspeita" — conexão recém-criada, histórico de restrição, ou um volume estranho de conversas novas em pouco tempo — o WhatsApp aplica uma **trava temporal**: o número continua conseguindo responder conversas **já abertas**, mas **iniciar conversa nova fica bloqueado** por um período. Esse período vai de algumas horas a **vários dias** — restrições de 7 ou 14 dias são comuns.
Essa trava costuma atingir **apenas a conexão da API** (o dispositivo vinculado), não o celular. Por isso você vê uma cena confusa: o número manda mensagem normalmente pelo aplicativo no celular, mas a instância falha ao enviar. **Não é bug da API** — é a restrição agindo especificamente sobre a conexão que estava disparando para contatos novos.
### Aquecimento (warmup): os primeiros dias definem o resto
Número novo é como conta nova em qualquer lugar: precisa construir reputação antes de pedir confiança. Trate as primeiras horas e dias como um período de aquecimento.
**Nas primeiras horas / primeiro dia:**
* Priorize **responder** mensagens que chegam (inbound). Todo início de conversa que parte do outro lado conta a seu favor.
* Evite iniciar conversas frias em lote. Se precisar iniciar alguma, que sejam poucas e espaçadas.
* Nada de **criar grupo, adicionar participantes em massa ou disparo em lote** — são as ações de maior risco logo após conectar.
**Ao longo da primeira semana:**
* Suba o volume **gradualmente**, não de zero para o volume-alvo de uma vez.
* Mantenha uma **proporção saudável** entre conversas que você recebe e conversas que você inicia. Um número que só inicia e nunca recebe é suspeito; um número que conversa nas duas direções parece real.
A tática mais eficaz de aquecimento é fazer o número **receber** conversas reais antes de começar a disparar. Coloque o número na bio, no site, num anúncio de clique-para-WhatsApp, no rodapé do e-mail. Cada pessoa que te procura primeiro gera exatamente o tipo de interação (inbound → resposta) que amadurece o número mais rápido e com menos risco.
### Reconexão não é a mesma coisa que número novo
Importante não confundir os dois casos:
* **Só reiniciou a instância** (reconectou o mesmo número que já vinha operando saudável) → **não precisa reaquecer do zero**. O histórico do número continua valendo; siga o ritmo normal.
* **Número novo** ou que **acabou de sair de uma restrição** → aí sim o cuidado de aquecimento vale integralmente. Número recém-saído de restrição volta "sensível" e uma recaída no mesmo padrão costuma trazer uma trava mais longa.
## Peça para ser adicionado nos contatos
Sempre que possível, peça ao destinatário que adicione o número da instância na agenda de contatos do celular. Quando alguém salva seu número, o WhatsApp entende que existe um relacionamento real entre vocês.
Isso eleva o "score" do número e reduz a chance de que suas mensagens sejam marcadas como spam.
Na prática, você pode incluir uma frase como:
> "Para garantir que nossas mensagens cheguem sempre, salve este número nos seus contatos."
## Cadência entre mensagens
Não envie mensagens em rajada. O WhatsApp detecta envios em massa com facilidade.
**Recomendações de intervalo:**
| Cenário | Intervalo mínimo | Ideal |
| ------------------------------- | ---------------- | ---------------- |
| Envio para lista de contatos | 30 segundos | 45 a 60 segundos |
| Follow-up após interação | 10 segundos | 20 a 30 segundos |
| Respostas automáticas (chatbot) | 3 a 5 segundos | 5 a 10 segundos |
Quanto maior o intervalo, melhor. Se você precisa enviar para 100 contatos, espere pelo menos 30 segundos entre cada envio. Isso significa que o lote leva cerca de 50 minutos pra finalizar. Parece lento, mas é o que mantém o número vivo.
Enviar mais de 1 mensagem por segundo para destinatários diferentes é um dos comportamentos que mais gera restrição. Evite sempre.
## Janela humana: 1 conversa por vez por instância
Repare em como uma pessoa real usa o WhatsApp Web. Ela foca em um contato, troca algumas mensagens, resolve aquele assunto e só então passa para o próximo. Ela não responde 5 conversas em paralelo, palavra por palavra, ao mesmo tempo. Esse foco sequencial é a assinatura de um humano de verdade.
A boa prática é reproduzir isso por instância: trate uma conversa por vez, dentro de uma "janela" ativa. Um padrão simples que funciona bem é o **debounce por contato**: uma janela de cerca de 1 minuto dedicada a um contato antes de seguir para o próximo.
Quando outro contato escreve no meio dessa janela, você não atende em paralelo. Responde algo curto como "já te respondo, um instante" e coloca aquele contato na fila.
O fluxo, em palavras:
1. Chega uma mensagem.
2. Já existe uma janela ativa nessa instância?
* **Sim** → enfileira o contato e responde com uma mensagem de espera.
* **Não** → abre a janela para esse contato e responde normalmente.
3. Ao fim da janela (ou quando o assunto se resolve), pega o próximo da fila.
O ponto importante: isso **reduz banimento sem reduzir o volume total**. Você continua atendendo a mesma quantidade de gente. Só muda a distribuição no tempo, o que evita o padrão de um robô falando com todo mundo ao mesmo tempo.
O **Smart Sending Mode** (em desenvolvimento) vai cuidar dessa fila e do debounce por contato de forma nativa, junto com o pool de instâncias.
## Presença em paralelo é veneno
Antes de enviar uma mensagem, use o [endpoint de atualização de presença](/pt-BR/v1/api-reference/utils/presence-update) para simular o comportamento humano:
```bash theme={null}
# Simular "Digitando..." por 5 segundos antes de enviar
curl -X PATCH https://api.zapsterapi.com/v1/wa/instances/SUA_INSTANCIA/presence \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"recipient": "5511999999999",
"status": "typing",
"duration_strategy": "maximum_duration",
"max_duration": 5
}'
```
O destinatário vai ver "Digitando..." por 5 segundos antes de receber a mensagem. Isso faz o envio parecer mais natural, tanto para quem recebe quanto para o algoritmo.
Para áudios, use `"status": "recording"` para mostrar "Gravando áudio...".
Você também pode usar `"duration_strategy": "until_next_message"` para manter o status ativo até que a mensagem seja enviada de fato. Isso funciona bem quando o tempo de processamento varia (como em respostas de IA).
### Por que paralelizar presença entrega o bot
Aqui está o erro que mais derruba número: disparar `presence: typing` (ou `recording`) para dois destinatários ao mesmo tempo na mesma instância. Pense no que isso representa: uma única pessoa "Digitando..." para o João e para a Maria no mesmo segundo. Nenhum humano digita para duas pessoas simultaneamente. É um sinal de robô que não tem como disfarçar.
A solução é **serializar a presença por instância**: processar a fila um por vez, com a sua presença, e só disparar o próximo quando o anterior terminar.
**Anti-padrão** (presença em paralelo, todos ao mesmo tempo):
```javascript theme={null}
// ❌ NÃO faça isso: dispara "Digitando..." para todos de uma vez
await Promise.all(
contacts.map(async (contact) => {
await setPresence(contact.phone, 'typing'); // todos "digitando" juntos
await sendMessage(contact.phone, contact.text);
}),
);
```
**Correto** (uma conversa por vez, presença serializada):
```javascript theme={null}
// ✅ Serializa: só começa a "digitar" para o próximo quando o atual termina
async function setPresence(phone, status) {
await fetch(`https://api.zapsterapi.com/v1/wa/instances/SUA_INSTANCIA/presence`, {
method: 'PATCH',
headers: {
Authorization: 'Bearer SEU_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: phone,
status,
// mantém "Digitando..." até a mensagem sair de fato
duration_strategy: 'until_next_message',
}),
});
}
for (const contact of contacts) {
await setPresence(contact.phone, 'typing');
await sendMessage(contact.phone, contact.text);
await new Promise((r) => setTimeout(r, 45000)); // intervalo entre conversas
}
```
O `duration_strategy: 'until_next_message'` é um aliado aqui: ele segura o "Digitando..." pelo tempo que o seu processamento levar e o encerra no envio, sem você ter que cronometrar nada. Combinado com a serialização, a presença fica naturalmente alinhada com uma conversa de cada vez.
## Use o dispositivo original regularmente
A Meta desconecta dispositivos vinculados que ficam inativos por mais de 14 dias. Isso significa que se ninguém abrir o aplicativo do WhatsApp no celular original durante 14 dias, a conexão da instância pode cair.
**Recomendação:** pelo menos uma vez por semana, abra o WhatsApp no celular onde o número está registrado. Não precisa fazer nada complexo:
* Abrir o app
* Navegar pelas conversas
* Enviar uma mensagem para alguém (pode ser para você mesmo em outro número)
* Verificar se tem atualizações pendentes do app
Esse uso periódico mantém o vínculo ativo e evita desconexões inesperadas.
Referência: [Sobre os dispositivos associados no WhatsApp Business](https://faq.whatsapp.com/647349420360876/?locale=pt_PT)
## Personalize as mensagens
Mensagens idênticas enviadas para muitas pessoas são um dos sinais mais fortes de automação. O WhatsApp compara o conteúdo das mensagens enviadas por um número e detecta padrões repetitivos.
**Ruim:**
```
Olá! Temos uma promoção especial para você. Acesse nosso site.
```
(mesma mensagem para 200 pessoas)
**Bom:**
```
Olá João! Vi que você se interessou pelo plano Pro na semana passada.
Ainda está avaliando? Posso te ajudar com alguma dúvida.
```
(mensagem personalizada com nome e contexto)
Na API da Zapster, você monta a mensagem dinamicamente no seu código antes de enviar. Cada request ao `POST /v1/wa/messages` pode ter um texto diferente:
```javascript theme={null}
const contacts = [
{ phone: '5511999999999', name: 'João', interest: 'plano Pro' },
{ phone: '5511888888888', name: 'Maria', interest: 'integração N8n' },
];
for (const contact of contacts) {
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
method: 'POST',
headers: {
'Authorization': 'Bearer SEU_TOKEN',
'X-Instance-ID': 'SUA_INSTANCIA',
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: contact.phone,
text: `Olá ${contact.name}! Vi que você se interessou por ${contact.interest}. Posso te ajudar?`,
}),
});
// Esperar entre envios
await new Promise(r => setTimeout(r, 45000)); // 45 segundos
}
```
## Opt-in e opt-out
Envie mensagens apenas para quem deu consentimento. Pessoas que não esperam receber suas mensagens vão denunciar como spam, e isso derruba o score do número rapidamente.
**Opt-in:** Tenha alguma forma de consentimento antes de enviar. Pode ser um formulário no site, uma confirmação por e-mail, ou uma interação prévia no próprio WhatsApp.
**Opt-out:** Sempre dê a opção de parar de receber mensagens. Inclua algo como:
> "Se não quiser mais receber nossas mensagens, responda SAIR."
E respeite quando alguém pedir para sair. Continuar enviando para quem pediu para parar é o caminho mais rápido para restrição.
## Higienização de contatos
Antes de enviar para uma lista, verifique se os números são válidos:
* Use o [endpoint de verificação de destinatário](/pt-BR/v1/api-reference/utils/fetch-recipient) para checar se o número tem WhatsApp
* Remova números que não respondem há meses
* Remova números que pediram opt-out
* Remova duplicatas
Enviar para números inválidos ou inativos gera falhas silenciosas que o WhatsApp contabiliza negativamente.
## Horários de envio
Enviar mensagens de madrugada ou em horários estranhos gera mais denúncias. Prefira horários comerciais:
| Horário | Recomendação |
| ---------------- | ---------------------------------------------------- |
| 8h às 12h | Bom |
| 12h às 14h | Aceitável (horário de almoço, taxa de leitura menor) |
| 14h às 18h | Bom |
| 18h às 20h | Aceitável |
| 20h às 8h | Evitar |
| Finais de semana | Evitar para mensagens comerciais |
Com o recurso de [mensagens agendadas](/pt-BR/v1/concepts/scheduled-messages), você pode preparar o envio fora do horário e deixar a Zapster disparar no momento certo.
## O que fazer se receber restrição
Se o número for restrito temporariamente:
1. **Pare imediatamente** de enviar mensagens automatizadas
2. **Espere** o período de restrição passar. A duração varia bastante: pode ser de algumas horas a **7 ou 14 dias**, dependendo do histórico do número e do tipo de comportamento que disparou a trava (restrições de conversa nova costumam ser as mais longas)
3. **Volte devagar** com volume reduzido e intervalos maiores — e, se o número era novo ou reincidente, retome o aquecimento (veja *"O erro mais comum: conectar e já sair enviando"*) priorizando responder inbound antes de iniciar conversas
4. **Revise** suas práticas antes de retomar o volume anterior
Se o número for banido permanentemente:
1. O número não pode ser recuperado na maioria dos casos
2. Considere migrar para uma [instância WABA (oficial)](/pt-BR/v1/guides/waba-vs-unofficial) que não tem esse risco
3. Se precisar de um novo número não oficial, comece com volume baixo e siga todas as práticas acima desde o início
## Auto-auditoria do workflow (regra 80/20)
Antes de concluir que "a API está banindo meu número", audite o seu próprio fluxo. Na prática, a causa quase sempre está no desenho do workflow, não na ferramenta.
Vale aplicar a regra 80/20 aqui: 80% do trabalho é planejamento e análise do fluxo, 20% é a execução do código. Quem inverte essa proporção (joga código em produção e só depois investiga) costuma queimar números no processo.
Passe o seu fluxo por estas perguntas:
* Quantas instâncias eu mantenho por número? Estou usando o modelo do WhatsApp Web (até 4 dispositivos) ou sobrecarregando uma só?
* Meu agente/bot responde várias conversas em paralelo? Ou trata uma de cada vez?
* Tenho controle de concorrência (fila, lock, debounce por contato)? Ou tudo dispara ao mesmo tempo?
* Onde eu envio `presence: typing`? Está serializado por instância ou paralelo?
* Qual o intervalo médio entre envios para o **mesmo** contato?
* Meu volume diário bate com "X atendentes humanos trabalhando das 9h às 18h"? Ou só faz sentido se fosse um robô?
Esse tipo de auditoria é uma ótima tarefa para delegar a um LLM (Claude, ChatGPT). Descreva o seu workflow atual (quantas instâncias, como o bot enfileira, onde dispara presença) e peça para o modelo apontar onde o padrão se afasta de um humano usando o WhatsApp Web.
Vale o posicionamento honesto: **você é dono do desenho do seu sistema**. A Zapster entrega as ferramentas (instâncias, presença, agendamento, fila), não a estratégia de como você as combina. Um workflow bem desenhado mantém o número saudável com as mesmas ferramentas que um workflow mal desenhado usa para queimá-lo.
## Checklist rápido
Use esta lista antes de iniciar um envio em volume:
* [ ] O perfil do WhatsApp está completo (foto, descrição, endereço)?
* [ ] Se a instância é nova (ou acabou de sair de restrição), ela já foi aquecida antes de disparar em volume?
* [ ] Nas primeiras horas, priorizei **responder** inbound em vez de iniciar conversas frias?
* [ ] Evitei criar grupo, adicionar em massa e disparo em lote logo após conectar?
* [ ] Os destinatários deram consentimento para receber mensagens?
* [ ] As mensagens estão personalizadas com nome ou contexto?
* [ ] O intervalo entre envios é de pelo menos 30 segundos?
* [ ] Estou usando o endpoint de presença ("Digitando...")?
* [ ] Tenho múltiplas instâncias por número para distribuir as conversas?
* [ ] A presença ("Digitando...") está serializada (uma por vez), nunca em paralelo?
* [ ] Tenho debounce por contato (uma janela por vez, sem atender tudo simultaneamente)?
* [ ] Os números da lista são válidos e ativos?
* [ ] O horário de envio é dentro do horário comercial?
* [ ] Tem opção de opt-out na mensagem?
* [ ] Usei o app do WhatsApp no celular original esta semana?
## Referências
* [Sobre os dispositivos associados no WhatsApp Business](https://faq.whatsapp.com/647349420360876/?locale=pt_PT)
* [Como vincular vários dispositivos a um número (recurso multidispositivo)](https://faq.whatsapp.com/378279804439436/?locale=pt_BR)
* [Sobre contas banidas no WhatsApp](https://faq.whatsapp.com/361005896189245?helpref=faq_content)
* [Sobre restrições temporárias no WhatsApp](https://faq.whatsapp.com/465883178708358?helpref=faq_content)
* [Sobre mensagens de segurança no WhatsApp](https://faq.whatsapp.com/717472490411581/?helpref=faq_content)
# Conectando uma instância WABA
Source: https://developer.zapsterapi.com/pt-BR/v1/guides/connect-waba-instance
Como criar e conectar uma instância usando a API oficial do WhatsApp
Existem duas formas de conectar uma instância WABA na Zapster: pelo dashboard (Embedded Signup) ou pela API (token manual). O Embedded Signup é o método recomendado para a maioria dos usuários.
## Método 1: Embedded Signup (recomendado)
O Embedded Signup é o jeito mais rápido de conectar. Você faz login na sua conta do Facebook, seleciona o número e pronto.
No dashboard da Zapster, clique em **Criar instância** e selecione a opção **WhatsApp Business (Oficial)**.
Clique no botão de conexão. Uma janela do Facebook vai abrir pedindo login.
Escolha a conta WhatsApp Business que deseja conectar. Se você não tem uma, pode criar durante o processo.
Escolha o número que será conectado à instância. O número precisa estar verificado na Meta.
Confirme a autorização. A Zapster vai configurar tudo automaticamente: webhook, credenciais, e a instância já estará pronta para uso.
Depois de conectar, você já pode enviar mensagens pelo mesmo endpoint `POST /v1/wa/messages` que usa para instâncias não oficiais. Não precisa mudar nada na integração.
## Método 2: Token manual (avançado)
Se você já tem um System User Token da Meta e prefere criar a instância via API, pode usar o endpoint de criação diretamente.
### O que você vai precisar
Antes de começar, você precisa de três informações do [Meta Business Manager](https://business.facebook.com/settings). Abaixo mostramos onde encontrar cada uma.
O System User Token precisa ter as permissões `whatsapp_business_management` e `whatsapp_business_messaging`. Sem elas, a criação vai falhar.
#### System User Token
O token é gerado na área de Usuários do sistema dentro das Configurações do Meta Business Manager.
1. No menu lateral, clique em **Usuários** e depois em **Usuários do sistema**
2. Selecione o usuário que vai se conectar (ou crie um novo clicando em **Adicionar**)
3. Clique no usuário e gere um novo token com as permissões necessárias
#### Phone Number ID
O Phone Number ID é o identificador interno que a Meta usa para o seu número. Não é o número de telefone em si.
1. No menu lateral, clique em **Contas de WhatsApp**
2. Selecione a conta que contém o número desejado
3. Clique no número de telefone para abrir os detalhes. O **Phone Number ID** aparece no painel lateral direito, abaixo do nome de exibição
#### WABA ID
O WABA ID é o identificador da conta WhatsApp Business como um todo (não do número individual).
1. No menu lateral, clique em **Contas de WhatsApp**
2. Selecione a conta desejada
3. Clique na aba **Phone Numbers** (ou **Números de telefone**). O **WABA ID** aparece no topo da página, ao lado do nome da conta
### Criando a instância via API
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/instances \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"connection_type": "waba",
"name": "Meu WhatsApp Oficial",
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255"
}
}'
```
```javascript JavaScript theme={null}
const response = await fetch('https://api.zapsterapi.com/v1/wa/instances', {
method: 'POST',
headers: {
'Authorization': 'Bearer SEU_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
connection_type: 'waba',
name: 'Meu WhatsApp Oficial',
waba: {
access_token: 'EAAxxxxxxx...',
phone_number_id: '1016102021584086',
waba_id: '419378847918255',
},
}),
});
const instance = await response.json();
console.log(instance);
```
Se tudo der certo, a resposta inclui a instância criada com status `connected`. A Zapster registra o webhook na Meta automaticamente.
#### Usando o seu próprio app Meta (BYO-app)
Se o seu System User Token pertence ao **seu próprio app Meta** (e não ao app da Zapster), os webhooks de entrada são assinados com o **App Secret do seu app**. Para que a Zapster verifique a autenticidade desses eventos, informe os campos opcionais abaixo no objeto `waba`:
* `app_secret`: App Secret do seu app Meta. Quando informado, a assinatura HMAC (`X-Hub-Signature-256`) dos webhooks é validada contra ele, garantindo a verificação completa de autenticidade dos eventos. É armazenado **criptografado em repouso** (AES-256), igual ao `access_token`.
* `app_id`: ID do seu app Meta. Usado apenas para identificação/auditoria — não é segredo e não participa da validação de assinatura.
* `webhook_verify_token`: token de verificação do webhook. Se omitido, a Zapster gera um aleatório. Também armazenado criptografado em repouso.
Sempre que o seu System User Token pertencer ao seu próprio app Meta, informe o `app_secret`. Como os webhooks são assinados com o segredo do seu app, é ele que permite à Zapster fazer a verificação completa da assinatura HMAC e garantir a autenticidade de cada evento recebido.
## Segurança dos dados
Seus dados sensíveis são protegidos em todas as etapas:
* **Token de acesso**: armazenado com criptografia AES-256-CBC, o mesmo padrão usado por bancos e fintechs. O token original nunca é salvo em texto puro.
* **Sem exposição**: o token não aparece em logs, webhooks, respostas da API nem no dashboard. Nem a equipe da Zapster tem acesso ao valor original.
* **Webhooks da Meta**: todos os eventos recebidos da Meta são validados por assinatura HMAC-SHA256 antes de serem processados. Eventos com assinatura inválida são descartados.
Se você precisar trocar o token (por exemplo, se o anterior expirou), crie uma nova instância WABA. O token antigo é removido junto com a instância.
## O que muda no uso da API?
Nada. Depois que a instância WABA está criada, os endpoints são os mesmos:
* `POST /v1/wa/messages` para enviar mensagens
* `DELETE /v1/wa/messages/:id` para cancelar agendadas
* `GET /v1/wa/messages` para listar histórico
A Zapster detecta automaticamente o tipo da instância e roteia para a Cloud API da Meta ou para a conexão não oficial.
A única diferença é que instâncias WABA suportam **templates de mensagem** (campo `template` no body) e **não suportam envio para grupos**.
## Próximos passos
* [Entenda as diferenças entre WABA e não oficial](/pt-BR/v1/guides/waba-vs-unofficial)
* [Cobrança de mensagens no WhatsApp oficial (WABA)](/pt-BR/v1/concepts/message-pricing)
* [Veja como enviar mensagens](/pt-BR/v1/api-reference/messages/sending)
* [Configure webhooks para receber eventos](/pt-BR/v1/webhooks/setting-up-webhook)
* [Erro ao criar template de autenticação (code 10, subcode 2388185)](/pt-BR/v1/guides/meta-auth-template-error)
# Mensagem com botões
Source: https://developer.zapsterapi.com/pt-BR/v1/guides/messages-with-buttons
Aprenda como enviar mensagens com botões interativos usando a API do ZapsterAPI
## Pré-requisitos
Para utilizar a funcionalidade de botões em mensagens, é necessário que:
1. **Você esteja inscrito no programa beta** - [Acesse aqui](https://app.zapsterapi.com/settings/beta-program) para se inscrever.
2. **A opção "Mensagens com botões" esteja ativa** - Vá em [Recursos em beta](https://app.zapsterapi.com/settings/beta-features) e ative o recurso.
A funcionalidade de botões está disponível apenas para usuários inscritos no programa beta. Caso não tenha acesso, entre em contato com nossa equipe de suporte.
**OBSERVAÇÃO:** Atualmente, ao enviar os três tipos de botões simultaneamente, o WhatsApp Web gera um erro, que também ocorre ao usar a própria API da Meta. Uma alternativa é enviar apenas os botões CALL, URL e COPYABLE juntos, e sempre enviar o botão REPLY separadamente.
## Visão Geral
Os botões permitem criar mensagens interativas no WhatsApp, oferecendo aos usuários opções de resposta rápida. Você pode adicionar até 3 botões por mensagem, cada um com diferentes tipos de ação.
## Tipos de Botões
Permite que o usuário responda com um texto pré-definido.
```json theme={null}
{
"label": "Sim, quero!",
"type": "reply"
}
```
Inicia uma chamada para um número de telefone específico.
```json theme={null}
{
"label": "Ligar Agora",
"type": "call",
"phone_number": "+5511999999999"
}
```
Abre um link no navegador do usuário.
```json theme={null}
{
"label": "Ver Produto",
"type": "url",
"url": "https://exemplo.com/produto"
}
```
Permite que o usuário copie um texto específico.
```json theme={null}
{
"label": "Copiar Código",
"type": "copyable",
"copy_code": "PROMO2024"
}
```
## Suporte por tipo de conexão
O suporte a botões varia conforme o tipo de conexão da instância. Em instâncias oficiais (WABA), os botões são enviados como mensagens interativas da Cloud API, que seguem regras próprias da Meta. A assinatura da requisição é a mesma nos dois tipos de conexão.
A coluna "Oficial (WABA)" abaixo descreve **mensagens de sessão**: mensagens interativas enviadas dentro da janela de conversa de 24 horas. **Templates** têm registro e aprovação separados na Meta e seguem regras próprias. Botões de ligação e de copiar código existem em templates, mesmo sem suporte em mensagem de sessão.
| Recurso | Não oficial (QR code) | Oficial (WABA) |
| -------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Botões `reply` | Até 3 | Até 3 |
| Botão `url` | Sim | Sim, exatamente 1 por mensagem |
| Botão `call` | Sim | Não em mensagem de sessão. Use um template com botão de ligação (`PHONE_NUMBER`) |
| Botão `copyable` | Sim | Não em mensagem de sessão. Disponível via template de Marketing ou Authentication |
| Misturar `url` com `reply` | Sim | Não |
| Mais de 1 botão `url` | Sim | Não |
| Mídia junto com botões | Sim | Sim. Imagem, vídeo ou documento viram o cabeçalho da mensagem interativa. Áudio não é suportado |
| `caption` da mídia | Vira a legenda da mídia | Vira o corpo da mensagem interativa, com prioridade sobre `text` quando os dois são enviados. Só `text` também vira o corpo |
Em instâncias WABA, combinações não suportadas retornam erro `400` imediato com os códigos `waba_feature_not_supported` ou `waba_invalid_button_combination`. Nenhum campo é descartado silenciosamente. Veja exemplos completos de envio em [Enviar mensagens com WABA](/pt-BR/v1/guides/send-waba-messages) e entenda a [cobrança de mensagens no WhatsApp oficial (WABA)](/pt-BR/v1/concepts/message-pricing).
## Modos de Botões
Os modos de botões (`buttons_mode`) definem como sua mensagem será enviada no WhatsApp. Existem dois modos disponíveis:
### Modo Padrão (`auto`)
* Usado para botões de resposta rápida simples
* Ideal quando você quer apenas receber respostas de texto do usuário
* O WhatsApp exibe os botões de forma básica
### Modo Interativo (`interactive`)
* Usado para botões mais avançados como ligações, links e textos copiáveis
* Permite uma experiência mais rica com diferentes tipos de ação
* O WhatsApp exibe os botões com mais destaque visual
### Como o Modo é Escolhido Automaticamente
Se você não especificar o `buttons_mode`, o sistema escolhe automaticamente:
* **Modo Interativo**: Será usado quando pelo menos um botão for do tipo `call`, `url` ou `copyable`
* **Modo Padrão**: Será usado quando todos os botões forem do tipo `reply`
**Dica importante**: Mesmo com todos os botões sendo `reply`, você pode forçar o modo interativo definindo `"buttons_mode": "interactive"` para ter uma apresentação visual melhor.
### Parâmetros dos Botões
Array de botões. Máximo 3 botões permitidos.
Modo de exibição dos botões. Valores aceitos: `auto` ou `interactive`.
### Estrutura de um Botão
Texto do botão. Máximo 20 caracteres.
Tipo do botão. Valores aceitos: `reply`, `call`, `url`, `copyable`.
ID único do botão. Máximo 256 caracteres.
Número para botão de ligação. Deve estar no formato internacional.
URL para botão de link. Deve ser uma URL válida.
Texto para copiar. Aceita qualquer texto.
```bash Botões de Resposta Simples theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-d '{
"recipient": "5511999999999",
"text": "Gostaria de receber nossas ofertas exclusivas?",
"buttons": [
{
"label": "Sim, quero!",
"type": "reply"
},
{
"label": "Não, obrigado",
"type": "reply"
}
],
"buttons_mode": "interactive"
}'
```
```bash Botões com Diferentes Tipos theme={null}
curl -X POST https://api.zapsterapi.com/messages/send \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-d '{
"recipient": "5511999999999",
"text": "Como posso te ajudar hoje?",
"buttons": [
{
"label": "Falar com Atendente",
"type": "call",
"phone_number": "+5511888888888"
},
{
"label": "Ver Catálogo",
"type": "url",
"url": "https://minhaloja.com/catalogo"
},
{
"label": "Copiar Cupom",
"type": "copyable",
"copy_code": "DESCONTO10"
}
],
"buttons_mode": "auto"
}'
```
```bash Botões com Media theme={null}
curl -X POST https://api.zapsterapi.com/messages/send \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-d '{
"recipient": "5511999999999",
"text": "Confira nosso novo produto!",
"media": {
"url": "https://exemplo.com/imagem.jpg",
"caption": "Produto incrível com desconto especial"
},
"buttons": [
{
"label": "Comprar Agora",
"type": "url",
"url": "https://minhaloja.com/comprar"
},
{
"label": "Ver Detalhes",
"type": "url",
"url": "https://minhaloja.com/detalhes"
}
],
"buttons_mode": "interactive"
}'
```
# Erro ao criar template de autenticação no WhatsApp (code 10, subcode 2388185)
Source: https://developer.zapsterapi.com/pt-BR/v1/guides/meta-auth-template-error
Por que a Meta recusa o template de autenticação/OTP com "Esta conta do WhatsApp Business não tem permissão para criar um modelo de mensagem" (code 10, error_subcode 2388185), como diagnosticar e como liberar a categoria AUTHENTICATION.
Ao criar um template de **categoria AUTHENTICATION** (OTP, o botão de "copiar código") no WhatsApp Manager ou pela Graph API, a Meta pode recusar com um erro genérico e enganoso: **"Esta conta do WhatsApp Business não tem permissão para criar um modelo de mensagem"**. Em inglês, o mesmo erro aparece como *"WhatsApp Business account doesn't have permission to create message template"* e, na API, como *"Application does not have permission for this action"* com `code: 10` e `error_subcode: 2388185`.
A mensagem sugere um problema na sua conta ou no conteúdo do template, mas quase sempre não é nenhum dos dois. A categoria AUTHENTICATION tem um requisito de elegibilidade próprio que UTILITY e MARKETING não têm. Este guia mostra como confirmar o diagnóstico e como destravar a categoria.
## Qual é o erro exato?
O mesmo erro aparece de duas formas, dependendo de onde você tenta criar o template.
**No WhatsApp Manager (UI):**
> Não é possível criar o modelo de mensagem
>
> Esta conta do WhatsApp Business não tem permissão para criar um modelo de mensagem.
**Na Graph API** (`POST /{WABA_ID}/message_templates` com `category: "AUTHENTICATION"`):
```json theme={null}
{
"error": {
"message": "Application does not have permission for this action",
"type": "OAuthException",
"code": 10,
"error_subcode": 2388185,
"is_transient": false,
"fbtrace_id": "AbCdEf123..."
}
}
```
A UI apenas reexibe esse erro da API. O `is_transient: false` confirma que repetir a chamada não adianta, e o `fbtrace_id` é o identificador que a Meta pede quando você abre um ticket de suporte.
Termos em inglês para busca: *whatsapp authentication template not allowed*, *code 10 authentication template*, *error\_subcode 2388185*, *can create utility but not authentication template whatsapp*. É o mesmo problema descrito aqui.
## Por que isso acontece?
Porque a categoria **AUTHENTICATION é restrita** e tem um gate de elegibilidade separado. Além do que UTILITY e MARKETING já exigem, um template de autenticação só é liberado quando a conta cumpre dois requisitos:
1. **Verificação de negócio por um dos caminhos oficiais de escala** (as "scaling paths" da Meta): verificação de negócio direta (Business Verification), verificação via parceiro Meta (partner-led) ou o programa Quality Messaging.
2. **Volume/tier mínimo de mensageria.** Contas em tier inicial não conseguem enviar mensagens de autenticação. A Meta cita, como referência, algo em torno de **2.000 mensagens entregues a usuários únicos em 30 dias** (fora da janela de 24h, com templates de boa qualidade).
Não existe um botão de "habilitar autenticação" nem um opt-in de termos. O caminho é verificar o negócio e escalar o tier. Desde o fim de 2025, a Meta passou a bloquear já na criação do template, em vez de bloquear só no envio.
Vale reforçar o que **não** é a causa:
* **Não é o conteúdo do template.** O mesmo texto, corpo e botão em outra categoria passa; só AUTHENTICATION é recusada.
* **Não é um bug ou estado da sua conta específica.** O erro reproduz em contas WABA diferentes, sempre só na categoria AUTHENTICATION.
* **Não é restrição do Brasil.** O gate vale para qualquer país; o `authentication_international` que aparece em alguns lugares é uma faixa de tarifação, não um bloqueio.
O sinal que fecha o diagnóstico é simples: **templates de UTILITY e MARKETING são criados normalmente na mesma conta, e só o de AUTHENTICATION falha.**
## Como diagnosticar?
A forma mais direta de isolar o gate é criar o mesmo template em duas categorias e comparar o retorno. Se `category: "UTILITY"` passa e `category: "AUTHENTICATION"` volta com `code: 10 / error_subcode: 2388185`, o problema é a categoria, não o conteúdo nem a conta.
Os comandos abaixo falam direto com a Graph API da Meta e exigem um **token de acesso da WABA**. Se você integra pela Zapster, na maioria das contas esse token fica do nosso lado (você usa a API da Zapster sem manipular o token da WABA), então provavelmente não conseguirá rodar estes `curl` por conta própria. Nesse caso, [fale com o suporte](https://wa.me/5587999079455?text=Olá,%20quero%20verificar%20a%20elegibilidade%20da%20minha%20conta%20para%20templates%20de%20autenticação%20no%20WhatsApp) que fazemos a checagem de elegibilidade da sua conta para você. Os exemplos a seguir servem para quem tem acesso direto ao token.
Este `POST` **cria o template de verdade** se a conta tiver permissão. Use apenas para diagnóstico manual pontual e apague o template de teste depois. Para uma checagem sem efeito colateral, prefira os sinais somente-leitura descritos mais abaixo.
```bash theme={null}
curl -X POST "https://graph.facebook.com/v25.0/{WABA_ID}/message_templates" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "otp_test",
"language": "pt_BR",
"category": "AUTHENTICATION",
"message_send_ttl_seconds": 60,
"components": [
{ "type": "BODY", "add_security_recommendation": true },
{ "type": "FOOTER", "code_expiration_minutes": 5 },
{ "type": "BUTTONS", "buttons": [{ "type": "OTP", "otp_type": "COPY_CODE" }] }
]
}'
```
Troque `category` para `"UTILITY"` (com um corpo simples, sem botão OTP) e rode de novo. Se UTILITY cria e AUTHENTICATION devolve `2388185`, o gate está confirmado.
### Como checar a elegibilidade sem criar nada?
Nenhum endpoint devolve um booleano definitivo de "pode criar autenticação", mas há sinais somente-leitura que funcionam como proxy forte:
* **Tier de mensagens (o sinal mais limpo).** É a mesma escada que a UI da Meta mostra: **250 → 2.000 → 10.000 → 100.000 → ilimitado**. Tier 250 (inicial) costuma significar autenticação bloqueada; a partir de 2.000 a conta muito provavelmente já é elegível. Não existe um tier de "1.000" (esse número, comum em blogs de parceiros, está desatualizado).
* **`health_status`.** `GET /{PHONE_NUMBER_ID}?fields=health_status` retorna `can_send_message` por entidade (`PHONE_NUMBER`, `WABA`, `BUSINESS`, `APP`) como `AVAILABLE`, `LIMITED` ou `BLOCKED`. Um `BUSINESS` em `LIMITED` ou `BLOCKED` costuma indicar verificação de negócio pendente.
* **Templates de autenticação já existentes.** `GET /{WABA_ID}/message_templates?category=AUTHENTICATION&fields=name,status`. Se já existe algum, a conta consegue criar. A lista vazia não prova o contrário, então só vale como sinal quando há resultado.
## Como resolver?
O caminho é destravar a categoria AUTHENTICATION cumprindo os requisitos oficiais da Meta. Não há atalho de configuração.
1. **Conclua a verificação de negócio** por um dos três caminhos de escala: Business Verification direta, verificação via parceiro Meta ou o programa Quality Messaging. Sem verificação de negócio, a autenticação continua bloqueada.
2. **Suba o tier de mensagens.** O gate real é o volume. Enquanto a conta estiver no tier inicial (250), a categoria tende a permanecer bloqueada. A referência da Meta gira em torno de 2.000 mensagens entregues a usuários únicos em 30 dias, com boa qualidade e fora da janela de 24h.
3. **Aguarde a liberação automática.** Quando a conta se torna elegível, a categoria costuma liberar em cerca de **6 horas**, sem nenhuma ação manual.
Prazos e limites são definidos pela Meta e podem mudar. Este guia descreve o comportamento observado, não uma garantia da Meta.
Se você já concluiu a verificação de negócio, está em um tier acima do inicial e o erro **persiste**, aí sim vale abrir um ticket com o suporte da Meta. Inclua o `error_subcode: 2388185` e o `fbtrace_id` da resposta da API, que é o que agiliza a análise do lado deles.
Enquanto a categoria AUTHENTICATION não libera, um stopgap comum é enviar o OTP por outro canal (SMS ou e-mail) e migrar para o template de autenticação quando a conta ficar elegível.
## O que NÃO resolve o erro?
Duas tentativas parecem óbvias e não funcionam:
* **Editar o conteúdo do template.** Como o bloqueio é de categoria, e não de conteúdo, mudar o texto, o corpo ou o botão não muda o resultado. O erro `2388185` continua.
* **Entregar o OTP como template UTILITY com botão de copiar código.** É proibido e tende a ser rejeitado. O botão `OTP` (copy-code / one-tap) é exclusivo de AUTHENTICATION. O botão `COPY_CODE` que existe em UTILITY e MARKETING é o de **cupom** (copiar código de desconto), não de OTP, e a Meta recusa a combinação com `code: 100 / error_subcode: 2388180`. A própria documentação de categorização é explícita: *"Only authentication templates can be used to send a one-time passcode for identity verification. Marketing and utility templates cannot be used for this purpose."*
Mesmo colocando o código inline no corpo, sem botão, o classificador de conteúdo da Meta reconhece o padrão de OTP e marca o template como `REJECTED`. Nenhum ajuste de texto contorna isso. O único caminho definitivo é habilitar a categoria AUTHENTICATION.
## Como a Zapster ajuda?
A Zapster traduz esse erro opaco da Meta. Na tela de gestão de templates, o `code: 10 / error_subcode: 2388185` vira uma mensagem clara: explica que templates de autenticação exigem verificação de negócio concluída e volume mínimo de mensagens, e que UTILITY e MARKETING não têm essa exigência. Você entende o motivo real sem precisar decifrar o retorno cru da API.
A liberação da categoria depende inteiramente da Meta (verificação de negócio e tier), então nem a Zapster nem qualquer outra plataforma consegue garantir aprovação ou prazo. O que fazemos é deixar o diagnóstico claro e apoiar você no processo, inclusive verificando a elegibilidade da sua conta quando você não tem acesso direto ao token da WABA. Se estiver travado nesse erro, [fale com o suporte](https://wa.me/5587999079455?text=Olá,%20estou%20com%20o%20erro%20de%20template%20de%20autenticação%20\(subcode%202388185\)%20no%20WhatsApp).
## Perguntas frequentes
Porque só a categoria AUTHENTICATION tem gate de elegibilidade próprio (verificação de negócio e tier de mensagens). UTILITY e MARKETING não têm essa exigência, então criam normalmente na mesma conta. É o sinal clássico de que o bloqueio é de categoria, não de conteúdo nem da conta.
É o código específico da Graph API para "a conta não tem permissão para criar template de autenticação". Vem junto com `code: 10` e `type: OAuthException`. Na UI, o mesmo erro aparece como "Esta conta do WhatsApp Business não tem permissão para criar um modelo de mensagem".
Não. O gate da categoria AUTHENTICATION vale para qualquer país. O `authentication_international` que aparece em alguns painéis é uma faixa de tarifação, não um bloqueio de criação.
Não. O bloqueio é de categoria, não de conteúdo. Mudar texto, corpo ou botão mantém o mesmo `error_subcode: 2388185`.
Não. O botão OTP é exclusivo de AUTHENTICATION, e a documentação da Meta proíbe usar templates de utilidade ou marketing para enviar código de verificação. Mesmo com o código inline no corpo, o template acaba rejeitado. O único caminho é habilitar a categoria AUTHENTICATION.
Quando a conta cumpre a verificação de negócio e sobe o tier, a categoria costuma liberar em cerca de 6 horas, de forma automática. Prazos são definidos pela Meta e podem mudar.
Cheque o tier de mensagens (250 → 2.000 → 10.000 → 100.000 → ilimitado): no tier inicial a autenticação tende a permanecer bloqueada. Se a verificação está concluída e o tier já subiu, abra um ticket com o suporte da Meta informando o `error_subcode: 2388185` e o `fbtrace_id` da resposta.
## Fontes oficiais da Meta
* [Limites de mensagens (messaging limits)](https://developers.facebook.com/docs/whatsapp/messaging-limits), a escada de tiers que funciona como gate real.
* [Categorização de templates (template categorization)](https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates/template-categorization), com a regra de que só templates de autenticação enviam OTP.
* [Thread da comunidade Meta sobre o erro 2388185](https://developers.facebook.com/community/threads/1372007877817645/), com vários relatos do mesmo `code: 10 / error_subcode: 2388185`.
## Próximos passos
* [Conectando uma instância WABA](/pt-BR/v1/guides/connect-waba-instance)
* [Enviando mensagens WABA](/pt-BR/v1/guides/send-waba-messages)
* [Número 555 da Meta e o erro 131037](/pt-BR/v1/numero-555-meta)
# Como agendar sua primeira mensagem
Source: https://developer.zapsterapi.com/pt-BR/v1/guides/schedule-first-message
Tutorial passo a passo para enviar uma mensagem agendada via API
Neste guia você vai agendar uma mensagem de WhatsApp para ser enviada em uma data futura. Leva menos de 5 minutos.
## O que você vai precisar
* Uma conta na Zapster API (se não tem, [crie aqui](https://app.zapsterapi.com/signup))
* Uma instância conectada (WABA ou não oficial)
* Seu token de autenticação
## 1. Agendar uma mensagem
O campo `send_at` é o que transforma um envio comum em um agendamento. Passe a data e hora no formato ISO 8601 com fuso horário.
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer SEU_TOKEN" \
-H "X-Instance-ID: SUA_INSTANCIA" \
-H "Content-Type: application/json" \
-d '{
"recipient": "5511999999999",
"text": "Olá! Seu boleto vence amanhã.",
"send_at": "2026-03-30T09:00:00-03:00"
}'
```
```javascript JavaScript (fetch) theme={null}
const response = await fetch('https://api.zapsterapi.com/v1/wa/messages', {
method: 'POST',
headers: {
'Authorization': 'Bearer SEU_TOKEN',
'X-Instance-ID': 'SUA_INSTANCIA',
'Content-Type': 'application/json',
},
body: JSON.stringify({
recipient: '5511999999999',
text: 'Olá! Seu boleto vence amanhã.',
send_at: '2026-03-30T09:00:00-03:00',
}),
});
const data = await response.json();
console.log(data);
// { message_id: "msg_k7m2nxp9q4", status: "scheduled", send_at: "2026-03-30T12:00:00.000Z" }
```
```python Python (requests) theme={null}
import requests
response = requests.post(
'https://api.zapsterapi.com/v1/wa/messages',
headers={
'Authorization': 'Bearer SEU_TOKEN',
'X-Instance-ID': 'SUA_INSTANCIA',
'Content-Type': 'application/json',
},
json={
'recipient': '5511999999999',
'text': 'Olá! Seu boleto vence amanhã.',
'send_at': '2026-03-30T09:00:00-03:00',
},
)
print(response.json())
# { "message_id": "msg_k7m2nxp9q4", "status": "scheduled", "send_at": "2026-03-30T12:00:00.000Z" }
```
Se a resposta voltar com status **201**, a mensagem foi agendada. Guarde o `message_id` porque é com ele que você cancela ou consulta o status depois. Repare que o `send_at` na resposta vem em UTC, então `-03:00` vira `+3 horas` no horário retornado.
## 2. Verificar o status
Para conferir se a mensagem ainda está na fila, use a listagem com filtros de data e status.
```bash cURL theme={null}
curl "https://api.zapsterapi.com/v1/wa/messages?from=2026-03-30T00:00:00Z&to=2026-03-30T23:59:59Z&status=scheduled" \
-H "Authorization: Bearer SEU_TOKEN"
```
```javascript JavaScript theme={null}
const response = await fetch(
'https://api.zapsterapi.com/v1/wa/messages?from=2026-03-30T00:00:00Z&to=2026-03-30T23:59:59Z&status=scheduled',
{ headers: { 'Authorization': 'Bearer SEU_TOKEN' } }
);
const { data } = await response.json();
console.log(data);
```
Você vai ver a mensagem com status `scheduled`. Depois que o horário agendado passar, o status muda para `sent` (ou `failed` se algo deu errado no envio).
## 3. Cancelar se precisar
Mudou de ideia? Cancele com um DELETE passando o `message_id`.
```bash cURL theme={null}
curl -X DELETE https://api.zapsterapi.com/v1/wa/messages/msg_k7m2nxp9q4 \
-H "Authorization: Bearer SEU_TOKEN"
```
```javascript JavaScript theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages/msg_k7m2nxp9q4', {
method: 'DELETE',
headers: { 'Authorization': 'Bearer SEU_TOKEN' },
});
// { id: "msg_k7m2nxp9q4", status: "canceled" }
```
Só dá para cancelar mensagens que ainda não foram enviadas. Se a mensagem já saiu, o DELETE retorna erro **422**.
## Perguntas frequentes
Sim. O mínimo é 1 minuto no futuro. Se você passar uma data que já passou ou que está a menos de 1 minuto de distância, a API retorna erro de validação.
O sistema tenta enviar 3 vezes com intervalo crescente entre as tentativas. Se todas falharem, a mensagem vai para o status `failed` com o motivo do erro no campo `errors`.
Quando a instância voltar, ela não reenvia automaticamente mensagens que já falharam. Você precisaria agendar novamente.
Não. Se você precisa alterar o texto, o destinatário ou o horário, cancele a mensagem existente com `DELETE /v1/wa/messages/:id` e crie uma nova.
Consulte o histórico com `GET /v1/wa/messages` e filtre por `status=failed`. O campo `errors` na resposta traz o código e a descrição do problema.
Motivos comuns:
* A instância estava desconectada no momento do envio
* A janela de 24 horas do WABA expirou (erro 131047)
* O template não foi encontrado (erro 132000)
* O número do destinatário não existe ou está bloqueado
Depende do seu plano:
| Plano | Agendadas simultâneas | Antecedência máxima |
| ---------- | --------------------- | ------------------- |
| Essential | 10 | 7 dias |
| Pro | 500 | 1 ano |
| Enterprise | 10.000 | Sem limite |
Se atingir o limite, a API retorna erro `max_scheduled_messages_reached`. Você pode cancelar mensagens pendentes para liberar espaço.
Esses campos dependem das configurações de privacidade do destinatário no WhatsApp. Se a pessoa desativou a confirmação de leitura, `read_at` nunca será preenchido. Se houve algum problema de rede, `delivered_at` pode demorar para aparecer.
O status da mensagem continua como `sent` independente desses campos.
Sim, os dois tipos. Não precisa mudar nada na configuração. A API detecta automaticamente o tipo da instância e envia da forma correta.
## Próximos passos
* [Veja todos os filtros disponíveis na listagem](/pt-BR/v1/api-reference/messages/list-messages)
* [Entenda o ciclo de vida das mensagens](/pt-BR/v1/concepts/message-lifecycle)
* [Limites e planos](/pt-BR/v1/concepts/scheduled-messages#limites-por-plano)
# Como enviar mensagens para BSUID (WhatsApp oficial)
Source: https://developer.zapsterapi.com/pt-BR/v1/guides/send-to-bsuid
Envie mensagens para um BSUID (Business-Scoped User ID) pela API oficial (WABA) quando o telefone do usuário está oculto. Exemplos em cURL, Node.js, Python e Go.
Este guia mostra como enviar mensagens para um **BSUID** (Business-Scoped User ID), o identificador sem telefone que a Meta usa no WhatsApp oficial (WABA). O envio usa o mesmo endpoint `POST /v1/wa/messages`, trocando apenas o valor do campo `recipient`.
## O que é um BSUID
BSUID é a sigla de **Business-Scoped User ID**. É um identificador que a Meta gera para representar um usuário do WhatsApp sem expor o número de telefone dele.
Ele existe por causa do rollout de **nomes de usuário (usernames)** do WhatsApp, previsto para 2026. Quando um usuário escolhe conversar por username, ou opta por manter o número oculto, a sua empresa deixa de receber o telefone e passa a receber um BSUID no lugar. Esse identificador permite continuar a conversa normalmente, só que o telefone real nunca é revelado.
O BSUID é **escopado por portfolio de negócio** (business portfolio). O mesmo usuário aparece com um BSUID diferente para cada portfolio, então um BSUID só serve dentro do portfolio que o recebeu (veja [Limitações e erros](#limitações-e-erros)).
O BSUID é **exclusivo do canal oficial (WABA)**. No canal não oficial (QR code), o identificador análogo é o **LID**, que segue pelo fluxo normal de JID. Um BSUID enviado para uma instância não oficial é rejeitado com o erro `waba_bsuid_requires_waba`.
## Formato
O BSUID tem duas formas:
| Tipo | Formato | Exemplo |
| -------------------------------------------------- | ---------------------------------------- | ----------------------------- |
| **Padrão** | código do país + `.` + identificador | `US.13491208655302741918` |
| **Parent** (negócios gerenciados entre portfolios) | código do país + `.ENT.` + identificador | `US.ENT.11815799212886844830` |
Regras do formato:
* O prefixo é o **código de país ISO 3166 alpha-2** (duas letras, como `US`, `BR`, `PT`).
* Em seguida vem um ponto (`.`).
* BSUIDs **parent** inserem o segmento `ENT` (também seguido de ponto) entre o código do país e o identificador.
* O identificador final tem até 128 caracteres alfanuméricos e é **opaco**: trate-o como uma string sem significado interno, sem alterar.
## Como enviar
O envio é idêntico ao de uma mensagem WABA comum. Você usa o mesmo endpoint `POST /v1/wa/messages` e a mesma assinatura de requisição. A única diferença é que o campo `recipient` recebe o BSUID em vez de um número de telefone. A Zapster detecta o formato de BSUID automaticamente e monta o payload da Cloud API da Meta com o campo correto.
Antes de começar, você precisa de uma [instância WABA conectada](/pt-BR/v1/guides/connect-waba-instance). Em todos os exemplos, troque `YOUR_API_TOKEN` pelo seu token de API e `YOUR_INSTANCE_ID` pelo ID da instância WABA. O BSUID de exemplo (`US.13491208655302741918`) representa o destinatário; use o BSUID real que chegou no seu webhook.
Como acontece com qualquer mensagem livre em WABA, texto, mídia e botões só são entregues dentro da **janela de conversa de 24 horas**. Fora da janela, use um **template** aprovado (veja mais abaixo). O detalhamento completo está em [Enviar mensagens com WABA](/pt-BR/v1/guides/send-waba-messages).
### Texto simples
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "US.13491208655302741918",
"text": "Olá! Seu pedido foi confirmado."
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
const response = await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
recipient: 'US.13491208655302741918',
text: 'Olá! Seu pedido foi confirmado.',
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
console.log(response.data.message_id)
```
```javascript Node.js (fetch) theme={null}
const response = await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
recipient: 'US.13491208655302741918',
text: 'Olá! Seu pedido foi confirmado.',
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
const data = await response.json()
console.log(data.message_id)
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "US.13491208655302741918",
"text": "Olá! Seu pedido foi confirmado.",
},
)
print(response.json()["message_id"])
```
```go Go theme={null}
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "US.13491208655302741918",
"text": "Olá! Seu pedido foi confirmado."
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
data, _ := io.ReadAll(res.Body)
fmt.Println(string(data))
}
```
### Mídia (imagem, vídeo ou documento)
Envie a mídia por URL pública ou base64 no campo `media`. O tipo é detectado automaticamente a partir do arquivo.
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "US.13491208655302741918",
"media": {
"url": "https://exemplo.com/imagem.jpg",
"caption": "Confira o catálogo de julho"
}
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
media: {
caption: 'Confira o catálogo de julho',
url: 'https://exemplo.com/imagem.jpg',
},
recipient: 'US.13491208655302741918',
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
```
```javascript Node.js (fetch) theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
media: {
caption: 'Confira o catálogo de julho',
url: 'https://exemplo.com/imagem.jpg',
},
recipient: 'US.13491208655302741918',
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
```
```python Python theme={null}
import requests
requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "US.13491208655302741918",
"media": {
"url": "https://exemplo.com/imagem.jpg",
"caption": "Confira o catálogo de julho",
},
},
)
```
```go Go theme={null}
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "US.13491208655302741918",
"media": {
"url": "https://exemplo.com/imagem.jpg",
"caption": "Confira o catálogo de julho"
}
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
res.Body.Close()
}
```
### Botões interativos
As regras de botão em WABA valem também para BSUID: até 3 botões `reply`, ou exatamente 1 botão `url`, sem misturar os dois tipos. A matriz completa está em [Mensagem com botões](/pt-BR/v1/guides/messages-with-buttons).
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "US.13491208655302741918",
"text": "Deseja confirmar o agendamento de amanhã?",
"buttons": [
{ "id": "confirm", "label": "Confirmar", "type": "reply" },
{ "id": "reschedule", "label": "Remarcar", "type": "reply" },
{ "id": "cancel", "label": "Cancelar", "type": "reply" }
]
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
buttons: [
{ id: 'confirm', label: 'Confirmar', type: 'reply' },
{ id: 'reschedule', label: 'Remarcar', type: 'reply' },
{ id: 'cancel', label: 'Cancelar', type: 'reply' },
],
recipient: 'US.13491208655302741918',
text: 'Deseja confirmar o agendamento de amanhã?',
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
```
```javascript Node.js (fetch) theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
buttons: [
{ id: 'confirm', label: 'Confirmar', type: 'reply' },
{ id: 'reschedule', label: 'Remarcar', type: 'reply' },
{ id: 'cancel', label: 'Cancelar', type: 'reply' },
],
recipient: 'US.13491208655302741918',
text: 'Deseja confirmar o agendamento de amanhã?',
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
```
```python Python theme={null}
import requests
requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "US.13491208655302741918",
"text": "Deseja confirmar o agendamento de amanhã?",
"buttons": [
{"id": "confirm", "label": "Confirmar", "type": "reply"},
{"id": "reschedule", "label": "Remarcar", "type": "reply"},
{"id": "cancel", "label": "Cancelar", "type": "reply"},
],
},
)
```
```go Go theme={null}
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "US.13491208655302741918",
"text": "Deseja confirmar o agendamento de amanhã?",
"buttons": [
{ "id": "confirm", "label": "Confirmar", "type": "reply" },
{ "id": "reschedule", "label": "Remarcar", "type": "reply" },
{ "id": "cancel", "label": "Cancelar", "type": "reply" }
]
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
res.Body.Close()
}
```
### Template (fora da janela de 24h)
Templates funcionam com BSUID, com uma exceção importante: **templates de autenticação one-tap, zero-tap e copy-code não são suportados** para BSUID e são rejeitados pela Meta com o erro `131062` (veja [Limitações e erros](#limitações-e-erros)). Templates de utility e marketing, e templates de autenticação com código por texto, funcionam normalmente.
O objeto `template` é um espelho do formato da Meta. Detalhes de `components`, variáveis posicionais e nomeadas estão em [Enviar mensagens com WABA](/pt-BR/v1/guides/send-waba-messages#template-fora-da-janela-de-24h).
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "US.13491208655302741918",
"template": {
"name": "confirmacao_pedido",
"language": "pt_BR",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "João" }
]
}
]
}
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
recipient: 'US.13491208655302741918',
template: {
components: [
{
parameters: [{ text: 'João', type: 'text' }],
type: 'body',
},
],
language: 'pt_BR',
name: 'confirmacao_pedido',
},
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
```
```javascript Node.js (fetch) theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
recipient: 'US.13491208655302741918',
template: {
components: [
{
parameters: [{ text: 'João', type: 'text' }],
type: 'body',
},
],
language: 'pt_BR',
name: 'confirmacao_pedido',
},
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
```
```python Python theme={null}
import requests
requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "US.13491208655302741918",
"template": {
"name": "confirmacao_pedido",
"language": "pt_BR",
"components": [
{
"type": "body",
"parameters": [{"type": "text", "text": "João"}],
}
],
},
},
)
```
```go Go theme={null}
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "US.13491208655302741918",
"template": {
"name": "confirmacao_pedido",
"language": "pt_BR",
"components": [
{
"type": "body",
"parameters": [{ "type": "text", "text": "João" }]
}
]
}
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
res.Body.Close()
}
```
## De onde vem o BSUID
Você não inventa um BSUID: ele **chega até você pelos webhooks de entrada**. A Zapster normaliza todo webhook antes de entregar, então você nunca lida com os campos crus da Meta. O contato sempre chega no mesmo formato, com `id`, `phone_number` e `bsuid`.
Em um evento `message.received`, o contato do cliente vem em `sender` (e, em conversas de um para um, também em `recipient`, que espelha o `sender`). O campo `id` é o identificador primário e segue uma regra simples: **telefone quando existe, BSUID quando não existe**.
* **Telefone visível:** `phone_number` traz o número e `bsuid` traz o BSUID (a Meta costuma enviar os dois). O `id` aponta para o `phone_number`.
* **Telefone oculto (usuário com privacidade):** `phone_number` é `null`, `bsuid` traz o BSUID e o `id` assume o valor do BSUID.
O envio do BSUID não é garantido pela Meta em todo recebimento WABA. Mesmo com o telefone visível, o campo `bsuid` pode chegar como `null`. Use sempre o `id` do contato como identificador primário e guarde o BSUID quando ele vier preenchido.
O campo `lid` não aparece no contato de uma instância WABA: ele é o identificador análogo do canal não oficial e fica omitido no canal oficial, já que LID e BSUID se excluem por canal (veja [WABA vs não oficial](/pt-BR/v1/guides/waba-vs-unofficial) para a comparação completa entre os dois canais).
Veja o `message.received` nos dois cenários. Em ambos, o `id` do contato é o valor que você usa no `recipient` para responder dentro da janela de 24 horas:
`phone_number` é `null`, `bsuid` traz o BSUID e o `id` assume o valor do BSUID.
```json theme={null}
{
"id": "V1StGXR8_Z5jdHi6B-myT",
"type": "message.received",
"created_at": "2026-07-25T14:22:07.000Z",
"data": {
"id": "wamid.HBgLMTU1NTU1NTU1NTUVAgARGBI5RjZ...",
"type": "text",
"sender": {
"id": "US.13491208655302741918",
"phone_number": null,
"name": "Maria",
"bsuid": "US.13491208655302741918",
"profile_picture": null,
"type": "chat"
},
"recipient": {
"id": "US.13491208655302741918",
"phone_number": null,
"name": "Maria",
"bsuid": "US.13491208655302741918",
"profile_picture": null,
"type": "chat"
},
"content": { "text": "Oi, cadê meu pedido?" },
"sent_at": "2026-07-25T14:22:07.000Z"
}
}
```
`phone_number` e `bsuid` vêm preenchidos, e o `id` aponta para o `phone_number`.
```json theme={null}
{
"id": "V1StGXR8_Z5jdHi6B-myT",
"type": "message.received",
"created_at": "2026-07-25T14:22:07.000Z",
"data": {
"id": "wamid.HBgLMTU1NTU1NTU1NTUVAgARGBI5RjZ...",
"type": "text",
"sender": {
"id": "5511999999999",
"phone_number": "5511999999999",
"name": "Maria",
"bsuid": "US.13491208655302741918",
"profile_picture": null,
"type": "chat"
},
"recipient": {
"id": "5511999999999",
"phone_number": "5511999999999",
"name": "Maria",
"bsuid": "US.13491208655302741918",
"profile_picture": null,
"type": "chat"
},
"content": { "text": "Oi, cadê meu pedido?" },
"sent_at": "2026-07-25T14:22:07.000Z"
}
}
```
Nos eventos de status (`message.sent`, `message.delivered`, `message.read`), o contato do cliente vem em `recipient` no mesmo formato, então o BSUID aparece em `recipient.bsuid` (e no `recipient.id` quando o telefone está oculto).
O fluxo prático é: o cliente manda mensagem para o seu número, você recebe o webhook, lê o `id` do contato (que já é o BSUID quando o telefone está oculto), guarda esse valor e usa ele no `recipient` do `POST /v1/wa/messages` para responder dentro da janela de 24 horas. Veja [Eventos disponíveis](/pt-BR/v1/webhooks/available-events) para o catálogo de webhooks.
## Limitações e erros
Quando o payload usa um recurso que a Cloud API não suporta com BSUID, a Zapster rejeita a requisição na hora com um erro `400`, sem descartar nada silenciosamente.
| Código | Quando acontece | Como resolver |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `waba_bsuid_requires_waba` | BSUID no `recipient` de uma instância **não oficial** | BSUID só funciona no canal oficial (WABA). Para instâncias não oficiais, use o número de telefone (o análogo do BSUID no não oficial é o LID) |
| `waba_bsuid_message_type_not_supported` | Template de autenticação **one-tap**, **zero-tap** ou **copy-code** enviado para um BSUID (erro `131062` da Meta) | Esses templates de autenticação exigem um número de telefone. Use um destinatário com telefone, ou escolha outro tipo de mensagem |
Além disso, lembre do escopo por portfolio:
* **O BSUID é escopado por portfolio de negócio.** Um BSUID recebido em um portfolio **não** vale em outro. Se você tentar enviar para um BSUID a partir de uma instância ligada a outro portfolio, a Meta rejeita o envio. Sempre responda usando a mesma instância (mesmo portfolio) que recebeu aquele BSUID.
## Boas práticas
* **Aceite e normalize as maiúsculas do prefixo.** O código do país e o segmento `ENT` são estruturais e canonicamente maiúsculos (`US`, `US.ENT.`). A Zapster normaliza um BSUID digitado como `us.ent.` para a forma que a Meta emite, então um valor em minúsculo no `recipient` também funciona.
* **Nunca altere o identificador.** A parte depois do prefixo é opaca e pode ser sensível a maiúsculas e minúsculas. Preserve-a byte a byte: não faça uppercase, trim de zeros ou qualquer transformação.
* **Guarde o BSUID canônico para correlação.** Armazene o BSUID na forma canônica (prefixo maiúsculo, identificador intacto) para casar com o valor que chega nos webhooks e manter o histórico do contato consistente. Vale lembrar que, quando o usuário troca de número, a Meta gera um novo BSUID para ele, então trate o BSUID como identificador do contato naquele portfolio, não como algo eterno.
## Próximos passos
* [Enviar mensagens com WABA](/pt-BR/v1/guides/send-waba-messages) para o guia completo de texto, mídia, botões e templates
* [WABA vs não oficial](/pt-BR/v1/guides/waba-vs-unofficial) para entender a diferença entre BSUID (oficial) e LID (não oficial)
* [Eventos disponíveis](/pt-BR/v1/webhooks/available-events) para receber o BSUID nos webhooks de entrada
# Enviar mensagens com WABA
Source: https://developer.zapsterapi.com/pt-BR/v1/guides/send-waba-messages
Como enviar texto, mídia, botões e templates por uma instância oficial (WABA) usando a API da Zapster
Este guia mostra como enviar mensagens por uma instância oficial (WABA). O endpoint é o mesmo das instâncias não oficiais, `POST /v1/wa/messages`, com a mesma assinatura de requisição. A Zapster converte o seu payload para o formato da Cloud API da Meta automaticamente.
## Antes de começar
1. Você precisa de uma [instância WABA conectada](/pt-BR/v1/guides/connect-waba-instance).
2. Mensagens livres (texto, mídia, botões) só são entregues dentro da **janela de conversa de 24 horas**, que abre quando o cliente manda mensagem para o seu número. Fora da janela, use um **template** aprovado pela Meta.
3. Instâncias WABA não enviam para grupos. Se precisar de grupos, use uma instância não oficial. Veja o comparativo em [WABA vs não oficial](/pt-BR/v1/guides/waba-vs-unofficial).
Em todos os exemplos abaixo, troque `YOUR_API_TOKEN` pelo seu token de API e `YOUR_INSTANCE_ID` pelo ID da instância WABA.
As mensagens livres (texto, mídia e botões) enviadas por uma instância oficial são gratuitas até **30 de setembro de 2026**. A partir de **1 de outubro de 2026**, a Meta passa a cobrar por elas. Entenda o que muda em [Cobrança de mensagens no WhatsApp oficial (WABA)](/pt-BR/v1/concepts/message-pricing).
## Texto simples
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "5511999999999",
"text": "Olá! Seu pedido foi confirmado."
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
const response = await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
recipient: '5511999999999',
text: 'Olá! Seu pedido foi confirmado.',
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
console.log(response.data.message_id)
```
```javascript Node.js (fetch) theme={null}
const response = await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
recipient: '5511999999999',
text: 'Olá! Seu pedido foi confirmado.',
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
const data = await response.json()
console.log(data.message_id)
```
```python Python theme={null}
import requests
response = requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "5511999999999",
"text": "Olá! Seu pedido foi confirmado.",
},
)
print(response.json()["message_id"])
```
```go Go theme={null}
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "5511999999999",
"text": "Olá! Seu pedido foi confirmado."
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
data, _ := io.ReadAll(res.Body)
fmt.Println(string(data))
}
```
## Mídia (imagem, vídeo ou documento)
Envie a mídia por URL pública ou base64 no campo `media`. O tipo (imagem, vídeo, documento) é detectado automaticamente a partir do arquivo. Para documentos, você pode informar `fileName` para controlar o nome exibido no WhatsApp.
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "5511999999999",
"media": {
"url": "https://exemplo.com/imagem.jpg",
"caption": "Confira o catálogo de julho"
}
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
media: {
caption: 'Confira o catálogo de julho',
url: 'https://exemplo.com/imagem.jpg',
},
recipient: '5511999999999',
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
```
```javascript Node.js (fetch) theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
media: {
caption: 'Confira o catálogo de julho',
url: 'https://exemplo.com/imagem.jpg',
},
recipient: '5511999999999',
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
```
```python Python theme={null}
import requests
requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "5511999999999",
"media": {
"url": "https://exemplo.com/imagem.jpg",
"caption": "Confira o catálogo de julho",
},
},
)
```
```go Go theme={null}
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "5511999999999",
"media": {
"url": "https://exemplo.com/imagem.jpg",
"caption": "Confira o catálogo de julho"
}
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
res.Body.Close()
}
```
Para enviar vídeo ou documento, basta trocar a URL. Exemplo de documento com nome de arquivo:
```json theme={null}
{
"recipient": "5511999999999",
"media": {
"url": "https://exemplo.com/contrato.pdf",
"fileName": "contrato.pdf",
"caption": "Segue o contrato para assinatura"
}
}
```
## Botões interativos
Em WABA, botões viram mensagens interativas da Cloud API e seguem as regras da Meta: até 3 botões `reply`, ou exatamente 1 botão `url`, sem misturar os dois tipos. Botões `call` e `copyable` não existem em mensagem de sessão (veja [Erros comuns](#erros-comuns)). A matriz completa está em [Mensagem com botões](/pt-BR/v1/guides/messages-with-buttons).
Quando você envia `media` junto com botões, a mídia vira o cabeçalho da mensagem interativa (imagem, vídeo ou documento; áudio não é suportado). Se enviar `media.caption` e `text` juntos, o `caption` tem prioridade e vira o corpo da mensagem.
### Botões de resposta rápida (reply) com imagem
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "5511999999999",
"text": "Deseja confirmar o agendamento de amanhã?",
"media": {
"url": "https://exemplo.com/clinica.jpg"
},
"buttons": [
{ "id": "confirm", "label": "Confirmar", "type": "reply" },
{ "id": "reschedule", "label": "Remarcar", "type": "reply" },
{ "id": "cancel", "label": "Cancelar", "type": "reply" }
]
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
buttons: [
{ id: 'confirm', label: 'Confirmar', type: 'reply' },
{ id: 'reschedule', label: 'Remarcar', type: 'reply' },
{ id: 'cancel', label: 'Cancelar', type: 'reply' },
],
media: { url: 'https://exemplo.com/clinica.jpg' },
recipient: '5511999999999',
text: 'Deseja confirmar o agendamento de amanhã?',
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
```
```javascript Node.js (fetch) theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
buttons: [
{ id: 'confirm', label: 'Confirmar', type: 'reply' },
{ id: 'reschedule', label: 'Remarcar', type: 'reply' },
{ id: 'cancel', label: 'Cancelar', type: 'reply' },
],
media: { url: 'https://exemplo.com/clinica.jpg' },
recipient: '5511999999999',
text: 'Deseja confirmar o agendamento de amanhã?',
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
```
```python Python theme={null}
import requests
requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "5511999999999",
"text": "Deseja confirmar o agendamento de amanhã?",
"media": {"url": "https://exemplo.com/clinica.jpg"},
"buttons": [
{"id": "confirm", "label": "Confirmar", "type": "reply"},
{"id": "reschedule", "label": "Remarcar", "type": "reply"},
{"id": "cancel", "label": "Cancelar", "type": "reply"},
],
},
)
```
```go Go theme={null}
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "5511999999999",
"text": "Deseja confirmar o agendamento de amanhã?",
"media": { "url": "https://exemplo.com/clinica.jpg" },
"buttons": [
{ "id": "confirm", "label": "Confirmar", "type": "reply" },
{ "id": "reschedule", "label": "Remarcar", "type": "reply" },
{ "id": "cancel", "label": "Cancelar", "type": "reply" }
]
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
res.Body.Close()
}
```
### Botão de link (url) com imagem
Lembre: em WABA só pode existir 1 botão `url` na mensagem, e ele não pode ser combinado com botões `reply`.
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "5511999999999",
"text": "Seu boleto de julho está disponível.",
"media": {
"url": "https://exemplo.com/fatura.jpg"
},
"buttons": [
{
"label": "Ver boleto",
"type": "url",
"url": "https://exemplo.com/boleto/123"
}
]
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
buttons: [
{
label: 'Ver boleto',
type: 'url',
url: 'https://exemplo.com/boleto/123',
},
],
media: { url: 'https://exemplo.com/fatura.jpg' },
recipient: '5511999999999',
text: 'Seu boleto de julho está disponível.',
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
```
```javascript Node.js (fetch) theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
buttons: [
{
label: 'Ver boleto',
type: 'url',
url: 'https://exemplo.com/boleto/123',
},
],
media: { url: 'https://exemplo.com/fatura.jpg' },
recipient: '5511999999999',
text: 'Seu boleto de julho está disponível.',
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
```
```python Python theme={null}
import requests
requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "5511999999999",
"text": "Seu boleto de julho está disponível.",
"media": {"url": "https://exemplo.com/fatura.jpg"},
"buttons": [
{
"label": "Ver boleto",
"type": "url",
"url": "https://exemplo.com/boleto/123",
}
],
},
)
```
```go Go theme={null}
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "5511999999999",
"text": "Seu boleto de julho está disponível.",
"media": { "url": "https://exemplo.com/fatura.jpg" },
"buttons": [
{ "label": "Ver boleto", "type": "url", "url": "https://exemplo.com/boleto/123" }
]
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
res.Body.Close()
}
```
## Template (fora da janela de 24h)
Templates precisam ser criados e aprovados na Meta antes do envio. O campo `template` é mutuamente exclusivo com `text` e `media`.
O objeto `template` é um **espelho do formato da Meta**. A Zapster embrulha apenas `name` e `language` (que vira `{ "code": ... }`) e repassa o array `components` exatamente como você o envia para a Cloud API, sem reinterpretar. Por isso, use o mesmo formato da documentação de templates da Cloud API da Meta.
O `components` descreve as partes do template que recebem valores no envio:
* **`header`**: cabeçalho com mídia (imagem, vídeo ou documento) ou com uma variável de texto.
* **`body`**: o corpo, onde entram as variáveis do texto aprovado.
* **`button`**: os botões que têm valor dinâmico, como o `payload` de uma resposta rápida ou o sufixo de uma URL.
As variáveis do template podem ser **posicionais** (`{{1}}`, `{{2}}`, preenchidas pela ordem do array `parameters`) ou **nomeadas** (`{{customer_name}}`, preenchidas por `parameter_name`). Cada template usa um estilo ou o outro, nunca os dois juntos. Os valores enviados precisam corresponder ao que o template aprovado espera.
### Exemplo simples (variável posicional)
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "5511999999999",
"template": {
"name": "confirmacao_pedido",
"language": "pt_BR",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "João" }
]
}
]
}
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
recipient: '5511999999999',
template: {
components: [
{
parameters: [{ text: 'João', type: 'text' }],
type: 'body',
},
],
language: 'pt_BR',
name: 'confirmacao_pedido',
},
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
```
```javascript Node.js (fetch) theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
recipient: '5511999999999',
template: {
components: [
{
parameters: [{ text: 'João', type: 'text' }],
type: 'body',
},
],
language: 'pt_BR',
name: 'confirmacao_pedido',
},
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
```
```python Python theme={null}
import requests
requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "5511999999999",
"template": {
"name": "confirmacao_pedido",
"language": "pt_BR",
"components": [
{
"type": "body",
"parameters": [{"type": "text", "text": "João"}],
}
],
},
},
)
```
```go Go theme={null}
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "5511999999999",
"template": {
"name": "confirmacao_pedido",
"language": "pt_BR",
"components": [
{
"type": "body",
"parameters": [{ "type": "text", "text": "João" }]
}
]
}
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
res.Body.Close()
}
```
### Com header, variáveis posicionais e botões
Este template tem cabeçalho de imagem, duas variáveis posicionais no corpo (`{{1}}` e `{{2}}`) e dois botões: um de resposta rápida (com `payload`) e um de URL dinâmica (o texto vira o sufixo anexado à URL base do template). O `index` do botão segue a ordem em que ele aparece no template aprovado.
```bash cURL theme={null}
curl -X POST https://api.zapsterapi.com/v1/wa/messages \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "X-Instance-ID: YOUR_INSTANCE_ID" \
-H "Content-Type: application/json" \
-d '{
"recipient": "5511999999999",
"template": {
"name": "pedido_enviado",
"language": "pt_BR",
"components": [
{
"type": "header",
"parameters": [
{ "type": "image", "image": { "link": "https://exemplo.com/banner.jpg" } }
]
},
{
"type": "body",
"parameters": [
{ "type": "text", "text": "João" },
{ "type": "text", "text": "#1234" }
]
},
{
"type": "button",
"sub_type": "quick_reply",
"index": 0,
"parameters": [
{ "type": "payload", "payload": "RASTREAR_PEDIDO" }
]
},
{
"type": "button",
"sub_type": "url",
"index": 1,
"parameters": [
{ "type": "text", "text": "pedido/1234" }
]
}
]
}
}'
```
```javascript Node.js (axios) theme={null}
const axios = require('axios')
await axios.post(
'https://api.zapsterapi.com/v1/wa/messages',
{
recipient: '5511999999999',
template: {
components: [
{
parameters: [
{ image: { link: 'https://exemplo.com/banner.jpg' }, type: 'image' },
],
type: 'header',
},
{
parameters: [
{ text: 'João', type: 'text' },
{ text: '#1234', type: 'text' },
],
type: 'body',
},
{
index: 0,
parameters: [{ payload: 'RASTREAR_PEDIDO', type: 'payload' }],
sub_type: 'quick_reply',
type: 'button',
},
{
index: 1,
parameters: [{ text: 'pedido/1234', type: 'text' }],
sub_type: 'url',
type: 'button',
},
],
language: 'pt_BR',
name: 'pedido_enviado',
},
},
{
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
},
)
```
```javascript Node.js (fetch) theme={null}
await fetch('https://api.zapsterapi.com/v1/wa/messages', {
body: JSON.stringify({
recipient: '5511999999999',
template: {
components: [
{
parameters: [
{ image: { link: 'https://exemplo.com/banner.jpg' }, type: 'image' },
],
type: 'header',
},
{
parameters: [
{ text: 'João', type: 'text' },
{ text: '#1234', type: 'text' },
],
type: 'body',
},
{
index: 0,
parameters: [{ payload: 'RASTREAR_PEDIDO', type: 'payload' }],
sub_type: 'quick_reply',
type: 'button',
},
{
index: 1,
parameters: [{ text: 'pedido/1234', type: 'text' }],
sub_type: 'url',
type: 'button',
},
],
language: 'pt_BR',
name: 'pedido_enviado',
},
}),
headers: {
Authorization: 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json',
'X-Instance-ID': 'YOUR_INSTANCE_ID',
},
method: 'POST',
})
```
```python Python theme={null}
import requests
requests.post(
"https://api.zapsterapi.com/v1/wa/messages",
headers={
"Authorization": "Bearer YOUR_API_TOKEN",
"X-Instance-ID": "YOUR_INSTANCE_ID",
},
json={
"recipient": "5511999999999",
"template": {
"name": "pedido_enviado",
"language": "pt_BR",
"components": [
{
"type": "header",
"parameters": [
{"type": "image", "image": {"link": "https://exemplo.com/banner.jpg"}}
],
},
{
"type": "body",
"parameters": [
{"type": "text", "text": "João"},
{"type": "text", "text": "#1234"},
],
},
{
"type": "button",
"sub_type": "quick_reply",
"index": 0,
"parameters": [{"type": "payload", "payload": "RASTREAR_PEDIDO"}],
},
{
"type": "button",
"sub_type": "url",
"index": 1,
"parameters": [{"type": "text", "text": "pedido/1234"}],
},
],
},
},
)
```
```go Go theme={null}
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"recipient": "5511999999999",
"template": {
"name": "pedido_enviado",
"language": "pt_BR",
"components": [
{
"type": "header",
"parameters": [
{ "type": "image", "image": { "link": "https://exemplo.com/banner.jpg" } }
]
},
{
"type": "body",
"parameters": [
{ "type": "text", "text": "João" },
{ "type": "text", "text": "#1234" }
]
},
{
"type": "button",
"sub_type": "quick_reply",
"index": 0,
"parameters": [{ "type": "payload", "payload": "RASTREAR_PEDIDO" }]
},
{
"type": "button",
"sub_type": "url",
"index": 1,
"parameters": [{ "type": "text", "text": "pedido/1234" }]
}
]
}
}`)
req, _ := http.NewRequest("POST", "https://api.zapsterapi.com/v1/wa/messages", body)
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
req.Header.Set("X-Instance-ID", "YOUR_INSTANCE_ID")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
res.Body.Close()
}
```
### Variáveis nomeadas
Quando o template foi aprovado com variáveis nomeadas, cada parâmetro leva um `parameter_name` além de `type` e `text`. O restante da requisição (o `recipient`, os headers, o `name` e o `language`) é igual aos exemplos acima. Muda apenas o conteúdo de `components`:
```json components (variáveis nomeadas) theme={null}
[
{
"type": "header",
"parameters": [
{ "type": "text", "parameter_name": "company_name", "text": "Zapster" }
]
},
{
"type": "body",
"parameters": [
{ "type": "text", "parameter_name": "customer_name", "text": "João" },
{ "type": "text", "parameter_name": "order_id", "text": "#1234" }
]
}
]
```
Não misture variáveis posicionais e nomeadas no mesmo template. Use `parameter_name` apenas quando o template foi aprovado com variáveis nomeadas; caso contrário, use a forma posicional (só `type` e `text`, na ordem em que aparecem).
## Cobrança das mensagens
O canal oficial (WABA) é pago, e quem cobra pelas mensagens é a Meta, não a Zapster. As mensagens livres deste guia são gratuitas até 30 de setembro de 2026 e passam a ser cobradas a partir de 1 de outubro de 2026. Os templates seguem com a cobrança própria deles.
Para entender o que muda em 2026, as datas e como o preço é definido, veja [Cobrança de mensagens no WhatsApp oficial (WABA)](/pt-BR/v1/concepts/message-pricing).
## Erros comuns
Quando o payload usa um recurso que a Cloud API não suporta, a Zapster rejeita a requisição na hora com um erro `400` explicando o motivo. Nada é descartado ou adaptado silenciosamente.
| Código | Quando acontece | Como resolver |
| --------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `waba_feature_not_supported` | Botão `call` ou `copyable` em mensagem de sessão, ou áudio junto com botões | Para ligação, use um template com botão `PHONE_NUMBER`. Para copiar código, use um template de Marketing ou Authentication. Para áudio, envie em uma mensagem separada |
| `waba_invalid_button_combination` | Mistura de botão `url` com `reply`, ou mais de 1 botão `url` | Envie 1 botão `url` sozinho, ou até 3 botões `reply` |
| `waba_conversation_window_closed` | Mensagem livre fora da janela de 24 horas | Envie um template aprovado para reabrir a conversa |
| `waba_group_not_supported` | `recipient` de grupo em instância WABA | Grupos só funcionam em instâncias não oficiais |
| `waba_template_required` | Campo `template` enviado para instância não oficial | Templates só existem em instâncias WABA |
## Próximos passos
* [Mensagem com botões](/pt-BR/v1/guides/messages-with-buttons) para a matriz completa de suporte por tipo de conexão
* [Enviar mensagens para BSUID](/pt-BR/v1/guides/send-to-bsuid) para responder a usuários com telefone oculto (username / BSUID)
* [WABA vs não oficial](/pt-BR/v1/guides/waba-vs-unofficial) para escolher o tipo de instância
* [Conectando uma instância WABA](/pt-BR/v1/guides/connect-waba-instance)
# WABA vs não oficial
Source: https://developer.zapsterapi.com/pt-BR/v1/guides/waba-vs-unofficial
Entenda as diferenças entre instâncias oficiais e não oficiais para escolher a melhor opção
A Zapster suporta dois tipos de conexão com o WhatsApp. Cada um tem vantagens e limitações. Aqui está o que você precisa saber para escolher.
## Comparativo
| | Não oficial (QR code) | Oficial (WABA) |
| -------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Conexão** | QR code ou código de pareamento | OAuth com Meta ou token manual |
| **Estabilidade** | Boa | Alta (garantida pela Meta) |
| **Risco de banimento** | Existe, se usar de forma inadequada | Baixo (uso aprovado pela Meta) |
| **Templates** | Não suporta | Suporta (marketing, utility, authentication) |
| **Custo por mensagem** | Sem custo adicional | Meta cobra por conversa |
| **Grupos** | Suporta | Não suporta |
| **Botões interativos** | Suporta (`reply`, `url`, `call`, `copyable`) | Suporta até 3 `reply` ou 1 `url`, com mídia no cabeçalho ([matriz completa](/pt-BR/v1/guides/messages-with-buttons)) |
| **Contato sem telefone** | LID, no campo `lid` do contato | BSUID, no campo `bsuid` do contato ([guia completo](/pt-BR/v1/guides/send-to-bsuid)) |
| **Confirmação de leitura** | Sim | Sim |
| **Setup** | Escanear QR code | Conectar conta Meta ou inserir token |
| **Infra** | Gerenciada pela Zapster | Nenhuma adicional (API REST direta) |
## Quando usar não oficial
* Você quer testar rápido com um número pessoal ou de teste
* Precisa enviar para grupos do WhatsApp
* Não quer custo adicional por mensagem
* Está construindo um MVP ou prova de conceito
* O volume de envio é moderado (centenas por dia, não milhares)
## Quando usar WABA
* Precisa de estabilidade máxima e não pode arriscar o número
* Compliance e governança são requisitos (empresas maiores, saúde, financeiro)
* Quer usar templates de mensagem aprovados pela Meta
* O volume é alto e precisa de garantia de entrega
* Quer evitar qualquer risco de banimento
## Sobre custo
Instâncias não oficiais não têm custo por mensagem além do plano da Zapster.
Instâncias WABA seguem a [tabela de preços da Meta](https://developers.facebook.com/docs/whatsapp/pricing), que cobra por conversa (não por mensagem). O preço varia por:
* **Categoria**: marketing é mais caro que utility, que é mais caro que authentication
* **País do destinatário**: cada país tem uma faixa de preço diferente
* **Quem inicia**: se o cliente inicia a conversa, a primeira janela de 24h pode ser gratuita
A Zapster não adiciona custo sobre o que a Meta cobra. Você paga o plano da Zapster + o custo da Meta direto na sua conta.
## Posso ter os dois tipos na mesma conta?
Sim. Você pode ter instâncias oficiais e não oficiais na mesma conta da Zapster, cada uma com seus webhooks e configurações. A API funciona da mesma forma para ambos os tipos.
## Migração entre tipos
Atualmente não é possível converter uma instância não oficial para WABA, nem o contrário. Esse recurso está em desenvolvimento.
Quando estiver disponível, a migração vai ser transparente. Seus webhooks, integrações e configurações vão continuar funcionando sem precisar alterar código.
Por enquanto, se você precisa trocar o tipo de conexão, crie uma nova instância e atualize o ID da instância na sua integração.
## Próximos passos
* [Como conectar uma instância WABA](/pt-BR/v1/guides/connect-waba-instance)
* [Enviar mensagens para BSUID](/pt-BR/v1/guides/send-to-bsuid) para responder a usuários com telefone oculto no canal oficial
* [Cobrança de mensagens no WhatsApp oficial (WABA)](/pt-BR/v1/concepts/message-pricing)
* [Boas práticas de envio](/pt-BR/v1/guides/best-practices)
* [Criar instância via API](/pt-BR/v1/api-reference/instance/create-instance)
# Credenciais
Source: https://developer.zapsterapi.com/pt-BR/v1/integrations/n8n/credentials
## Objetivo
Criar a credencial "Zapster API" no N8n para autenticar suas chamadas.
## Como criar
1. Na sua instância do N8n, vá em Credentials → New.
2. Selecione "Zapster API Credentials".
3. Preencha o campo **API Key** ([clique aqui para obter o token](https://app.zapsterapi.com/tokens))
4. Opcionalmente você pode definir um ID de instância padrão ([clique aqui para obter o ID de instância](https://app.zapsterapi.com/instances)).
### Obtendo ID de instância
Dentro da página de [instâncias](https://app.zapsterapi.com/instances) você buscará pela instância que gostaria de conectar, e então clicar no botão para copiar o ID, assim como na imagem abaixo.
# Workflow de Exemplo
Source: https://developer.zapsterapi.com/pt-BR/v1/integrations/n8n/example
Para configuração rápida você pode usar nosso workflow de exemplo para entender o funcionamento e ver suas primeiras execuções usando o nó oficial Zapster API.
## Visão geral
O workflow acima é o que chamaos de "Roteador de Comandos", é uma automação simples, e consistem em "escutar" pelo evento de **Mensagem recebida** da instância selecionada e processar comandos.
Os comandos disponíveis para começar a brincar com a automação são
* **!ping**: Responderá com um *!pong*.
* **!image**: Responderá com uma imagem.
* **!audio**: Responderá com um áudio.
* **!video**: Responderá com um vídeo.
Em mensagens de texto, imagem e vídeo, acompanhará o tempo de resposta entre o recebimento e o envio da resposta. Veja o exemplo na próxima seção.
## Exemplos
## Baixar Workflow
Para que este workflow funcione, é necessário que você já tenha instalado os nós da Zapster. Se você ainda não instalou, veja como instalar em [Instalação](/pt-BR/v1/integrations/n8n/installation)
Copie o conteudo abaixo e cole dentro de um workflow do seu N8n.
```json Workflow [expandable] theme={null}
{
"name": "Command Router Example",
"nodes": [
{
"parameters": {
"events": [
"message.received"
],
"mode": "multiOutput",
"instancesIds": []
},
"type": "@zapsterapi/n8n-nodes-zapsterapi.zapsterApiTrigger",
"typeVersion": 1,
"position": [
-256,
16
],
"id": "f68a3c32-b1b6-4571-ae1d-8025bb42a31b",
"name": "Zapster API Trigger",
"webhookId": "2d4965a3-8815-4559-8e67-a02878f31a94",
"credentials": {}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "d0101f06-ec7b-496e-aafc-47738c3b0d77",
"leftValue": "={{ $json.data.recipient.type }}",
"rightValue": "chat",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
-32,
16
],
"id": "e239310a-41cb-4cb7-9e33-2b53e32593af",
"name": "Is individual chat?"
},
{
"parameters": {},
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
192,
128
],
"id": "ac9b8cf6-bd0d-46f5-a1db-e179d5b4b53d",
"name": "Ignoring groups!"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"leftValue": "={{ $('Zapster API Trigger').item.json.data.content.text }}",
"rightValue": "!ping",
"operator": {
"type": "string",
"operation": "equals"
},
"id": "3465f5e4-474a-4578-9912-8b397195aa90"
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "PING"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "cb1012bb-13a9-431f-99ee-b76a0374bb3b",
"leftValue": "={{ $('Zapster API Trigger').item.json.data.content.text }}",
"rightValue": "!image",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "IMAGE"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "aa27fc15-c330-4005-a709-6d23e0887abc",
"leftValue": "={{ $('Zapster API Trigger').item.json.data.content.text }}",
"rightValue": "!audio",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "AUDIO"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "17c24136-f19b-4d3f-ad5f-dfdd4133aa4e",
"leftValue": "={{ $('Zapster API Trigger').item.json.data.content.text }}",
"rightValue": "!video",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "VIDEO"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
192,
-128
],
"id": "c46c4512-90eb-4f82-b891-c65f1bd16b99",
"name": "Command Router"
},
{
"parameters": {
"resource": "message",
"operation": "sendMessage",
"instanceId": {
"__rl": true,
"value": "={{ $('Zapster API Trigger').item.json.instance_id }}",
"mode": "id"
},
"recipient": "={{ $('Zapster API Trigger').item.json.data.recipient.id }}",
"textMessage": "=pong! ({{DateTime.now().toUTC().diffTo(DateTime.fromISO($('Zapster API Trigger').item.json.created_at), 'seconds')}} segundos)",
"media": {},
"buttons": {},
"buttonSettingsNotice": "",
"additionalFields": {
"replyToMessageId": "={{ $('Zapster API Trigger').item.json.data.id }}"
}
},
"type": "@zapsterapi/n8n-nodes-zapsterapi.zapsterApi",
"typeVersion": 1,
"position": [
416,
-384
],
"id": "1216aa2f-0a84-4132-a5df-efa967360efb",
"name": "Send Pong",
"credentials": {
"zapsterApiCredentials": {
"id": "wuHiiZoHeCfPHogg",
"name": "Token PRD"
}
}
},
{
"parameters": {
"resource": "message",
"instanceId": {
"__rl": true,
"value": "={{ $('Zapster API Trigger').item.json.instance_id }}",
"mode": "id"
},
"recipient": "={{ $('Zapster API Trigger').item.json.data.recipient.id }}",
"textMessage": "={{DateTime.now().toUTC().diffTo(DateTime.fromISO($('Zapster API Trigger').item.json.created_at), 'seconds')}} segundos",
"media": {
"mediaSettings": {
"mediaUrl": "https://images.unsplash.com/photo-1485827404703-89b55fcc595e?q=80&w=600&format=jpeg&fit=crop"
}
},
"additionalFields": {
"replyToMessageId": "={{ $('Zapster API Trigger').item.json.data.id }}"
}
},
"type": "@zapsterapi/n8n-nodes-zapsterapi.zapsterApi",
"typeVersion": 1,
"position": [
416,
-192
],
"id": "c606f22c-b7b8-4225-a974-7ac1d1b8710f",
"name": "Send an Image",
"credentials": {
"zapsterApiCredentials": {
"id": "wuHiiZoHeCfPHogg",
"name": "Token PRD"
}
}
},
{
"parameters": {
"resource": "message",
"instanceId": {
"__rl": true,
"value": "={{ $('Zapster API Trigger').item.json.instance_id }}",
"mode": "id"
},
"recipient": "={{ $('Zapster API Trigger').item.json.data.recipient.id }}",
"textMessage": "=",
"media": {
"mediaSettings": {
"mediaUrl": "https://zapsterapi-samples.s3.us-east-1.amazonaws.com/file_example_MP3_700KB.mp3"
}
},
"additionalFields": {
"replyToMessageId": "={{ $('Zapster API Trigger').item.json.data.id }}"
}
},
"type": "@zapsterapi/n8n-nodes-zapsterapi.zapsterApi",
"typeVersion": 1,
"position": [
416,
0
],
"id": "8d95ad69-b25f-46a6-9dab-d785b46b5d68",
"name": "Send an Audio",
"credentials": {
"zapsterApiCredentials": {
"id": "wuHiiZoHeCfPHogg",
"name": "Token PRD"
}
}
},
{
"parameters": {
"resource": "message",
"instanceId": {
"__rl": true,
"value": "={{ $('Zapster API Trigger').item.json.instance_id }}",
"mode": "id"
},
"recipient": "={{ $('Zapster API Trigger').item.json.data.recipient.id }}",
"textMessage": "={{DateTime.now().toUTC().diffTo(DateTime.fromISO($('Zapster API Trigger').item.json.created_at), 'seconds')}} segundos",
"media": {
"mediaSettings": {
"mediaUrl": "https://zapsterapi-samples.s3.us-east-1.amazonaws.com/file_example_MP4_480_1_5MG.mp4"
}
},
"additionalFields": {
"replyToMessageId": "={{ $('Zapster API Trigger').item.json.data.id }}"
}
},
"type": "@zapsterapi/n8n-nodes-zapsterapi.zapsterApi",
"typeVersion": 1,
"position": [
416,
192
],
"id": "58488c81-2bba-4452-9f09-1ddde51065bc",
"name": "Send an Video",
"credentials": {}
}
],
"pinData": {},
"connections": {
"Zapster API Trigger": {
"main": [
[
{
"node": "Is individual chat?",
"type": "main",
"index": 0
}
]
]
},
"Is individual chat?": {
"main": [
[
{
"node": "Command Router",
"type": "main",
"index": 0
}
],
[
{
"node": "Ignoring groups!",
"type": "main",
"index": 0
}
]
]
},
"Command Router": {
"main": [
[
{
"node": "Send Pong",
"type": "main",
"index": 0
}
],
[
{
"node": "Send an Image",
"type": "main",
"index": 0
}
],
[
{
"node": "Send an Audio",
"type": "main",
"index": 0
}
],
[
{
"node": "Send an Video",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "f02e13c4-c1aa-44d1-ad86-30a69b18a3b9",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "8602b2bf44dc37aa465fd74e0c6e1e64728f18e19e18f668e104fcbd0de5c15e"
},
"id": "9gbFMRrQyoRhnHsP",
"tags": [
{
"createdAt": "2025-01-12T17:55:58.580Z",
"updatedAt": "2025-01-12T17:55:58.580Z",
"id": "btVxbPPBIKHgWFJE",
"name": "dev"
}
]
}
```
# Visão Geral
Source: https://developer.zapsterapi.com/pt-BR/v1/integrations/n8n/index
## Visão geral
Integração oficial dos nós Zapster para o N8n. Aqui você encontra instalação, configuração de credenciais, lista de nós (triggers e actions), exemplos e troubleshooting.
Como instalar o pacote de nós Zapster no N8n.
Como configurar a credencial Zapster API no N8n.
Eventos suportados pelo nó de gatilho da Zapster.
Workflows práticos para começar rápido.
# Instalação
Source: https://developer.zapsterapi.com/pt-BR/v1/integrations/n8n/installation
## Pré-requisitos
* N8n self-hosted ou cloud com Community Nodes habilitados.
* Acesso administrador ao painel do N8n.
## Instalar via Community Nodes
1. Abra o N8n e vá em Settings → Community Nodes habilitados.
2. Clique em "Install".
3. Informe o pacote: **@zapsterapi/n8n-nodes-zapsterapi**
4. Confirme a instalação e reinicie o N8n se solicitado.
## Verificar instalação
* No editor do n8n, pesquise por "Zapster".
* Você deve ver o Trigger (eventos) e as Actions (Ex.: Send a message, Check phone number, Presence update, Get one/many instance).
# Webhooks (Trigger)
Source: https://developer.zapsterapi.com/pt-BR/v1/integrations/n8n/trigger
O "Trigger" no N8n é o que faz o papel de Webhook, é quem receberá os eventos enviados dos servidores da Zapster, é nele que você definirá qual instância você precisa "escutar" pelos eventos e quais eventos você quer "escutar".
## Eventos
Quando você pesquisar por "Zapster API" em nós disponíveis, você deverá ver entrando em "Zapster API" duas seções (Triggers e Actions). Na seção triggers você deverá ver todos os eventos que a Zapster API suporta para as instâncias.
## Configurando Trigger
Após selecionar o evento (no nosso caso selecionamos "On message received"), você deverá ver as configurações do trigger como na imagem abaixo.
Este nó gerencia automaticamente os webhooks na sua conta da Zapster API através do token configurado. Você poderá ver os webhooks criados pelo N8n quando você ver o nome **Workflow ID# (Managed by N8n)** na lista de webhooks da sua conta. Como na imagem abaixo.
Selecione os eventos em **Events** e as instâncias em **Instances to listen for**. Você pode "escutar" por um ou mais eventos ao mesmo tempo para uma ou mais instâncias.
Optionalmente você pode informar o modo de saída (*Output Mode*), isto funciona como um facilitador, fazendo com que cada evento recebido tenha a sua própria saída do nó, veja o exemplo da imagem abaixo, onde temos dois eventos selecionados (`message.received` e `message.sent`), com o `Output Mode=Multiple Outputs` cada um desses eventos terá sua propria saida.
## Modo Teste e Ativação
Sempre que você ativar seu workflow (modo teste ou produção) através de um dos botões apresentados na imagem abaixo, automaticamente será criado ou anexado o webhook para as instâncias selecionadas no passo anterior.
Dessa forma, você raramente precisará entrar no dashboard de gestão de instâncias para criar ou gerenciar seus webhooks, te economizando tempo no desenvolvimento das suas automações.
## Erros comuns e como resolver.
### Workflow could not be activated
Se você estiver enfrentando problemas para ativar seu workflow em modo produção ou teste, como na imagem abaixo.
Você ou alguém pode ter alterado manualmente o webhook através da interface de gestão de instâncias, ou até mesmo o **N8n** pode ter tido algum erro de comunicação com os servidores da Zapster API.
Para solucionar, exclua o webhook através do painel de gestão, e tente ativar novamente seu workflow. Se o problema persistir, por favor, entre em contato que tentaremos te ajudar.
### Cannot activate test webhook
Se você estiver enfrentando problemas **para ativar o modo teste** em seu workflow, como na imagem abaixo.
Basicamente o que este erro está falando é que você não pode ter um webhook em **modo produção** e este mesmo webhook em **modo teste** ao mesmo tempo.
A solução para este caso é basicamente desativar o workflow, e depois tentar ativar no modo teste novamente.
# Começando
Source: https://developer.zapsterapi.com/pt-BR/v1/introduction
Envie sua primeira mensagem usando a API
Como integrar com outros sistemas
## Para agentes de IA
Índice de toda a documentação no formato [llmstxt.org](https://llmstxt.org/). Cole como contexto inicial no Claude Code, Codex, OpenClaw — o agente fica orientado sem navegar página a página.
`npm i -g @zapsterapi/cli` — wrapper sobre a REST API otimizado para shells e agentes. Inclui um quickstart copy-paste para o agente instalar e configurar sozinho.
## Conceitos
Apenda os conceitos e terminologias sobre instâncias.
Conceitos e terminologias sobre webhooks.
Entenda o que são e como funcionam.
O limite de 3 req/s, os headers `RateLimit-*`, o 429 e como tratar.
# Como aprovar o nome de exibição no WhatsApp (erro 131037)
Source: https://developer.zapsterapi.com/pt-BR/v1/numero-555-meta/aprovar-display-name
Passo a passo para aprovar o nome de exibição do seu número no WhatsApp pelo Meta Business Manager, atender aos critérios da Meta e resolver o erro 131037.
Para liberar os envios do [número 555 da Meta](/pt-BR/v1/numero-555-meta) e sair do erro 131037, você precisa enviar o nome de exibição para a Meta aprovar. Tudo é feito no Meta Business Manager e leva de alguns minutos a poucos dias úteis.
## Antes de começar: verificação do negócio
Sua conta precisa ter concluído a **verificação do negócio** (Business Verification) no Meta Business Manager. Sem ela, a opção de enviar o nome para análise nem aparece. Se ainda não fez, conclua a verificação primeiro e depois siga os passos abaixo.
## Passo a passo no Meta Business Manager
O caminho completo, do início ao envio para análise, é este:
```text theme={null}
business.facebook.com
→ Configurações do negócio (engrenagem)
→ Contas → Contas do WhatsApp → [sua conta]
→ número +1 555-XXX-XXXX
→ editar nome de exibição (lápis) → Enviar para análise
```
Entre em [business.facebook.com](https://business.facebook.com/) com a conta que administra o negócio. Se você gerencia mais de um negócio, confirme no seletor do topo da página que está no negócio certo antes de seguir.
No menu lateral, clique no ícone de engrenagem (**Configurações do negócio**). Dentro dele, no grupo **Contas**, abra **Contas do WhatsApp** e selecione a conta que contém o número 555. A conta selecionada mostra, à direita, os números vinculados a ela.
Na lista de números da conta, clique no número que começa com `+1 555` para abrir os detalhes. O nome de exibição atual aparece logo no topo, ao lado do número, junto com um ícone de lápis.
Clique no ícone de **lápis** ao lado do nome de exibição. Digite o novo nome seguindo as [diretrizes da Meta](https://www.facebook.com/business/help/338047025165344) e confirme em **Enviar para análise** (*Submit for review*). Depois disso, o nome fica marcado como "em análise" até a Meta responder.
## O que a Meta avalia
A análise é feita por uma pessoa, não de forma automática. Os pontos que mais pesam:
* O nome representa o negócio de verdade (nome real, marca ou uma variação reconhecível).
* O nome combina com a sua presença online, como site e redes sociais.
* Não tem termos enganosos, URL no meio do nome nem formatação fora das regras.
Se o nome for reprovado, a Meta informa o motivo. Ajuste conforme a orientação e envie de novo.
## Como saber que foi aprovado
A Meta avisa pelo painel do Business Manager e por e-mail quando o nome é aprovado. A partir daí, o erro 131037 deixa de aparecer e você já envia mensagens normalmente.
## Próximos passos
* [Número 555 da Meta e o erro 131037](/pt-BR/v1/numero-555-meta)
* [Perguntas frequentes](/pt-BR/v1/numero-555-meta/faq)
* [Conectando uma instância WABA](/pt-BR/v1/guides/connect-waba-instance)
***
Ficou com dúvida em algum passo? [Fale com o suporte](https://wa.me/5587999079455?text=Olá,%20preciso%20de%20ajuda%20com%20a%20aprovação%20do%20nome%20de%20exibição) ou [volte ao Dashboard](https://app.zapsterapi.com/?utm_source=Documentation\&utm_medium=DisplayNameApproval).
# FAQ: Perguntas frequentes sobre o número 555 da Meta
Source: https://developer.zapsterapi.com/pt-BR/v1/numero-555-meta/faq
Respostas rápidas sobre o número 555 da Meta no WhatsApp: erro 131037, custo, limite de mensagens, quando migrar para o seu próprio número e o que acontece se o cliente sair da Zapster.
Respostas curtas para as dúvidas mais comuns sobre o [número 555 da Meta](/pt-BR/v1/numero-555-meta) e o erro 131037.
## Por que não consigo enviar mensagem logo de cara?
Porque falta aprovar o nome de exibição do número. Até a Meta aprovar, o envio para clientes reais volta com o erro 131037. Veja [como aprovar o nome de exibição](/pt-BR/v1/numero-555-meta/aprovar-display-name).
## Quanto tempo demora a aprovação do nome?
De alguns minutos a poucos dias úteis. Não há um prazo fixo divulgado pela Meta.
## Preciso pagar pelo número 555?
Não. O número 555 é gratuito. Você paga apenas o preço normal das mensagens do WhatsApp, cobrado pela Meta por conversa, igual a qualquer outro número.
## Qual é o limite de mensagens?
O mesmo de qualquer número novo na Meta: começa baixo e aumenta conforme a qualidade do número e o volume de envios.
## O número 555 serve para produção?
Ele foi pensado para teste e onboarding inicial. Para uma operação contínua, a Meta recomenda migrar para o seu próprio número. O 555 também tem DDD fixo dos Estados Unidos (+1 555) e não funciona para SMS ou ligações.
## Quando devo migrar para o meu próprio número?
Vale migrar quando o volume de mensagens cresce, quando existe um contrato com o cliente, quando o branding importa (um DDD local, por exemplo) ou quando a linha precisa servir também para SMS e voz. Enquanto você ainda está validando a integração, o 555 dá conta. Para migrar, conecte uma instância com o seu número seguindo o guia [Conectando uma instância WABA](/pt-BR/v1/guides/connect-waba-instance).
## O cliente perde o número 555 se sair da Zapster?
O número fica vinculado à conta WhatsApp Business do cliente na Meta, não à Zapster. Mas o 555 não é portável: não dá para movê-lo para outra conta nem levar o histórico de conversas junto.
## Preciso verificar o negócio antes de aprovar o nome?
Sim. A verificação do negócio (Business Verification) é pré-requisito para enviar o nome de exibição para análise. Conclua a verificação primeiro e depois siga o [passo a passo de aprovação](/pt-BR/v1/numero-555-meta/aprovar-display-name).
## Próximos passos
* [Número 555 da Meta e o erro 131037](/pt-BR/v1/numero-555-meta)
* [Como aprovar o nome de exibição](/pt-BR/v1/numero-555-meta/aprovar-display-name)
***
Não encontrou sua resposta? [Fale com o suporte](https://wa.me/5587999079455?text=Olá,%20tenho%20uma%20dúvida%20sobre%20o%20número%20555%20da%20Meta) ou [volte ao Dashboard](https://app.zapsterapi.com/?utm_source=Documentation\&utm_medium=FAQ555).
# Número 555 da Meta e o erro 131037 no WhatsApp
Source: https://developer.zapsterapi.com/pt-BR/v1/numero-555-meta/index
Entenda o número 555 que a Meta gera no Embedded Signup do WhatsApp, por que a primeira mensagem dá o erro 131037 e como liberar os envios aprovando o nome de exibição.
Ao conectar uma conta pelo Embedded Signup, a Meta pode criar para você um número de teste gratuito com DDD **+1 555**. Ele aparece conectado no painel, mas a primeira mensagem para um cliente costuma voltar com o erro **131037**. Aqui você entende o que é esse número e como liberar os envios.
## O que é o número 555
É um número de teste que a Meta empresta durante o Embedded Signup, para você começar a usar o WhatsApp sem precisar ter um número próprio verificado. Ele é gratuito, já vem verificado e serve para testar a integração antes de ir para produção.
Cada conta costuma receber um ou dois desses números. Como é um número de teste com DDD dos Estados Unidos, a Meta recomenda usá-lo para avaliação e onboarding e migrar para o seu próprio número quando a operação virar produção. Falamos disso no [FAQ](/pt-BR/v1/numero-555-meta/faq).
## Por que a primeira mensagem é bloqueada
Antes de um número enviar mensagens para qualquer pessoa, a Meta precisa aprovar o **nome de exibição**, que é o nome que aparece para quem recebe. Enquanto esse nome não é aprovado, o número só conversa com contatos de teste, e o envio para um cliente real volta assim:
```text theme={null}
(#131037) WhatsApp provided number needs display name approval before message can be sent.
```
No painel da Meta o número parece pronto: aparece conectado e com o nome preenchido. É o que mais confunde. O que falta não é a conexão, é a aprovação do nome.
Bateu nesse erro? A solução é aprovar o nome de exibição. Veja o passo a passo em [Aprovar o nome de exibição](/pt-BR/v1/numero-555-meta/aprovar-display-name).
## Próximos passos
* [Aprovar o nome de exibição](/pt-BR/v1/numero-555-meta/aprovar-display-name)
* [Perguntas frequentes](/pt-BR/v1/numero-555-meta/faq)
* [Conectando uma instância WABA](/pt-BR/v1/guides/connect-waba-instance)
# Eventos Disponíveis
Source: https://developer.zapsterapi.com/pt-BR/v1/webhooks/available-events
Lista de eventos suportados e exemplos
Estamos em processo de melhorias da nossa documentação, em breve estaremos incluindo mais eventos com seus devidos exemplos.
Alguns eventos dependem do tipo de conexão da instância. Instâncias com **API oficial (WABA)** emitem hoje apenas `message.received`, `message.flow_reply`, `message.sent`, `message.delivered`, `message.read` e `message.failed`; os demais eventos desta página são emitidos por instâncias **não oficiais** (conexão por QR Code). Na outra direção, `message.failed` e `message.flow_reply` existem apenas na API oficial. A API recusa a assinatura de qualquer evento indisponível para o tipo de conexão da instância, tanto na criação quanto na atualização do webhook: a resposta é um erro `400` com o código `unsupported_webhook_event`, que nomeia todos os eventos recusados e lista os eventos disponíveis para aquela instância. Cada evento com essa restrição traz o aviso na sua própria seção.
### `instance.connected`
A instância foi conectada com sucesso e está pronta para envio e recebimento de mensagens.
```json theme={null}
{
"created_at": "2024-03-14T23:33:13.623Z",
"data": {
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"id": "so9lv3u3pu81he8gumfa4", // ID da notificação
"type": "instance.connected"
}
```
### `instance.disconnected`
A instância foi desconectada com sucesso.
Algumas vezes a desconexão pode acontecer devido a falhas internas do Whatsapp, internamente temos estrategias de recuperação, nestes casos o evento `instance.connected` pode ser emitido alguns segundos depois do evento de desconexão.
```json theme={null}
{
"created_at": "2024-09-14T13:51:49.224Z",
"data": {
"name": "Account Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"reason": {
"code": "logout",
"message": "The instance has been logged out."
}
},
"id": "682jcucv557qt0yarqivh",
"type": "instance.disconnected"
}
```
### `instance.forbidden`
A conexão da instância foi rejeitada pelo WhatsApp. Isso pode indicar que o número foi bloqueado, mas o evento sozinho não é uma confirmação de bloqueio: é necessária verificação antes de assumir isso.
Depois do evento, a instância fica `disconnected` e um novo QR Code costuma ser gerado logo em seguida (o evento `instance.qrcode` normalmente é emitido na sequência). Ao receber esse evento, reconecte a instância lendo o novo QR Code; se ele voltar a acontecer com frequência, revise as práticas de envio do número.
Este evento se aplica apenas a instâncias **não oficiais** (conectadas via QR Code). Instâncias com **API oficial (WABA)** não emitem este evento.
```json theme={null}
{
"created_at": "2025-07-29T13:51:49.224Z",
"data": {
"name": "Account Name",
"id": "551112341234",
"phone_number": "551112341234",
"lid": "123456789012345",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"id": "682jcucv557qt0yarqivh",
"type": "instance.forbidden"
}
```
### `message.received`
Uma mensagem foi recebida na instância. Para detalhamento completo de como é o formato do objeto mensagem verifique na página [Estrutura dos eventos > Mensagem](./event-schemas/message)
```json theme={null}
{
"created_at": "2024-09-14T13:55:46.420Z",
"data": {
"content": {
"text": "Oi"
},
"id": "3AAB4DA4297176B74E38",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2024-09-14T13:55:46.000Z",
"type": "text"
},
"id": "y66lhiw5la6z3r8f1urm0",
"type": "message.received"
}
```
```json theme={null}
{
"created_at": "2025-01-30T13:28:15.771Z",
"data": {
"content": {
"view_once": false,
"media": {
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"text": "My image caption"
},
"id": "3EB0AA6B4A8B13C4CA44E4",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-01-30T13:28:15.000Z",
"type": "image"
},
"id": "sepu74f9o9c3y8gq0ikbl",
"type": "message.received"
}
```
```json theme={null}
{
"created_at": "2025-01-30T13:28:15.771Z",
"data": {
"content": {
"view_once": false,
"media": {
// URL para arquivo de áudio MP3
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"text": ""
},
"id": "3EB0AA6B4A8B13C4CA44E4",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-01-30T13:28:15.000Z",
"type": "audio"
},
"id": "sepu74f9o9c3y8gq0ikbl",
"type": "message.received"
}
```
```json theme={null}
{
"created_at": "2025-01-30T13:31:56.534Z",
"data": {
"content": {
"location": {
"address": "São Paulo, SP",
"latitude": -9.123456789123456,
"longitude": -40.123456789123456,
"mode": "static",
"name": "Centro de Artes"
}
},
"id": "3A8A44190C6F468A1E90",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-01-30T13:31:56.000Z",
"type": "location"
},
"id": "8qmaixneh95c4vb6xm89k",
"type": "message.received"
}
```
```json theme={null}
{
"created_at": "2025-01-30T13:36:41.856Z",
"data": {
"content": {
"media": {
"metadata": {
"animated": true
},
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
}
},
"id": "3AB26376707099366558",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-01-30T13:36:41.000Z",
"type": "sticker"
},
"id": "3niukssdl9ca2qktbv9u6",
"type": "message.received"
}
```
```json theme={null}
{
"created_at": "2025-01-30T13:39:37.156Z",
"data": {
"content": {
"view_once": false,
"media": {
"metadata": {
"duration": 1,
"playback": true
},
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"text": "My video/gif caption"
},
"id": "3AB703F9740E34B5E110",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-01-30T13:39:36.000Z",
"type": "video"
},
"id": "jlmnxdp63p03wrv2ynepn",
"type": "message.received"
}
```
Observe a propriedade `data.content.quoted`, ela representa a citação ou marcação de quem está respondendo e tem o mesmo formato de uma `message.received`.
```json theme={null}
{
"created_at": "2025-02-02T21:18:28.437Z",
"data": {
"content": {
"view_once": false,
"quoted": {
"content": {
"text": "🙏"
},
"id": "3EB0E8FE1559DADE848EF5",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"type": "text"
},
"text": "My reply to quoted message"
},
"id": "3EB090C9F062EF62F1D924",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-02-02T21:18:28.000Z",
"type": "text"
},
"id": "wy43uruj26ylse1cs38ps",
"type": "message.received"
}
```
Observe que o status respondido ficará dentro de `data.content.quoted` que terá o mesmo formato de uma `message.received`, a grande diferença aqui é que você verá uma nova propriedade `data.content.quoted.content.origin` sendo o seu valor igual à `status`.
Agora existe um evento dedicado [`status.reply`](#status-reply) para respostas a status. Ele é emitido **além** do `message.received` (que continua sendo disparado, sem quebra de compatibilidade) e traz um formato enxuto, com o essencial do status em `data.content.status`. Prefira assiná-lo se você só precisa reagir a respostas de status.
Em alguns casos você pode encontrar uma variação do payload contendo uma propriedade `background_color` para status que são postado em formato de texto, seu valor representará a cor do fundo (background), contendo no formato decimal, hexadecimal com e sem o canal alfa (transparência).
```json theme={null}
{
"background_color": {
"decimal": 4283864831,
"hex_argb": "#FF5696FF", // com o canal alfa
"hex_rgb": "#5696FF" // sem o canal alfa
}
}
```
```json theme={null}
{
"created_at": "2025-02-02T21:14:47.330Z",
"data": {
"content": {
"view_once": false,
"quoted": {
"content": {
"view_once": false,
"origin": "status",
"media": {
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"text": "My status caption"
},
"id": "E7531155884C68EAC1F3F1774E2CABD2",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"type": "image"
},
"text": "Answering to the posted status XYZ"
},
"id": "3EB02ADDF16B28F7CA3753",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-02-02T21:14:46.000Z",
"type": "text"
},
"id": "p7ly4vp5jrlsw3yfm7pt2",
"type": "message.received"
}
```
Se a propriedade `waid` (ela pode ser ausente) estiver presente dentro de `data.content.contacts.phones` isso pode siginificar que o telefone / contato recebido tem um whatsapp válido.
```json theme={null}
{
"created_at": "2025-02-02T21:33:48.334Z",
"data": {
"content": {
"contacts": [
{
"vcard": "BEGIN:VCARD\nVERSION:3.0\nN:Test;Contato;;;\nFN:Contato Test\nTEL;type=CELL;waid=5511123451234:+55 11 12345-1234\nEND:VCARD",
"display_name": "Contato Test",
"first_name": "Contato",
"last_name": "Test",
"phones": [
{
"formatted_value": "+55 11 12345-1234",
"waid": "5511123451234"
}
]
}
]
},
"id": "3EB0B2B79F42613ACE4E",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-02-02T21:33:47.000Z",
"type": "vcard"
},
"id": "u0hyeyfkiwfmjdwf937cs",
"type": "message.received"
}
```
As mensagens com botões poderão chegar com os tipos **text**, **image** ou **video** e sempre acompanhada da propriedade **buttons** em seu conteudo (`data.content`).
```json theme={null}
{
"created_at": "2025-03-08T13:18:10.215Z",
"data": {
"content": {
"buttons": [
{
"id": "2ec4cf13-6c5c-48b3-af42-cc572d22c2b2",
"label": "Sim",
"type": "reply"
},
{
"id": "ccebc70b-aefd-492f-a19c-94b1384964be",
"label": "Não",
"type": "reply"
}
],
"text": "Você gostaria de informar seu endereço agora?"
},
"id": "3EB0303793FBDDACB97101",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-03-08T13:18:08.000Z",
"type": "text"
},
"id": "n0co5zard1myk7wx07cks",
"type": "message.received"
}
```
Assim como o exemplo acima, o tipo de mensagem chegará como **text**, **video** ou **image** porém a propriedade **button\_reply** (`data.button_reply`) mostrará qual botão o usuário pressionou.
```json theme={null}
{
"created_at": "2025-03-08T13:43:34.060Z",
"data": {
"content": {
"text": "Sim",
"button_reply": {
"label": "Sim",
"type": "reply",
"id": "2ec4cf13-6c5c-48b3-af42-cc572d22c2b2"
},
"quoted": {
"content": {
"buttons": [
{
"label": "Sim",
"type": "reply",
"id": "2ec4cf13-6c5c-48b3-af42-cc572d22c2b2"
},
{
"label": "Não",
"type": "reply",
"id": "ccebc70b-aefd-492f-a19c-94b1384964be"
}
],
"text": "Você gostaria de informar seu endereço agora?"
},
"id": "3EB0303793FBDDACB97101",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-03-08T13:18:08.000Z",
"type": "text"
}
},
"id": "A09627FC7D6444122AFF8AB0AB59BA6A",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-03-08T13:43:31.000Z",
"type": "text"
},
"id": "kckozfp7fpn4cfxfbsglu",
"type": "message.received"
}
```
```json theme={null}
{
"created_at": "2025-03-08T17:54:47.475Z",
"data": {
"content": {
"list_options": {
"button_label": "Abrir lista de opções",
"sections": [
{
"description": null,
"options": [
{
"description": "Descrição, opção 1",
"id": "1",
"title": "Opção 1"
},
{
"description": "Descrição, opção 2",
"id": "2",
"title": "Opção 2"
}
],
"title": "Opções disponíveis"
}
]
},
"text": "Selecione a opção que melhor encaixa para você!"
},
"id": "3EB0D33E50E19D78A5A789",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-03-08T17:54:46.000Z",
"type": "text"
},
"id": "f7wjjrkpd1d1nyjl3n5kl",
"type": "message.received"
}
```
Assim como o exemplo acima, o tipo de mensagem chegará como **text** porém a propriedade **list\_reply** (`data.list_reply`) mostrará qual opção o usuário selecionou.
```json theme={null}
{
"created_at": "2025-03-08T18:15:09.450Z",
"data": {
"content": {
"list_reply": {
"title": "Opção 2",
"description": "Descrição, opção 2",
"id": "2"
},
"text": "Descrição, opção 2",
"quoted": {
"content": {
"list_options": {
"button_label": "Abrir lista de opções",
"sections": [
{
"description": null,
"options": [
{
"description": "Descrição, opção 1",
"id": "1",
"title": "Opção 1"
},
{
"description": "Descrição, opção 2",
"id": "2",
"title": "Opção 2"
}
],
"title": "Opções disponíveis"
}
]
},
"text": "Selecione a opção que melhor encaixa para você!"
}
"id": "3EB0D33E50E19D78A5A789",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-03-08T17:54:46.000Z",
"type": "text"
}
},
"id": "3EB081D5F40D11F1C39815",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2025-03-08T18:15:08.000Z",
"type": "text"
},
"id": "9sj082811g9xm1bja68fp",
"type": "message.received"
}
```
Disponível apenas em instâncias com **API oficial (WABA)**, já que WhatsApp Flows não existem no WhatsApp não oficial. A resposta do formulário fica namespaced em `data.content.flow_reply` (`flow_token`, `response` e `response_raw`) e `data.type` vem como `flow_reply`.
Agora existe um evento dedicado [`message.flow_reply`](#message-flow-reply) para respostas de Flow. Ele é emitido **além** do `message.received` (que continua sendo disparado, sem quebra de compatibilidade) e traz os mesmos campos na raiz de `data.content`. Prefira assiná-lo se você só precisa reagir a respostas de formulário.
```json theme={null}
{
"created_at": "2026-07-29T00:16:04.000Z",
"data": {
"content": {
"flow_reply": {
"flow_token": "pedido-8231",
"response": {
"tipo_ocorrencia": "manutencao_refrigeracao",
"descricao": "despressurização"
},
"response_raw": "{\"tipo_ocorrencia\":\"manutencao_refrigeracao\",\"descricao\":\"despressuriza\\u00e7\\u00e3o\",\"flow_token\":\"pedido-8231\"}"
},
"quoted": {
"id": "wamid.HBgMNTU4..."
}
},
"id": "wamid.HBgMNTU4NzgxMTcwMjYxFQIAEhgg...",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2026-07-29T00:16:04.000Z",
"type": "flow_reply"
},
"id": "p7ly4vp5jrlsw3yfm7pt2",
"type": "message.received"
}
```
### `message.flow_reply`
Emitido quando alguém conclui um **WhatsApp Flow** (formulário nativo do WhatsApp) enviado pela sua instância. É um evento dedicado e assinável, pensado para quem precisa reagir só a respostas de formulário, sem inspecionar todas as `message.received`.
Este evento está disponível apenas em instâncias com **API oficial (WABA)**. WhatsApp Flows não existem no WhatsApp não oficial.
Este evento **não substitui** o `message.received`: uma resposta de Flow continua sendo disparada também como `message.received`, com o conteúdo namespaced em `data.content.flow_reply` (mesmos campos `flow_token`, `response` e `response_raw`) e `data.type` igual a `flow_reply`. O `message.flow_reply` é emitido **em adição**, trazendo esses mesmos campos direto na raiz de `data.content`, para quem só precisa assinar respostas de formulário.
O conteúdo da resposta fica em `data.content`:
* `flow_token`: o token que você definiu ao enviar o Flow, usado para correlacionar a resposta com o envio original. Pode vir `null` quando o Flow não devolve token. Evite colocar dados pessoais nesse token: diferente das respostas do formulário, ele não é tratado como dado sensível pela plataforma.
* `response`: as respostas do formulário já parseadas em objeto. As chaves são exatamente as definidas por você no Flow JSON, sem nenhuma transformação de chave ou valor. O `flow_token` não aparece dentro de `response`, ele já vem promovido para o campo de topo.
* `response_raw`: a string JSON original enviada pela Meta, sem nenhum tratamento. Está sempre presente, mesmo quando o parse deu certo, e serve para quem quer aplicar o próprio parser ou fazer auditoria byte a byte da submissão. Se o JSON vier malformado, `response` chega como `{}` e `response_raw` preserva a submissão original.
* `quoted` (quando presente): a mensagem de Flow original que foi respondida, no mesmo formato de citação usado em `message.received`.
```json theme={null}
{
"created_at": "2026-07-29T00:16:04.000Z",
"data": {
"content": {
"flow_token": "pedido-8231",
"response": {
"tipo_ocorrencia": "manutencao_refrigeracao",
"descricao": "despressurização"
},
"response_raw": "{\"tipo_ocorrencia\":\"manutencao_refrigeracao\",\"descricao\":\"despressuriza\\u00e7\\u00e3o\",\"flow_token\":\"pedido-8231\"}",
"quoted": {
"id": "wamid.HBgMNTU4..."
}
},
"id": "wamid.HBgMNTU4NzgxMTcwMjYxFQIAEhgg...",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2026-07-29T00:16:04.000Z",
"type": "flow_reply"
},
"id": "p7ly4vp5jrlsw3yfm7pt2",
"type": "message.flow_reply"
}
```
### `message.sent`
Uma mensagem foi enviada da instância mensagem pode ter sido enviada através do Whatsapp ou através da API da Zapster.
Você consegue identificar facilmente a origem do envio olhando para a propriedade `data.origin` que tem 2 valores possíveis (`zapsterapi` ou `whatsapp`), que identificarão a origem do envio da mensagem.
Em números **oficiais (WABA)** com o recurso de **Coexistência** da Meta ativo, as mensagens que a equipe envia pelo próprio **WhatsApp Business App** (ou por um dispositivo vinculado) também chegam como `message.sent` com `data.origin` igual a `whatsapp`. Mensagens enviadas pela API têm `data.origin` igual a `zapsterapi`.
Para detalhamento completo de como é o formato do objeto mensagem verifique na página [Estrutura dos eventos > Mensagem](./event-schemas/message)
```json theme={null}
{
"created_at": "2024-09-14T13:55:46.420Z",
"data": {
"content": {
"text": "Oi"
},
"id": "3AAB4DA4297176B74E38",
"recipient": {
"name": "Recipient Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
},
"sent_at": "2024-09-14T13:55:46.000Z",
"origin": "zapsterapi",
"type": "text"
},
"id": "y66lhiw5la6z3r8f1urm0",
"type": "message.sent"
}
```
### `message.delivered`
Indica que a mensagem foi entregue ao destinatário.
```json theme={null}
{
"created_at": "2025-09-03T13:38:17.798Z",
"data": {
"content": {
"text": "ok"
},
"id": "3ADC5C4A6F9DABCDEF25",
"recipient": {
"name": "Recipient Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "5511999990000",
"profile_picture": "https://zapsterapi..."
},
"sent_at": "2025-09-03T13:38:17.000Z",
"type": "text"
},
"id": "YHSC28q7sD32zm0ier3BQ",
"type": "message.delivered"
}
```
### `message.read`
Indica que a mensagem foi lida pelo destinatário.
Nas configurações de privacidade da instância, se a confirmação de leitura estiver desativada, você não poderá ver nem exibir confirmações de leitura. Então o evento de webhook não irá disparar.
```json theme={null}
{
"created_at": "2025-09-03T14:36:46.585Z",
"data": {
"content": {
"text": "Message readed"
},
"id": "3920A9F9FAFEC78CBE1C26E6ABCDEF25",
"recipient": {
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3...",
"name": "Recipient Name",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"sent_at": "2025-09-03T14:07:17.000Z",
"type": "text"
},
"id": "Cj41hzsvNUEr6isfHBrHJ",
"type": "message.read"
}
```
### `message.failed`
O WhatsApp recusou a entrega da mensagem. O evento traz o motivo da recusa em `data.errors` e, quando a mensagem foi enviada pela Zapster, também o conteúdo original em `data.content`.
Este evento está disponível apenas em instâncias com **API oficial (WABA)**. O WhatsApp não oficial não devolve confirmação de falha de entrega, então a assinatura de `message.failed` é recusada ao criar ou atualizar um webhook de instância não oficial.
Cada item de `data.errors` traz `code` e `title` sempre preenchidos, e `message` e `details` quando a Meta os envia. Use o `code` para tratar a falha de forma programática (por exemplo, `131026` indica mensagem não entregue ao destinatário, e `131047` indica que a janela de atendimento expirou e um template é necessário) e o `details` para registrar a explicação completa.
```json theme={null}
{
"created_at": "2026-07-29T13:41:02.000Z",
"data": {
"content": {
"text": "Seu pedido saiu para entrega"
},
"errors": [
{
"code": 131026,
"title": "Message undeliverable",
"message": "Message Undeliverable",
"details": "Message could not be delivered to the recipient."
}
],
"id": "wamid.HBgNNTUxMTk5OTk5OTk5ORUCABEYEjcxQ...",
"recipient": {
"bsuid": null,
"id": "5511999999999",
"name": "Recipient Name",
"phone_number": "5511999999999",
"profile_picture": null,
"type": "chat"
},
"sender": {
"bsuid": null,
"id": "5511999990000",
"name": null,
"phone_number": "5511999990000",
"profile_picture": "https://zapsterapi...",
"type": "chat"
},
"sent_at": "2026-07-29T13:41:00.000Z",
"type": "text"
},
"id": "kQ2s7bWfvJ1p0aTmz9xLr",
"type": "message.failed"
}
```
### `message.deleted`
Indica que uma mensagem foi apagada (para mim ou para todos) na conversa.
```json theme={null}
{
"created_at": "2025-09-03T14:15:05.588Z",
"data": {
"content": {
"text": "teste"
},
"id": "3A4B7D720682ABCDEF25",
"recipient": {
"approval_mode": "auto_approve",
"description": null,
"id": "120363402123456789",
"invite_code": null,
"invite_mode": "all_members",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group Name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": null,
"total_participants": 2,
"type": "group"
},
"sender": {
"name": "Sender Name",
"id": "5511999990000",
"profile_picture": "https://zapsterapi.s3..."
},
"sent_at": "2025-09-03T14:10:04.000Z",
"type": "text"
},
"id": "ToMoKaeAtAYhHLhhI6GNY",
"type": "message.deleted"
}
```
### `message.reaction`
Indica que uma reação (emoji) foi aplicada a uma mensagem.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"id": "3EB0220A8B6B28ABCDEF25",
"reacted_at": "2025-09-02T23:35:05.000Z",
"reacted_by": {
"name": "Recipient Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"reacted_message": {
"content": {
"text": "teste reaction"
},
"id": "3AC0C55193850CB8F36C",
"recipient": {
"name": "Recipient Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3...",
"type": "chat"
},
"sender": {
"name": "Sender Name",
"id": "5511999990000",
"profile_picture": "https://zapsterapi.s3..."
},
"sent_at": "2025-09-02T23:34:58.000Z",
"type": "text"
},
"reaction": "😮"
},
"id": "l1j0pt4wofz904u0456sp",
"type": "message.reaction"
}
```
Reações a mensagens com mais de 72 horas o objeto reacted\_message não será enviado com todas informações, mas sim apenas com o ID da mensagem que foi reagida.
```json theme={null}
{
"created_at": "2025-09-02T17:28:39.272Z",
"data": {
"id": "3EB0353F4E0589D1AFC7BF",
"reacted_at": "2025-09-02T17:28:38.000Z",
"reacted_by": {
"name": "Reacted by Name",
"id": "551112341234",
"profile_picture": "..."
},
"reacted_message": {
"id": "3EB0308CD725A43924946B"
},
"reaction": "😂"
},
"id": "nmy2s3rq9yz5rysq692bw",
"type": "message.reaction"
}
```
### `message.pinned`
Indica que uma mensagem foi fixada na conversa/grupo.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"author": {
"name": "Author Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"message": {
"duration": 604800,
"content": {
"text": "Dia 19 meeting de boas vindas"
},
"id": "3A73212D3B60ABCDEF25",
"recipient": {
"approval_mode": "auto_approve",
"description": null,
"id": "120363420123456789",
"invite_code": null,
"invite_mode": "all_members",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group Name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": null,
"total_participants": 4,
"type": "group"
},
"sender": {
"name": "Sender Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"sent_at": "2025-09-02T22:17:50.000Z",
"type": "text"
}
},
"id": "l1j0pt4wofz904u0456sp",
"type": "message.pinned"
}
```
### `message.unpinned`
Indica que uma mensagem foi desafixada.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"author": {
"name": "Author Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"message": {
"content": {
"text": "Meeting de boas vindas"
},
"id": "3A73212D3B60ABCDEF25",
"recipient": {
"approval_mode": "auto_approve",
"description": null,
"id": "120363420123456789",
"invite_code": null,
"invite_mode": "all_members",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": null,
"total_participants": 4,
"type": "group"
},
"sender": {
"name": "Sender Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"sent_at": "2025-09-02T22:17:50.000Z",
"type": "text"
}
},
"id": "l1j0pt4wofz904u0456sp",
"type": "message.unpinned"
}
```
### `instance.mentioned`
Indica que sua instância foi mencionada ("@...") em uma conversa/grupo.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"author": {
"name": "Author Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"mentioned_at": "2025-09-02T22:17:43.000Z",
"message": {
"content": {
"mentions": [
{
"name": "Mentioned Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
}
],
"text": "@5511999999999"
},
"id": "90C1979C3AA24B5FD8868523ABCDEF25",
"sent_at": "2025-09-02T22:17:43.000Z",
"type": "text"
},
"recipient": {
"approval_mode": "auto_approve",
"description": null,
"id": "120363420123456789",
"invite_code": null,
"invite_mode": "all_members",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group Name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": null,
"total_participants": 4,
"type": "group"
}
},
"id": "l1j0pt4wofz904u0456sp",
"type": "instance.mentioned"
}
```
### `status.reply`
Emitido quando alguém responde a um **status** publicado pela sua instância. É um evento dedicado e assinável, pensado para quem precisa automatizar em cima de respostas de status sem inspecionar todas as `message.received`.
Este evento **não substitui** o `message.received`: uma resposta a status continua sendo disparada também como `message.received` (com o status em `data.content.quoted`, no formato completo de mensagem). O `status.reply` é emitido **em adição**, com um formato enxuto e dedicado.
Diferente do `message.received`, o `status.reply` tem um formato **enxuto**: o status respondido vem em `data.content.status` (`id`, `type`, `text`, `media`, `background_color`) — sem o `data.content.quoted` redundante — e **não há `data.sender`**, porque nesse contexto ele seria sempre igual ao `data.recipient` (o contato que respondeu). A resposta em si fica no topo: `data.content.text`/`media`, `data.recipient`, `data.sent_at` e `data.type`.
Respostas de status podem conter **mídia** (imagem, vídeo, áudio, arquivo), assim como o próprio status respondido. A mídia da resposta vem em `data.content.media`; a mídia do status respondido em `data.content.status.media`. Status de texto trazem `data.content.status.background_color` com a cor de fundo nos formatos decimal e hexadecimal (com e sem canal alfa).
```json theme={null}
{
"created_at": "2025-02-02T21:14:47.330Z",
"data": {
"content": {
"text": "Amei! Quero aproveitar",
"status": {
"id": "E7531155884C68EAC1F3F1774E2CABD2",
"type": "text",
"text": "Promoção só hoje!",
"background_color": {
"decimal": 4283864831,
"hex_argb": "#FF5696FF",
"hex_rgb": "#5696FF"
}
}
},
"id": "3EB02ADDF16B28F7CA3753",
"recipient": {
"name": "Contact Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"lid": "137585536053271",
"phone_number": "551112341234",
"type": "chat"
},
"sent_at": "2025-02-02T21:14:46.000Z",
"type": "text"
},
"id": "p7ly4vp5jrlsw3yfm7pt2",
"type": "status.reply"
}
```
```json theme={null}
{
"created_at": "2025-02-02T21:14:47.330Z",
"data": {
"content": {
"text": "Que legal!",
"status": {
"id": "E7531155884C68EAC1F3F1774E2CABD2",
"type": "image",
"text": "My status caption",
"media": {
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/..."
}
}
},
"id": "3EB02ADDF16B28F7CA3753",
"recipient": {
"name": "Contact Name",
"id": "551112341234",
"profile_picture": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"lid": "137585536053271",
"phone_number": "551112341234",
"type": "chat"
},
"sent_at": "2025-02-02T21:14:46.000Z",
"type": "text"
},
"id": "p7ly4vp5jrlsw3yfm7pt2",
"type": "status.reply"
}
```
### `instance.qrcode`
Notifica quando um novo QR Code é gerado/atualizado para a instância.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"qrcode": "2@6t2v/gh1D+Ru+RnuEJf9hwjOEyar29s/1x6aWvfLvN38G/g..."
},
"id": "7jatr6a3hnn1qlxoz2ccc",
"type": "instance.qrcode"
}
```
### `group.created`
Indica que um novo grupo foi criado.
```json theme={null}
{
"id": "2711aqyqcy9ooavsvnu0e",
"data": {
"id": "120363420123456789",
"name": "Group Name",
"owner": {
"id": "5511999999999",
"name": "Owner Name",
"profile_picture": "https://zapsterapi.s3..."
},
"description": null,
"invite_code": "KlMCWzU3TakKghDpKFgVbr",
"invite_mode": "all_members",
"is_community": false,
"approval_mode": "requires_approval",
"is_restricted": false,
"is_announcement": false,
"profile_picture": null,
"total_participants": 4
},
"type": "group.created",
"created_at": "2025-09-02T21:52:34.409Z"
}
```
### `group.updated`
Indica que os dados do grupo foram atualizados (nome, foto, descrição, etc.).
```json theme={null}
{
"created_at": "2025-09-02T21:37:49.741Z",
"data": {
"approval_mode": "requires_approval",
"description": "Description of group",
"id": "120363020089898070",
"invite_code": "KxBnzvpAzFZsMnHJmj9EK5",
"invite_mode": "admins_only",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group Name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": "https://zapsterapi.s3...",
"total_participants": 3
},
"id": "l1j0pt4wofz904u0456sp",
"type": "group.updated"
}
```
### `group.participants_added`
Indica que um ou mais participantes foram adicionados ao grupo.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"author": {
"name": "Author Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"group": {
"approval_mode": "requires_approval",
"description": null,
"id": "120363020123456789",
"invite_code": "KxBnzvpAzFZsMnHJmj9EK5",
"invite_mode": "admins_only",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group Name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": "https://zapsterapi.s3...",
"total_participants": 3
},
"participants": [
{
"name": "Participants Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
}
]
},
"id": "l1j0pt4wofz904u0456sp",
"type": "group.participants_added"
}
```
### `group.participants_removed`
Indica que participantes foram removidos do grupo.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"author": {
"name": "Author Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"group": {
"approval_mode": "requires_approval",
"description": null,
"id": "120363020123456789",
"invite_code": "KxBnzvpAzFZsMnHJmj9EK5",
"invite_mode": "admins_only",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group Name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": "https://zapsterapi.s3...",
"total_participants": 3
},
"participants": [
{
"name": "Participant Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
}
]
},
"id": "l1j0pt4wofz904u0456sp",
"type": "group.participants_removed"
}
```
### `group.participants_promoted`
Indica que participantes foram promovidos a administradores.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"author": {
"name": "Author Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"group": {
"approval_mode": "requires_approval",
"description": null,
"id": "120363020123456789",
"invite_code": "KxBnzvpAzFZsMnHJmj9EK5",
"invite_mode": "admins_only",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group Name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": "https://zapsterapi.s3...",
"total_participants": 3
},
"participants": [
{
"name": "Participant Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
}
]
},
"id": "l1j0pt4wofz904u0456sp",
"type": "group.participants_promoted"
}
```
### `group.participants_demoted`
Indica que participantes foram rebaixados de administradores para membros.
```json theme={null}
{
"created_at": "2025-09-02T20:57:57.182Z",
"data": {
"author": {
"name": "Author Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"group": {
"approval_mode": "requires_approval",
"description": null,
"id": "120363020123456789",
"invite_code": "KxBnzvpAzFZsMnHJmj9EK5",
"invite_mode": "admins_only",
"is_announcement": false,
"is_community": false,
"is_restricted": false,
"name": "Group Name",
"owner": {
"name": "Owner Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
},
"profile_picture": "https://zapsterapi.s3...",
"total_participants": 3
},
"participants": [
{
"name": "Participant Name",
"id": "5511999999999",
"profile_picture": "https://zapsterapi.s3..."
}
]
},
"id": "l1j0pt4wofz904u0456sp",
"type": "group.participants_demoted"
}
```
# Mensagem
Source: https://developer.zapsterapi.com/pt-BR/v1/webhooks/event-schemas/message
# Introdução
Source: https://developer.zapsterapi.com/pt-BR/v1/webhooks/intro
# O que são Eventos?
Eventos são avisos que nossa plataforma envia automaticamente sempre que algo importante acontece. Por exemplo, quando uma nova mensagem é recebida ou enviada, nós enviamos um evento avisando sobre isso.
Você pode escutar esses eventos usando um webhook, permitindo que seu sistema responda automaticamente quando esses eventos acontecerem.
## Como os eventos são enviados?
Todos os eventos que enviamos possuem a mesma estrutura básica, facilitando a sua integração:
```json theme={null}
{
"created_at": "2025-03-08T15:00:00Z", // Data e hora do evento no formato UTC
"data": {}, // Conteúdo específico do evento
"id": "evt_1234567890", // Identificador único do evento
"type": "message.received" // Tipo do evento
}
```
* **created\_at**: Indica quando o evento foi disparado.
* **data**: Contém as informações específicas que variam conforme o tipo do evento.
* **id**: Um identificador único para referência e auditoria.
* **type**: Indica o que exatamente aconteceu, como `message.received`, `message.sent`, etc.
Confira todos os [eventos disponíveis](./available-events).
# Configurando Webhook
Source: https://developer.zapsterapi.com/pt-BR/v1/webhooks/setting-up-webhook
Estamos elaborando mais informações sobre criação de webhook que irão te ajudar 😊