API v1

ZapYou API
Documentação

Referência completa para integrar mensagens do WhatsApp Business em suas aplicações. Construa ferramentas poderosas de automação e engajamento.

64
Endpoints
5
Webhooks
RESTful
API Design

Introdução

Bem-vindo à API do ZapYou

A API do ZapYou permite que você integre o poder do WhatsApp Business em suas aplicações. Envie mensagens, gerencie instâncias, consulte históricos e muito mais, tudo através de uma API RESTful simples e poderosa.

64 Endpoints
Cobertura completa de funcionalidades
5 Webhooks
Receba eventos em tempo real
RESTful
Padrões modernos e consistentes

URL Base

https://server.zapyou.com/v1/api/

Formato de Resposta

Todas as respostas são JSON, mas não há um envelope único. O formato depende do grupo do endpoint — não escreva um cliente que assuma success ou data em toda resposta.

// Campanhas, tickets e lookups: envelope { data } (+ pagination nas listagens)
{ "data": [ ... ], "pagination": { "page": 1, "limit": 50, "total": 120, "hasMore": true } }

// Instancias, mensagens, templates e AI agents: objeto cru, sem envelope
{ "id": "507f1f77bcf86cd799439011" }

// Erros: { message } na maior parte da API; { error, details } na validacao Zod
{ "message": "Instance not found" }
{ "error": "INVALID_FIELDS", "details": [ { "path": ["name"], "code": "invalid_type" } ] }

Duas exceções valem atenção: GET /instances devolve um objeto indexado por posição ("0", "1"...) em vez de um array, e GET /messages devolve as mensagens agrupadas por instância, não em lista plana.

Autenticação

Company Member Token

Gerenciamento

Cobre tudo exceto o envio de mensagens. Escopo: a empresa inteira, com cada endpoint checando ainda uma permissão do grupo do membro:

  • Instâncias e webhooks
  • Consulta de mensagens
  • Campanhas e templates Meta
  • Tickets (atendimento)
Onde obter (são dois valores):
Configurações → aba API → Member ID + Token

Instance Token

Envio de Mensagens

Usado somente nos seis endpoints de envio. Cada instância tem seu próprio token, comparado literalmente — sem middleware e sem checagem de permissão:

  • Enviar texto
  • Enviar imagem
  • Enviar vídeo/áudio
  • Enviar documento e template
Onde obter:
Conexões → [Conexão] → Chave
Na mesma tela, o campo UUID é o :instanceId das rotas de envio.

AI Agent Token

Integração Externa

Usado para integração externa com AI Agents. Cada agente possui seus tokens:

  • Conversar com o agente
  • Gerenciar sessões
  • Obter histórico
  • Consultar informações
Onde obter:
AI Agents → [Agente] → Tokens → Criar

Como Usar

# Company Member Token — dois cabecalhos separados, sem "Bearer".
# Usado em: instancias, templates, mensagens, campanhas, tickets, lookups.
member: <CompanyMember.id>
token:  <CompanyMember.token>

# Instance Token — valor CRU no Authorization, sem "Bearer".
# Usado apenas nos seis POST /instances/send/*.
Authorization: <Instance.token>

# AI Agent Token — este sim usa Bearer (64 caracteres hexadecimais).
# Usado apenas em /aiagents/*.
Authorization: Bearer <ai-agent-token>

Boas Práticas para AI Agent Token

Defina expiração adequada: Configure uma data de expiração alinhada com seu caso de uso
Armazene com segurança: Use variáveis de ambiente, nunca hardcode o token no código
Um token por aplicação: Crie tokens separados para cada integração
Monitore o uso: Acompanhe as estatísticas de cada token no painel
Revogue quando necessário: Se um token for comprometido, expire-o imediatamente
Trate erros 402: Implemente tratamento para saldo de IA insuficiente

Referência da API

Explore todos os endpoints disponíveis na API do ZapYou, organizados por categoria.

Gerenciamento de Instâncias

6 endpoints

GET/instances

Listar Instâncias

Retorna todas as instâncias da empresa do token. ATENÇÃO ao formato: a resposta NÃO é um array nem tem envelope — o backend serializa a lista como objeto indexado por posição ("0", "1", "2"...). Use Object.values(resposta) para iterar. Cada item é o registro completo da instância (inclusive o campo token, que é o Instance Token usado nos endpoints de envio), com businessAccountId achatado na raiz (null quando a instância não é meta_cloud). Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão instance:list.

POST/instances/poweron/:instanceId

Ligar Instância

Liga uma instância desligada. Antes de ligar, o backend valida a assinatura: instância sem subscription ACTIVE/TRIALING, com período vencido ou em trial expirado recebe 402 com um code específico. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão instance:start.

POST/instances/poweroff/:instanceId

Desligar Instância

Desliga uma instância ligada (grava on=false, connected=false e limpa poweredOnAt). A sessão do WhatsApp é preservada — para encerrar a sessão use o endpoint de desconexão. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão instance:stop.

POST/instances/disconnect/:instanceId

Desconectar Instância

Encerra a sessão do WhatsApp (logout). Em instâncias Baileys o auth_state local é apagado, então a próxima conexão exige novo QR Code. A desconexão é assíncrona: o 200 confirma que o evento foi disparado, não que já concluiu — acompanhe pelo webhook instance:disconnected. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão instance:stop.

PUT/instances/update/:instanceId

Atualizar Nome da Instância

Atualiza o nome da instância. Único campo editável por este endpoint. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão instance:update. Este endpoint não passa por rate limit.

