-
Notifications
You must be signed in to change notification settings - Fork 2
API e Webhooks
Guia completo para consumir a API REST e os endpoints de Webhook do Zyra.
No .env:
WA_API_ENABLED=true
WA_API_HOST=0.0.0.0
WA_API_PORT=3000
# opcional (recomendado em produção)
WA_API_KEY=sua-chave
# obrigatório para /webhooks/connections e /connections/:id/webhook/start
WA_WEBHOOK_SHARED_SECRET=segredo-hmac
# obrigatório para cadastro/entrega de webhooks de saída
# (lista CSV exata de URLs permitidas)
WA_WEBHOOK_ALLOWED_TARGETS=https://meu-sistema.com/webhook,https://hooks.exemplo.com/zyraBase URL local (exemplo): http://localhost:3000
- Rotas REST:
Authorization: Bearer <WA_API_KEY>quandoWA_API_KEYestiver configurada. - Exceção:
POST /webhooks/connectionsusa autenticação HMAC própria (não usa Bearer). - Dashboard (
/e/dashboard) é servido sem Bearer.
- Erros seguem formato:
{ "error": "mensagem" }- Sucesso retorna JSON do recurso, exceto endpoints
204 No Content.
-
created: criada, sem socket ativo. -
connecting: conectando. -
qr: aguardando leitura do QR. -
open: conectada/autenticada. -
closed: desconectada. -
error: falha de conexão.
Cria uma instância sem conectar.
Body:
{ "connectionId": "minha-sessao", "label": "Bot Suporte" }Respostas:
-
201: conexão criada. -
400:connectionId é obrigatório. -
409:connectionId já existe.
Lista conexões (runtime + fallback managed).
Respostas:
-
200: array de conexões.
Detalha uma conexão.
Respostas:
-
200: conexão encontrada. -
404:conexão não encontrada.
Atualiza label.
Body:
{ "label": "Novo nome" }Para limpar:
{ "label": null }Respostas:
-
200: conexão atualizada. -
404:conexão não encontrada.
Remove conexão.
Respostas:
-
204: removida. -
404:conexão não encontrada.
Remove a conexão e tenta limpar artefatos persistidos de sessão, incluindo credenciais e estados auxiliares.
Proteções obrigatórias:
- query
?force=true - header
x-zyra-hard-delete-confirm: truequandoWA_WEBHOOK_HARD_DELETE_TOKENnão estiver configurado - header
x-zyra-hard-delete-token: <token>quandoWA_WEBHOOK_HARD_DELETE_TOKENestiver configurado
Exemplo:
curl -s -X DELETE "http://localhost:3000/connections/minha-sessao/hard?force=true" \
-H "Authorization: Bearer sua-chave" \
-H "x-zyra-hard-delete-confirm: true" -iRespostas:
-
204: hard delete concluído. -
403: token adicional inválido. -
404:conexão não encontrada. -
422:forceou confirmação ausente.
Alias: POST /connections/:id/start.
Inicia conexão/socket.
Respostas:
-
200: conexão emconnecting. -
404:conexão não encontrada. -
409:operação indisponível neste processo (WA_BOOTSTRAP_CONNECTIONS_ENABLED=false).
Desconecta.
Respostas:
-
200: status atualizado. -
404:conexão não encontrada. -
409: manager indisponível.
Pausa administrativamente uma conexão: encerra o socket ativo e marca o estado desejado como paused.
Respostas:
-
200: conexão atualizada. -
404:conexão não encontrada. -
409: manager indisponível.
Retoma uma conexão pausada: volta o estado desejado para running e agenda reconexão.
Respostas:
-
200: conexão atualizada. -
404:conexão não encontrada. -
409: manager indisponível.
Alias: POST /connections/:id/reconnect.
Respostas:
-
200: status atualizado (normalmenteconnecting). -
404:conexão não encontrada. -
409: manager indisponível.
Resumo operacional (inclui visão admin).
Respostas:
-
200: status resumido. -
404:conexão não encontrada.
Retorna uma visão consolidada do runtime e do estado administrativo persistido.
Resposta inclui:
-
runtime.socketGeneration,socketActive,reconnectInFlight,qrCodeAvailable,qrCodeAt -
admin.desired_state,pairing_state,last_error,last_disconnect_code -
capabilities.managerCanExecuteRuntimeActions,webhookIngressConfigured
Respostas:
-
200: diagnóstico da conexão. -
404:conexão não encontrada.
Lista eventos administrativos persistidos em connection_admin_events.
Exemplo:
curl -s "http://localhost:3000/connections/minha-sessao/events?limit=50" \
-H "Authorization: Bearer sua-chave" | jqRespostas:
-
200:{ connectionId, count, limit, events }. -
404:conexão não encontrada.
Lista comandos webhook recebidos para a conexão.
Respostas:
-
200:{ connectionId, count, limit, commands }. -
404:conexão não encontrada.
Consulta um comando webhook específico por ID.
Respostas:
-
200: comando encontrado. -
404:comando não encontrado.
Retorna QR atual.
Respostas:
-
200:{ connectionId, qrCode, qrCodeAt }. -
404:conexão não encontradaouQR code não disponível.
Inicia pareamento remoto.
Respostas:
-
202: estado inicial (pending/qr_ready). -
409: manager indisponível.
Cancela pareamento remoto.
Respostas:
-
200: estado final do pairing. -
404:conexão não encontrada. -
409: manager indisponível.
Consulta estado do pairing.
Respostas:
-
200: incluistatus,qrCode,qrUpdatedAt,qrExpiresAt. -
404:conexão não encontrada. -
409: manager indisponível.
Cria/atualiza conexão e despacha comando start via webhook assinado interno.
Body:
{ "label": "Bot Principal" }Respostas:
-
200: comando aceito. -
502: falha ao acionar webhook de conexão. -
503:WA_WEBHOOK_SHARED_SECRETnão configurado.
Pré-condição: conexão deve estar open.
O endpoint aceita dois modos:
- Tipos atalho da API:
text,image,video,audio,document,sticker,contacts,location,react,poll,event,buttonReply,groupInvite,listReply,pin,sharePhoneNumber,requestPhoneNumber,forward,delete,disappearingMessagesInChatelimitSharing. -
type: "raw"para enviar umAnyMessageContentnativo do Baileys quando o payload não tiver atalho próprio.
Campos-base:
| Campo | Obrigatório | Descrição |
|---|---|---|
type |
sim | Tipo da mensagem ou raw
|
to |
sim | JID do destino (@s.whatsapp.net, @g.us ou status@broadcast) |
options |
não | Opções extras do Baileys, como quoted, statusJidList, backgroundColor, font e broadcast
|
Campos principais por tipo:
| Tipo | Campos |
|---|---|
text |
text |
image |
url, caption
|
video |
url, caption, gifPlayback, ptv
|
audio |
url, ptt, seconds
|
document |
url, fileName, mimetype, caption
|
sticker |
url, isAnimated
|
contacts |
contacts.displayName, contacts.contacts[]
|
location |
latitude/longitude ou degreesLatitude/degreesLongitude
|
react |
text, messageKey
|
poll |
name, values[], selectableCount
|
event |
name, startDate, endDate, description, location, call
|
pin |
messageKey, time (86400, 604800 ou 2592000) |
forward |
message, force
|
delete |
messageKey |
disappearingMessagesInChat |
value |
limitSharing |
value |
raw |
content com o payload Baileys completo |
Exemplo text:
{ "type": "text", "to": "5511999999999@s.whatsapp.net", "text": "Olá" }Exemplo de mídia:
{
"type": "document",
"to": "5511999999999@s.whatsapp.net",
"url": "https://exemplo.com/arquivo.pdf",
"fileName": "arquivo.pdf",
"mimetype": "application/pdf"
}Exemplo de status:
{
"type": "text",
"to": "status@broadcast",
"text": "Status enviado pela API",
"options": {
"statusJidList": ["5511999999999", "5511888888888@s.whatsapp.net"],
"backgroundColor": "#102030",
"font": 3
}
}Exemplo raw:
{
"type": "raw",
"to": "5511999999999@s.whatsapp.net",
"content": {
"sharePhoneNumber": true
}
}Respostas:
-
200: resposta bruta dosendMessage(Baileys). -
400: payload inválido/campos obrigatórios. -
404:conexão não encontrada. -
409: instância não conectada ou socket indisponível. -
500: falha ao enviar.
Pré-condição: conexão open.
Respostas:
-
200: mapa de grupos retornado porgroupFetchAllParticipating. -
404:conexão não encontrada. -
409: instância não conectada ou socket indisponível. -
500: falha ao buscar grupos.
Executa ações administrativas em um grupo. O groupJid deve estar no formato ...@g.us e precisa estar URL-encoded quando usado no caminho.
Exemplo:
curl -s -X POST http://localhost:3000/connections/minha-sessao/groups/120363000000000001%40g.us/admin \
-H "Authorization: Bearer sua-chave" \
-H "Content-Type: application/json" \
-d '{"action":"ban","participants":["5511999999999"]}' | jqAções suportadas:
action |
Campos extras | Descrição |
|---|---|---|
add |
participants |
Adiciona participantes |
kick |
participants |
Remove participantes |
remove |
participants |
Alias explícito de remoção |
ban |
participants |
Alias de remoção para banimento |
promote |
participants |
Promove participantes para admin |
demote |
participants |
Remove privilégios de admin |
announcementMode |
enabled: boolean |
Fecha/abre envio de mensagens para membros |
lockedMode |
enabled: boolean |
Trava/libera edição de dados do grupo |
subject |
subject: string |
Atualiza o nome do grupo |
description |
description: string | null |
Atualiza ou limpa a descrição |
ephemeral |
expirationSeconds: number |
Configura mensagens temporárias |
getInviteCode |
nenhum | Retorna código/link atual |
revokeInvite |
nenhum | Revoga convite e retorna o novo |
memberAddMode |
mode: "admin_add" | "all_member_add" |
Define quem pode adicionar membros |
joinApprovalMode |
mode: "on" | "off" |
Liga/desliga aprovação de entrada |
listJoinRequests |
nenhum | Lista solicitações pendentes |
approveJoinRequests |
participants |
Aprova solicitações pendentes |
rejectJoinRequests |
participants |
Rejeita solicitações pendentes |
participants aceita string única, CSV ou array. Números sem sufixo são normalizados para @s.whatsapp.net.
Respostas:
-
200:{ ok: true, action, ... }. -
400:groupJidinválido, body inválido ou campo obrigatório ausente. -
404:conexão não encontrada. -
409: instância não conectada ou socket indisponível. -
500: falha na ação administrativa.
Antes de criar webhooks, configure WA_WEBHOOK_ALLOWED_TARGETS com os destinos autorizados.
Sem isso, a API retorna erro: nenhum destino autorizado configurado. defina WA_WEBHOOK_ALLOWED_TARGETS.
Cria webhook de uma conexão.
Body:
{
"url": "https://meu-sistema.com/webhook",
"eventsFilter": ["messages", "connection.update"],
"secret": "segredo-opcional"
}eventsFilter aceita:
*- eventos diretos:
connection.update,messages.upsert,messages.update,messages.delete,message-receipt.update,messages.reaction,groups.upsert,groups.update,group-participants.update - grupos:
connection,messages,groups
Respostas:
-
201: webhook criado. -
400: body inválido,urlinválida,eventsFiltervazio ou URL não permitida. -
500: falha ao criar.
Lista webhooks da conexão.
Respostas:
-
200: array de webhooks.
Respostas:
-
200: webhook. -
404:webhook não encontrado.
Body parcial:
{
"url": "https://novo-endpoint.com/hook",
"eventsFilter": ["messages.upsert"],
"active": true,
"secret": null
}Respostas:
-
200: webhook atualizado. -
400: body/url inválido(a). -
404:webhook não encontrado.
Respostas:
-
204: removido. -
404:webhook não encontrado.
Lista histórico de entregas.
Respostas:
-
200: array de entregas. -
404:webhook não encontrado.
Força nova tentativa de entrega.
Respostas:
-
200: entrega atualizada. -
404: webhook ou entrega não encontrada. -
500: falha ao retentar.
Mesmo contrato dos webhooks por conexão, mas para todas as conexões:
GET /webhooksPOST /webhooksGET /webhooks/:webhookIdPATCH /webhooks/:webhookIdDELETE /webhooks/:webhookIdGET /webhooks/:webhookId/deliveriesPOST /webhooks/:webhookId/deliveries/:deliveryId/retry
Formato:
{
"event": "messages.upsert",
"connectionId": "minha-sessao",
"timestamp": 1780000000000,
"data": {}
}Headers de entrega:
content-type: application/jsonx-webhook-event: <nome-do-evento>x-webhook-delivery: <id-da-entrega>-
x-webhook-signature: sha256=<hmac>quandosecretfoi configurado no webhook.
Status de entrega persistido:
pendingdeliveredfaileddead_letter
Endpoint:
POST /webhooks/connections
Headers obrigatórios:
content-type: application/jsonx-zyra-timestampx-zyra-signaturex-zyra-delivery-id
Regra da assinatura:
- HMAC SHA-256 sobre
"<timestamp>.<rawBody>"usandoWA_WEBHOOK_SHARED_SECRET. - Aceita
x-zyra-signaturecom ou sem prefixosha256=.
Payload:
{
"event": "connection.command",
"version": "2026-05-27",
"command_id": "uuid",
"sent_at": "2026-05-30T16:00:00.000Z",
"connection": { "id": "minha-sessao", "display_name": "Bot X" },
"action": { "type": "start", "reason": "dashboard.qr" },
"options": { "force": false },
"metadata": { "source": "sistema-externo" }
}Ações válidas (action.type):
registerstartreconnectdisconnectpauseresumedelete_softdelete_hardsync_statuspairing_startpairing_cancel
Resposta de sucesso:
{
"ok": true,
"command_id": "uuid",
"connection_id": "minha-sessao",
"accepted": true,
"action": "start",
"current_state": "connecting",
"desired_state": "running"
}Regras importantes:
- Idempotência por
command_id(duplicado pode retornarduplicate: true). -
delete_hardexigeoptions.force=true. - Sem
WA_WEBHOOK_HARD_DELETE_TOKEN, também exige headerx-zyra-hard-delete-confirm=true. - Com
WA_WEBHOOK_HARD_DELETE_TOKEN, exigex-zyra-hard-delete-tokenigual ao token configurado.
Erros comuns:
-
400: payload/event/fields inválidos. -
401: headers de auth ausentes, timestamp inválido/fora da janela, assinatura inválida. -
405: método diferente dePOST. -
413: payload acima do limite. -
415: content-type inválido. -
422: ação inválida ou regra de hard delete não atendida. -
500: erro interno ao processar comando.
Retorna perfil e capacidades do processo:
-
profile:full,connections-only,api-webhook,stateless -
capabilities,api,webhook,process
Liveness simples do processo.
Resposta:
-
200:{ ok: true, live: true, now, uptime_sec }
Readiness (MySQL/Redis/control-plane).
Respostas:
-
200: pronto. -
503: dependência não pronta.
Resumo por conexão + contadores agregados (open, connecting, paused, error).
Quando WA_BOOTSTRAP_CONNECTIONS_ENABLED=false, o processo atende API/webhooks, mas não controla sockets locais.
Nesse modo:
-
POST /connections,PATCH /connections/:id,DELETE /connections/:id,GET /connectionseGET /connections/:idoperam sobre o registro managed persistido. -
GET /connections/:id/status,GET /connections/:id/diagnostics,GET /connections/:id/eventseGET /connections/:id/commandscontinuam úteis para leitura operacional. -
POST /connections/:id/connect,/disconnect,/pause,/resume,/restart,/pairing/start,/pairing/cancele/qrdependem do manager local e podem retornar409. - Para iniciar uma conexão a partir do processo API/webhook, use
POST /connections/:id/webhook/start, que despacha comando assinado para o ingress interno.
POST /connectionsPOST /connections/:id/connect- Poll em
GET /connections/:id/qraté vir200comqrCode - Poll em
GET /connections/:id/statusatéstatus=open POST /connections/:id/messages/send
BASE="http://localhost:3000"
TOKEN="sua-chave"
ID="sessao-demo"
curl -s -X POST "$BASE/connections" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"connectionId\":\"$ID\"}" | jq
curl -s -X POST "$BASE/connections/$ID/connect" \
-H "Authorization: Bearer $TOKEN" | jq
curl -s "$BASE/connections/$ID/qr" \
-H "Authorization: Bearer $TOKEN" | jqZyra Wiki • Última atualização: 17/05/2026
Home | Configuração | Comandos | Banco-de-Dados | Produção | Troubleshooting