PUT/instances/webhooks/:instanceId

Atualizar URLs de Webhook

Define as URLs de webhook da instância. Chave omitida do corpo permanece inalterada; para limpar uma URL, envie-a como string vazia (""). Cada URL preenchida passa por validação anti-SSRF (protocolo, porta, domínio e faixas de IP privadas/reservadas) antes de ser salva; uma URL reprovada devolve 400 e nenhuma das cinco é gravada. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão instance:webhooks. Este endpoint não passa por rate limit.

Envio de Mensagens

5 endpoints

POST/instances/send/text/:instanceId

Enviar Mensagem de Texto

Envia uma mensagem de texto para um contato do WhatsApp.

POST/instances/send/image/:instanceId

Enviar Imagem

Envia uma imagem com legenda opcional para um contato do WhatsApp.

POST/instances/send/video/:instanceId

Enviar Vídeo

Envia um vídeo para um contato do WhatsApp.

POST/instances/send/audio/:instanceId

Enviar Áudio

Envia um áudio ou nota de voz (PTT) para um contato do WhatsApp.

POST/instances/send/document/:instanceId

Enviar Documento

Envia um documento (PDF, DOC, etc) para um contato do WhatsApp.

Consulta de Mensagens

3 endpoints

GET/messages

Listar Mensagens

Lista as mensagens da empresa com paginação por cursor (ObjectId decrescente, da mais recente para a mais antiga). O resultado NÃO é uma lista plana: as mensagens vêm agrupadas por instância, junto de um resumo em stats e do eco dos filtros aplicados. Respostas são cacheadas no Redis por 5 minutos por combinação de filtros — use POST /messages/clear-cache para invalidar. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão message:show.

GET/messages/:phone

Buscar Mensagens por Telefone

Retorna as mensagens trocadas com um número, agrupadas por instância. Diferente de GET /messages, aqui cada mensagem vem com TODOS os campos do registro e o arquivo completo (include: file) — resposta mais pesada. Não há cache. Toda instância da empresa aparece no array, inclusive as sem mensagens para esse número (com messages vazio). Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão message:show.

POST/messages/clear-cache

Limpar Cache de Mensagens

Invalida TODO o cache Redis de GET /messages da empresa do token (todas as combinações de filtro). Não recebe corpo — enviar um é inofensivo, mas ignorado; não há como limpar o cache de uma instância específica. Este endpoint não checa permissão além da autenticação e não passa por rate limit.

Campanhas

37 endpoints

GET/campaigns

Listar Campanhas

Lista as campanhas ativas da empresa (as desativadas via DELETE /campaigns/:campaignId nunca aparecem), da mais recente para a mais antiga, com paginação por página. Cada item é um resumo — para o objeto completo com contagens, use GET /campaigns/:campaignId. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão campaign:list.

GET/departments

Listar Departamentos

Lookup dos departamentos ativos da empresa, para preencher o campo departmentId ao configurar o roteamento de respostas de campanha (PUT /campaigns/:campaignId/reply-routing). Devolve apenas id e nome, sem paginação. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão campaign:show.

GET/members

Listar Atendentes

Lookup dos membros da empresa, para preencher o campo memberId ao rotear respostas de campanha para um atendente específico. O id devolvido é o User.id (não o CompanyMember.id). Sem paginação e sem filtro por status. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão campaign:show.

POST/campaigns

Criar Campanha

Cria uma nova campanha. Use type "default" para campanhas comuns (texto/mídia) ou "meta_template" para campanhas baseadas em templates Meta aprovados.

GET/campaigns/:campaignId

Obter Campanha

Retorna os detalhes completos de uma campanha pelo seu ID.

GET/campaigns/scheduled

Listar Campanhas Agendadas

Retorna as campanhas com agendamento ativo (status "scheduled").

PUT/campaigns/:campaignId/name

Renomear Campanha

Altera o nome de uma campanha existente.

PUT/campaigns/:campaignId/interval

Alterar Intervalo de Envio

Define o intervalo (delay) em segundos entre cada disparo da campanha.

POST/campaigns/:campaignId/duplicate

Duplicar Campanha

Cria uma cópia da campanha. Use duplicateType para escolher o que copiar: "full" (tudo), "messages-only" (apenas mensagens) ou "payloads-only" (apenas destinatários).

DELETE/campaigns/:campaignId

Desativar Campanha

Desativa (remove) uma campanha pelo seu ID.

GET/campaigns/:campaignId/messages/models

Listar Modelos de Mensagem

Retorna os modelos de mensagem (texto/mídia) configurados na campanha, ordenados por "order".

POST/campaigns/:campaignId/messages/models

Adicionar Modelo de Mensagem

Adiciona um modelo de mensagem à campanha. Pode ser um modelo comum (texto/mídia, com type + options) ou o anexo de um template Meta aprovado (type "template" + templateId). Campanhas meta_template aceitam apenas 1 template.

PUT/campaigns/:campaignId/messages/models/:messageId

Atualizar Modelo de Mensagem

Atualiza um modelo de mensagem existente. Usa o mesmo schema do create (type + options obrigatórios).

PUT/campaigns/:campaignId/messages/models/:messageId/order

Reordenar Modelo de Mensagem

Altera a posição (order) de um modelo de mensagem na sequência de envio.

DELETE/campaigns/:campaignId/messages/models/:messageId

Remover Modelo de Mensagem

Remove um modelo de mensagem da campanha.

POST/campaigns/:campaignId/template/preview

Pré-visualizar Template

Renderiza o template Meta da campanha usando os campos de um destinatário existente, identificado pelo índice (payloadIndex).

GET/campaigns/:campaignId/template/variables

Listar Variáveis do Template

Retorna as variáveis declaradas pelo template Meta anexado à campanha, aninhadas por componente (header/body/buttons), além do mapeamento atual (currentMapping), dos campos disponíveis dos destinatários (availableFields) e da mídia de header (headerMediaType, staticHeaderMedia). O objeto `variables` segue o mesmo shape esperado pelo `variableMapping` em PUT /template/mapping.

PUT/campaigns/:campaignId/template/mapping

Mapear Variáveis do Template

Define o mapeamento entre as variáveis do template Meta e os campos dos destinatários. O `variableMapping` é aninhado por componente (header/body/buttons); cada sub-objeto é um Record<string,string> (índice da variável → nome da coluna). Botões usam a chave "índiceBotão_índiceVar" (ex.: "0_1") e o header de mídia dinâmica usa a chave "media".

POST/campaigns/:campaignId/media

Upload de Mídia da Campanha

Envia um arquivo e devolve uma URL pública utilizável no header de mídia do template (`staticHeaderMedia`) ou em uma ação de botão (`buttonActions[].url`). O upload **não** grava configuração: persista a URL você mesmo, via `PUT /campaigns/:campaignId/template/mapping` ou `PUT /campaigns/:campaignId/messages/models/:messageId`. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer"). A resposta vem **fora** do envelope `{ data }` usado no restante da API pública. A URL gerada é pública — é o servidor da Meta que baixa o arquivo a cada disparo.

GET/campaigns/:campaignId/payloads

Listar Destinatários

Retorna os destinatários (payloads) da campanha de forma paginada. Cada payload contém telefone e campos personalizados.

POST/campaigns/:campaignId/payloads

Adicionar Destinatários

Adiciona destinatários à campanha em lote. Cada item é um objeto com o telefone (campo definido por phoneKey, default "phone") e campos personalizados.

POST/campaigns/:campaignId/payloads/import-url

Importar Destinatários por URL

Importa destinatários a partir de um arquivo acessível por URL (ex.: CSV). O backend baixa o arquivo, faz o parse e adiciona os destinatários à campanha.

GET/campaigns/:campaignId/contacts

Listar Contatos

Retorna os contatos da campanha de forma paginada (telefone + status ativo).

POST/campaigns/:campaignId/instances

Definir Instâncias da Campanha

Define as instâncias (conexões WhatsApp) usadas para enviar a campanha. Substitui a lista atual.

POST/campaigns/:campaignId/testing

Testar Campanha

Envia a sequência de mensagens da campanha para um número de teste, sem afetar a lista real de destinatários.

POST/campaigns/:campaignId/start

Iniciar Campanha

Inicia o disparo da campanha. Envie o header Idempotency-Key (UUID único por clique) para evitar inícios duplicados.

POST/campaigns/:campaignId/pause

Pausar Campanha

Pausa uma campanha em andamento.

POST/campaigns/:campaignId/resume

Retomar Campanha

Retoma uma campanha que estava pausada.

POST/campaigns/:campaignId/schedule/start

Agendar Início

Agenda o início automático da campanha para uma data/hora (ISO 8601).

POST/campaigns/:campaignId/schedule/pause

Agendar Pausa

Agenda a pausa automática da campanha para uma data/hora (ISO 8601).

POST/campaigns/:campaignId/schedule/resume

Agendar Retomada

Agenda a retomada automática da campanha para uma data/hora (ISO 8601).

PUT/campaigns/:campaignId/schedule

Atualizar Agendamento Completo

Define em uma única chamada todas as janelas de agendamento (início, pausa, retomada) e o auto-agendamento.

DELETE/campaigns/:campaignId/schedule

Cancelar Agendamento

Remove todas as janelas de agendamento da campanha, desativando o auto-agendamento.

PUT/campaigns/:campaignId/reply-routing

Configurar Roteamento de Respostas

Define para onde as respostas dos contatos são roteadas: fila ("queue"), departamento ("department") ou atendente ("member"). Envie replyRouting: null para desabilitar.

PUT/campaigns/:campaignId/reply-routing

Desabilitar Roteamento de Respostas

Desabilita o roteamento de respostas da campanha. Usa o mesmo endpoint do reply-routing, enviando replyRouting: null no corpo.

GET/campaigns/:campaignId/submissions

Listar Envios

Retorna os envios (submissions) da campanha de forma paginada, com status individual de cada disparo. Pode filtrar por status.

GET/campaigns/:campaignId/metrics

Obter Métricas da Campanha

Retorna as métricas consolidadas da campanha: totais por status, percentual de progresso e taxas de entrega e leitura.

Meta Templates

4 endpoints

Renderizando o preview do template com components

Estrutura crua do template

components carrega a estrutura crua do template — header, body, footer e botões, com os exemplos de preenchimento vindos da Meta. É o que permite mostrar ao usuário como a mensagem vai ficar antes de disparar. Ele vem tanto na listagem quanto no detalhe.

  • Percorra o array por type: HEADER, BODY, FOOTER e BUTTONS. A ordem no array é a ordem de exibição.
  • No HEADER, use format para saber se é texto (TEXT) ou mídia (IMAGE, VIDEO, DOCUMENT). Esse mesmo format define o type do headerMedia no envio.
  • Use example para pré-preencher a visualização com valores realistas — o BODY traz example.body_text[0], um array na ordem das variáveis.
// Substitui {{1}}, {{2}}... pelos valores informados
const fill = (text, values) =>
  text.replace(/\{\{(\d+)\}\}/g, (_, i) => values[i] ?? '{{' + i + '}}');

function renderPreview(template, values = {}) {
  const preview = { header: null, body: '', footer: '', buttons: [] };

  for (const c of template.components) {
    switch (c.type) {
      case 'HEADER':
        // format diz se o header e texto ou midia
        preview.header =
          c.format === 'TEXT'
            ? { kind: 'text', value: fill(c.text, values) }
            : { kind: 'media', mediaType: c.format }; // IMAGE | VIDEO | DOCUMENT
        break;
      case 'BODY':
        preview.body = fill(c.text, values);
        break;
      case 'FOOTER':
        preview.footer = c.text; // footer nao aceita variavel
        break;
      case 'BUTTONS':
        preview.buttons = c.buttons.map((b) => ({ type: b.type, text: b.text }));
        break;
    }
  }

  return preview;
}

// Pre-preenchendo com os exemplos que a Meta devolve:
const body = template.components.find((c) => c.type === 'BODY');
const sample = body?.example?.body_text?.[0] ?? []; // ["Joao", "12345"]
const values = Object.fromEntries(sample.map((v, i) => [String(i + 1), v]));

renderPreview(template, values);
GET/templates

Listar Templates WABA

Lista os templates Meta Cloud da empresa, com filtros e paginação. Cada item traz components (a estrutura crua do template — header, body, footer e botões, com os exemplos vindos da Meta), que é o que permite renderizar um preview antes de disparar. Atenção: o campo variables lista APENAS as variáveis do BODY — variáveis de header ou de URL de botão não aparecem aqui; para montar o formulário de envio, use GET /templates/:id (expectedVariables). Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige permissão instance:list.

GET/templates/:id

Detalhe de Template

Retorna um template específico — os mesmos campos de um item da lista (inclusive components, plano na raiz, sem o envelope data), acrescidos de expectedVariables. Este é o ÚNICO endpoint que expõe expectedVariables, o contrato completo de variáveis (header, body, botões e total). Liste com GET /templates, mas monte o formulário de envio com GET /templates/:id: quem deriva o formulário do campo variables da listagem perde as variáveis de header e de botão silenciosamente e recebe 422 MISSING_VARIABLES no envio. Autenticação por Company Member Token (cabeçalhos member + token) — exige permissão instance:list.

GET/instances/:instanceId

Detalhe de Instância

Retorna os dados públicos (seguros) de uma instância. Nunca expõe access token, segredos ou credenciais. Autenticação por Company Member Token (cabeçalhos member + token) — exige permissão instance:show.

POST/instances/send/template/:instanceId

Enviar Mensagem via Template

Envia uma mensagem usando um template Meta Cloud aprovado. Requer instância meta_cloud ligada e conectada. A resposta é SÍNCRONA: o backend aguarda o resultado real do envio (ou 30s de timeout) antes de responder — não há polling a fazer. Autenticação por Instance Token: cabeçalho Authorization com o valor CRU do token (sem "Bearer") — enviar "Bearer <token>" causa 401.

AI Agents

5 endpoints

AI Agent Token

Integração Externa

Tokens exclusivos para cada AI Agent, permitindo acesso programático sem autenticação de usuário. Crie chatbots inteligentes, assistentes virtuais e automações.

Onde obter:
AI Agents → [Agente] → Aba Tokens → Criar Token
POST/aiagents/chat

Chat com AI Agent

Envia uma mensagem para o AI Agent e recebe a resposta. Usa o contexto da sessão para manter a conversa.

GET/aiagents/agent

Informações do Agente

Retorna informações básicas do AI Agent associado ao token.

GET/aiagents/widget/config

Configuração do Widget

Devolve os dados públicos usados pela página hospedada do widget de chat (widget.zapyou.com). Só responde 200 se o widget estiver habilitado para ESTE token — habilite em AI Agents → [Agente] → Tokens. O script carregador do widget é servido pela própria API, em https://server.zapyou.com/v1/widget/loader.js.

GET/aiagents/sessions/:sessionId

Buscar Histórico da Sessão

Retorna o histórico de uma sessão. As sessões vivem no Redis com TTL de 24 horas a partir da última mensagem e guardam no máximo as 50 mensagens mais recentes (janela deslizante) — este endpoint devolve até 50. Sessão inexistente ou expirada NÃO é erro: responde 200 com messages vazio e totalMessages 0. O escopo é o token: uma sessão criada por outro token não é visível aqui.

DELETE/aiagents/sessions/:sessionId

Limpar Sessão

Apaga o histórico da sessão no Redis, permitindo recomeçar a conversa com o mesmo ID. Devolve 404 quando não havia nada para apagar (sessão inexistente ou já expirada).

Tickets (Atendimento)

4 endpoints

API somente-leitura para montar dashboards externos de atendimento: listar tickets com filtros e paginação, ver o detalhe de um ticket, o histórico de movimentação e estatísticas de mensagens. O escopo é a empresa inteira do token — diferente da tela interna, não há recorte por canais do membro nem por regras de fila.

GET/tickets

Listar Tickets

Lista os tickets (atendimentos) da empresa com filtros ricos e paginação por página. Autenticação por Company Member Token (cabeçalhos member + token, sem "Bearer") — exige a permissão attendance:reports:view.

GET/tickets/:ticketId

Detalhe de um Ticket

Retorna um ticket específico. Mesmo objeto da listagem, sem messageCount, acrescido de customFields, unreadCount, transferredFromUserId, transferReason e um contato mais completo. Autenticação por Company Member Token (cabeçalhos member + token) — exige attendance:reports:view.

GET/tickets/:ticketId/history

Histórico de Movimentação

Retorna o histórico de movimentação do ticket (mudanças de status, transferências, notas). Autenticação por Company Member Token (cabeçalhos member + token) — exige attendance:reports:view.

GET/tickets/:ticketId/stats

Estatísticas de Mensagens

Retorna estatísticas de mensagens do ticket: contagens por remetente/tipo/status de entrega e tempos. NUNCA inclui conteúdo de mensagem (texto ou mídia). Autenticação por Company Member Token (cabeçalhos member + token) — exige attendance:reports:view.

Webhooks

O que são Webhooks?

Webhooks são notificações HTTP POST enviadas automaticamente para URLs configuradas quando eventos específicos ocorrem no ZapYou. Use webhooks para receber atualizações em tempo real sobre mensagens, status e conexões.

Configuração
Configure as URLs em PUT /instances/webhooks/:instanceId. Toda URL passa por validação anti-SSRF: endereços privados, portas bloqueadas e protocolos fora de http/https são recusados com 400.
Formato
Todas as requisições são POST com Content-Type: application/json e o corpo no formato { event, datetime, payload }.
messageURL

Disparado a cada mensagem recebida ou enviada — é o webhook de maior frequência. O campo event vale sempre "message", mas o payload difere conforme o provider da instância: instâncias Meta Cloud incluem provider: "meta_cloud" e um objeto file com mediaId/mimeType, enquanto instâncias Baileys não enviam provider e trazem mentions e registryType. Entrega: Baileys chama uma única vez, com timeout de 5s e sem retentativa; Meta Cloud usa timeout de 10s com até 3 retentativas em backoff exponencial. Uma falha na entrega não é reprocessada depois — trate o webhook como best-effort e reconcilie por GET /messages quando precisar de garantia.

Payload Fields

FieldTypeDescription
eventstringSempre "message"
datetimestringTimestamp da mensagem em ISO 8601
payload.providerstringPresente APENAS em instâncias Meta Cloud, com o valor "meta_cloud". Ausente em Baileys
payload.instancestringInstance.id (ObjectId de 24 caracteres)
payload.codestringInstance.code (UUID da instância)
payload.messagestringID da mensagem no WhatsApp (wamid em Meta Cloud)
payload.typestringTipo da mensagem: text, image, video, gif, audio, document, sticker, location, contact...
payload.fromMebooleantrue quando a mensagem saiu desta linha
payload.sourcestringSomente em ecos do Meta Cloud (fromMe: true): "whatsapp_app"
payload.remotePhonestringNúmero do contato remoto
payload.connectedPhonestringNúmero da instância conectada
payload.textstringTexto da mensagem ou legenda da mídia. String vazia quando não há texto
payload.fileobjectBaileys: { is } quando não há arquivo; { is, name, type, mimeType, size, url } quando há. Meta Cloud: { is, mediaId, mimeType, caption, fileName, url }
payload.groupobject{ is, id } — id é string vazia fora de grupo. Meta Cloud sempre envia { is: false, id: "" }
payload.forwardedobject{ is, score } — o padrão é { is: false, score: 0 }
payload.quotedobject{ is, id } — id é o stanzaId da mensagem citada; o padrão é { is: false, id: "" }
payload.mentionsarrayApenas em Baileys: JIDs mencionados na mensagem
payload.contactsarrayCartões de contato anexados
payload.localizationobjectObjeto vazio quando não há localização; { degreesLatitude, degreesLongitude, live } quando há
payload.statusstringBaileys: received, error, pending, server, delivery, read ou played. Meta Cloud: RECEIVED (entrada) ou SENT (eco)
payload.pushNamestringNome do contato no WhatsApp. Cai para "Unknown" quando indisponível
payload.createdAtstringTimestamp da mensagem em ISO 8601
payload.registryTypestringApenas em Baileys: tipo bruto do evento interno de origem

Example Payload

JSON
{
  "event": "message",
  "datetime": "2026-01-08T14:30:45.000Z",
  "payload": {
    "instance": "507f1f77bcf86cd799439011",
    "code": "9f8b4c21-5d3e-4a17-9c62-2b7e0f5a1d38",
    "message": "3EB0F7C8E2D4A3B1",
    "type": "text",
    "fromMe": false,
    "remotePhone": "551199999000",
    "connectedPhone": "551151183618",
    "text": "Olá, gostaria de informações sobre produtos",
    "file": {
      "is": false
    },
    "group": {
      "is": false,
      "id": ""
    },
    "forwarded": {
      "is": false,
      "score": 0
    },
    "quoted": {
      "is": false,
      "id": ""
    },
    "mentions": [],
    "contacts": [],
    "localization": {},
    "status": "received",
    "pushName": "João Silva",
    "createdAt": "2026-01-08T14:30:45.000Z",
    "registryType": "text"
  }
}
statusMessageURL

Disparado quando o status de entrega de uma mensagem muda. ATENÇÃO: o nome do evento e o formato do payload dependem do provider. Baileys envia event "ack" com um payload mínimo; Meta Cloud envia event "status" com os metadados da Meta (destinatário, conversa, tarifação e erro). Os valores de status também não coincidem entre os dois — não trate o campo como um enum único.

Payload Fields

FieldTypeDescription
eventstring"ack" em instâncias Baileys; "status" em instâncias Meta Cloud
datetimestringMomento do processamento do evento, em ISO 8601
payload.instancestringInstance.id (ObjectId de 24 caracteres)
payload.codestringInstance.code (UUID da instância)
payload.messagestringID da mensagem (wamid em Meta Cloud)
payload.statusstringBaileys: error, pending, server, delivery, read ou played. Meta Cloud: os valores da Meta (sent, delivered, read, failed)
payload.recipientstringSomente Meta Cloud: número do destinatário
payload.timestampnumberSomente Meta Cloud: timestamp Unix informado pela Meta
payload.conversationIdstringSomente Meta Cloud: ID da conversa tarifada
payload.pricingobjectSomente Meta Cloud: dados de tarifação da conversa
payload.errorobjectSomente Meta Cloud: detalhes do erro quando status é failed

Example Payload

JSON
{
  "event": "ack",
  "datetime": "2026-01-08T14:31:00.000Z",
  "payload": {
    "instance": "507f1f77bcf86cd799439011",
    "code": "9f8b4c21-5d3e-4a17-9c62-2b7e0f5a1d38",
    "message": "3EB0F7C8E2D4A3B1",
    "status": "read"
  }
}
connectedURL

Disparado quando a instância conclui a conexão com o WhatsApp. Evento de baixa frequência. O nome do evento é "instance:connected" — com o prefixo instance:, não apenas "connected". O payload traz somente a identificação da instância; para saber o número conectado, consulte GET /instances/:instanceId após receber o evento.

Payload Fields

FieldTypeDescription
eventstringSempre "instance:connected"
datetimestringMomento do evento em ISO 8601
payload.instancestringInstance.id (ObjectId de 24 caracteres)
payload.codestringInstance.code (UUID da instância)

Example Payload

JSON
{
  "event": "instance:connected",
  "datetime": "2026-01-08T14:30:00.000Z",
  "payload": {
    "instance": "507f1f77bcf86cd799439011",
    "code": "9f8b4c21-5d3e-4a17-9c62-2b7e0f5a1d38"
  }
}
disconnectedURL

Disparado quando a instância perde a conexão com o WhatsApp — por logout via API, sessão expirada ou queda de conexão. Evento de baixa frequência. O nome do evento é "instance:disconnected" e o payload NÃO informa o motivo da desconexão: traz apenas a identificação da instância.

Payload Fields

FieldTypeDescription
eventstringSempre "instance:disconnected"
datetimestringMomento do evento em ISO 8601
payload.instancestringInstance.id (ObjectId de 24 caracteres)
payload.codestringInstance.code (UUID da instância)

Example Payload

JSON
{
  "event": "instance:disconnected",
  "datetime": "2026-01-08T15:00:00.000Z",
  "payload": {
    "instance": "507f1f77bcf86cd799439011",
    "code": "9f8b4c21-5d3e-4a17-9c62-2b7e0f5a1d38"
  }
}
templateButtonURL

Disparado quando um contato toca um botão de RESPOSTA RÁPIDA em uma mensagem de template. Exclusivo de instâncias Meta Cloud — instâncias Baileys não enviam template, então a URL nunca produz evento nelas. ATENÇÃO ao limite da plataforma: botões de URL, telefone e copiar código NÃO geram evento algum, porque a Meta não reporta esses toques ao servidor; respostas de Flow também estão fora do escopo. Este é o único webhook assinado da ZapYou: cada requisição traz o cabeçalho X-ZapYou-Signature no formato sha256=<hex>, um HMAC-SHA256 do corpo CRU (antes de qualquer parse) usando o token da instância como chave. Entrega: timeout de 10s e até 4 tentativas com backoff exponencial; diferente dos demais webhooks, qualquer resposta com status maior ou igual a 400 conta como falha e é retentada — se o seu endpoint devolve 401 ao rejeitar uma assinatura, isso aparece como falha de entrega e não como sucesso. Use payload.click.messageId como chave de idempotência.

Payload Fields

FieldTypeDescription
eventstringSempre "template:button"
datetimestringMomento em que a ZapYou processou o clique, em ISO 8601
payload.providerstringSempre "meta_cloud"
payload.click.messageIdstringwamid da mensagem do clique — use como chave de idempotência
payload.click.clickedAtstringMomento do clique informado pela Meta, em ISO 8601
payload.connection.instancestringInstance.id (ObjectId de 24 caracteres)
payload.connection.codestringInstance.code (UUID da instância)
payload.connection.namestringNome da instância na ZapYou
payload.connection.connectedPhonestringNúmero da instância conectada. null quando não cadastrado
payload.connection.phoneNumberIdstringphone_number_id do número na Meta
payload.connection.businessAccountIdstringWABA ID da conta. null quando indisponível
payload.contact.idstringContact.id na ZapYou. null quando o contato não está cadastrado
payload.contact.phonestringTelefone do contato, normalizado
payload.contact.pushNamestringNome do contato no WhatsApp. null quando indisponível
payload.contact.namestringNome cadastrado na ZapYou. null quando o contato não está cadastrado
payload.contact.emailstringE-mail cadastrado. null quando ausente
payload.contact.profilePicUrlstringFoto de perfil. null quando ausente
payload.contact.tagsarrayTags do contato como { id, name, color }. Array vazio quando não há. Campos personalizados (customFields) NÃO são enviados
payload.template.messageIdstringwamid da mensagem de template original. Sempre presente
payload.template.sentAtstringQuando o template foi enviado, em ISO 8601. Presente sempre que o envio deixou registro — inclusive com resolved: false. NÃO use este campo para inferir se o template foi resolvido
payload.template.idstringMetaTemplate.id na ZapYou. null quando resolved é false
payload.template.metaIdstringID do template na Meta. null quando resolved é false
payload.template.namestringNome do template. null quando resolved é false
payload.template.languagestringIdioma do template (ex.: pt_BR). null quando resolved é false
payload.template.categorystringMARKETING, UTILITY ou AUTHENTICATION. null quando resolved é false
payload.template.resolvedbooleanÚNICO campo que indica se o template foi identificado. false quando o envio é anterior à v2.45.0 ou quando o registro não foi encontrado — nesse caso o evento é entregue mesmo assim, com os dados de clique, conexão, contato e botão
payload.button.typestringSempre "QUICK_REPLY" quando identificado. null quando resolved é false
payload.button.textstringRótulo do botão tocado, como veio da Meta. Sempre presente
payload.button.payloadstringPayload do botão. Em disparos de campanha vem como btn_<índice>; nos demais envios a Meta ecoa o próprio rótulo do botão
payload.button.indexnumberPosição do botão no template (base 0). null quando resolved é false ou quando o botão é ambíguo (dois botões com o mesmo rótulo)
payload.context.campaignobject{ id, name } quando o template saiu de uma campanha; null caso contrário. Sempre presente como chave
payload.context.ticketobject{ id, protocol } quando o template pertence a um atendimento; null caso contrário. Sempre presente como chave

Example Payload

JSON
{
  "event": "template:button",
  "datetime": "2026-09-03T14:22:10.000Z",
  "payload": {
    "provider": "meta_cloud",
    "click": {
      "messageId": "wamid.HBgNNTUxMTk5OTk5MDAwFQ",
      "clickedAt": "2026-09-03T14:22:09.000Z"
    },
    "connection": {
      "instance": "507f1f77bcf86cd799439011",
      "code": "9f8b4c21-5d3e-4a17-9c62-2b7e0f5a1d38",
      "name": "Comercial",
      "connectedPhone": "551151183618",
      "phoneNumberId": "123456789012345",
      "businessAccountId": "987654321098765"
    },
    "contact": {
      "id": "6512f8a1b2c3d4e5f6a7b8c9",
      "phone": "551199999000",
      "pushName": "João",
      "name": "João Silva",
      "email": "[email protected]",
      "profilePicUrl": "https://cdn.exemplo.com/joao.jpg",
      "tags": [
        {
          "id": "6512bb00000000000000bb01",
          "name": "Lead quente",
          "color": "#FF5722"
        }
      ]
    },
    "template": {
      "messageId": "wamid.HBgMNTUxMTk5OTk5MDAwFQ",
      "sentAt": "2026-09-03T09:00:00.000Z",
      "id": "6512aa00000000000000aa01",
      "metaId": "123456789012345",
      "name": "promo_setembro",
      "language": "pt_BR",
      "category": "MARKETING",
      "resolved": true
    },
    "button": {
      "type": "QUICK_REPLY",
      "text": "Quero saber mais",
      "payload": "btn_0",
      "index": 0
    },
    "context": {
      "campaign": {
        "id": "6512cc00000000000000cc01",
        "name": "Promo Setembro"
      },
      "ticket": null
    }
  }
}

Códigos de Erro

A API do ZapYou usa códigos de status HTTP convencionais para indicar sucesso ou falha de uma requisição. Códigos na faixa 2xx indicam sucesso, códigos na faixa 4xx indicam erro do cliente, e códigos na faixa 5xx indicam erro do servidor.

CodeStatusNameDescriptionSolution
200SucessoRequisição processada com sucesso
Nenhuma ação necessária
201CriadoRecurso criado. Devolvido apenas por POST /campaigns
Nenhuma ação necessária
(sem code)400Requisição InválidaCampos obrigatórios ausentes ou inválidos nos endpoints de envio e de instância. O corpo traz apenas { message }, ex.: "Invalid fields", "Number not found", "Invalid type. Must be 'PN' or 'LID'"
Confira os campos obrigatórios do endpoint e o formato do número
INVALID_FIELDS400Campos Inválidos (validação Zod)Usado nos endpoints validados por Zod (campanhas, tickets e envio de template). O corpo é { error: "INVALID_FIELDS", details: [...] }, onde details são as issues cruas do Zod (path, code, message) — não há campo message no nível raiz
Percorra details[].path para mapear cada erro ao campo correspondente do formulário
TAG_FILTER_TOO_BROAD400Filtro de Tags Muito AmploNa listagem de tickets, o tagIds enviado casa mais de 5.000 contatos; a requisição é rejeitada, não truncada
Restrinja o filtro (menos tags / tags mais específicas) ou combine com contactId, channelId, departmentId ou um range de datas
(sem code)401Não AutorizadoCobre dois casos distintos: credenciais inválidas (cabeçalhos member/token ausentes ou não conferem; Authorization diferente do token da instância; Bearer de AI Agent inválido ou expirado) E falta de permissão nos endpoints de instância e mensagem, que respondem 401 — não 403 — com { message: "User without permission" }
Verifique o esquema de autenticação do endpoint (são três, incompatíveis entre si) e, se as credenciais estiverem certas, a permissão do grupo do membro
SUBSCRIPTION_REQUIRED402Assinatura NecessáriaPOST /instances/poweron/:instanceId em instância sem subscription ACTIVE ou TRIALING
Regularize a assinatura da instância antes de ligá-la
SUBSCRIPTION_EXPIRED402Assinatura ExpiradaPOST /instances/poweron/:instanceId com o período da assinatura vencido
Renove a assinatura da instância
TRIAL_EXPIRED402Trial ExpiradoPOST /instances/poweron/:instanceId em instância de teste com prazo vencido
Adicione um método de pagamento para converter o trial em assinatura
Insufficient Balance402Saldo de IA InsuficientePOST /aiagents/chat sem saldo de IA na empresa para reservar o custo do embedding ou da geração. É o ÚNICO 402 por saldo da API — os endpoints de envio de mensagem nunca retornam 402
Recarregue o saldo de IA da empresa no painel
(sem code)403Permissão InsuficienteUsado pelos endpoints de campanhas, tickets e lookups. O corpo traz { message: "Insufficient permissions", requiredPermission: "<código>" }, que nomeia exatamente a permissão faltante
Conceda a permissão indicada em requiredPermission ao grupo do membro
Forbidden403Widget DesabilitadoGET /aiagents/widget/config com o widget desativado para o token informado
Habilite o widget para esse token em AI Agents → [Agente] → Tokens
(sem code)404Não EncontradoRecurso inexistente ou pertencente a outra empresa — a API responde 404 nos dois casos, de propósito, para não confirmar a existência de IDs alheios
Confira o ID e se ele pertence à empresa do token
TEMPLATE_NOT_FOUND404Template Não EncontradoO template não existe para essa empresa/idioma (envio via template)
Confira templateName e language; eles precisam bater com um template aprovado
TEMPLATE_NOT_SUPPORTED422Template Não SuportadoA instância é Baileys; templates só funcionam em instâncias Meta Cloud
Use uma instância meta_cloud para enviar via template
TEMPLATE_NOT_APPROVED422Template Não AprovadoO template não está com status APPROVED (veja rejectedReason)
Aguarde aprovação do template na Meta ou ajuste e reenvie para revisão
MISSING_VARIABLES422Variáveis AusentesFaltam variáveis exigidas pelo template (body, header ou buttons)
Use GET /templates/:id → expectedVariables para montar o payload completo
(sem code)422Entidade Não ProcessávelRegra de negócio violada em campanhas, ex.: "One or more instances are invalid" ao associar instâncias que não pertencem à empresa
Verifique os IDs enviados e o estado atual da campanha
(sem code)409ConflitoAção de campanha incompatível com o estado atual ("Campaign already sending") ou reenvio detectado pelo header Idempotency-Key ("Duplicate request")
Consulte o status atual em GET /campaigns/:campaignId antes de repetir a ação
RATE_LIMIT_EXCEEDED429Limite de Taxa ExcedidoMuitas requisições na janela. O corpo traz { error, retryAfter } e, em alguns buckets, message. Os cabeçalhos padrão RateLimit-* acompanham a resposta
Aguarde os segundos indicados em retryAfter e implemente backoff exponencial
(sem code)500Erro Interno do ServidorErro inesperado. A mensagem crua fica no log do servidor, nunca na resposta
Tente novamente mais tarde ou contate o suporte
(sem code)503Instância IndisponívelEndpoints de envio: a instância existe mas o socket não está autenticado no momento (Baileys) ou a instância Meta Cloud não está ativa
Confirme o estado da conexão e, se necessário, desligue e ligue a instância
(sem code)504Timeout de EnvioSem resposta do envio em 30s. Ocorre apenas em POST /instances/send/template/:instanceId
A mensagem pode ter sido enviada mesmo assim — confirme antes de repetir, para não duplicar o disparo

Limites de Taxa

Limites de Requisição

Para garantir a qualidade do serviço para todos os usuários, a API do ZapYou implementa limites de taxa nas requisições. Se você exceder o limite, receberá um erro 429 Too Many Requests.

POST /instances/send/* (texto, imagem, vídeo, áudio, documento e template)

Chave = valor do header Authorization + instanceId da rota. Requisições com o header x-internal-request: true são ignoradas pelo contador

30
Requisições
por minuto
POST /aiagents/chat

Mesmo bucket dos envios de mensagem (30/min, não 60). Chave = o Bearer token do AI Agent

30
Requisições
por minuto
GET /aiagents/agent, /aiagents/sessions/:sessionId, /aiagents/widget/config e DELETE /aiagents/sessions/:sessionId

Bucket geral da API. Chave = o Bearer token do AI Agent

100
Requisições
por minuto
GET /instances, /instances/:instanceId, /templates, /templates/:id, /messages, /messages/:phone e POST /instances/poweron|poweroff|disconnect

Bucket geral da API. A chave é o header Authorization — que estes endpoints NÃO usam (autenticam por member + token). Na prática, portanto, o limite é por IP de origem, compartilhado entre todos os tokens que saem do mesmo IP

100
Requisições
por minuto
Endpoints de campanhas (/campaigns/*), GET /departments e GET /members

Chave = companyId do token. Bucket próprio, que não compete com o dos tickets

60
Requisições
por minuto
GET /tickets/*

Chave = companyId do token. Bucket separado, dimensionado para dashboards com várias widgets

120
Requisições
por minuto
PUT /instances/update/:instanceId, PUT /instances/webhooks/:instanceId e POST /messages/clear-cache

Estes três endpoints não têm rate limit aplicado; ainda assim, use-os com parcimônia

sem limite
Requisições
por