Webhooks
Webhooks permitem que você receba callbacks HTTP em tempo real quando eventos ocorrem nas suas instâncias WhatsApp. Em vez de fazer polling na API, a Wappfy envia os eventos para o seu servidor conforme eles acontecem.
Eventos Suportados
A Wappfy suporta 12 tipos de eventos de webhook:
Evento Descrição message.receivedUma nova mensagem de entrada foi recebida. message.sentUma mensagem de saída foi enviada com sucesso. message.deliveredUma mensagem enviada foi entregue no dispositivo do destinatário (duplo check). message.readUma mensagem enviada foi lida pelo destinatário (checks azuis). message.failedUma mensagem de saída falhou no envio. message.reactionAlguém reagiu a uma mensagem com um emoji.
Evento Descrição instance.connectedUma instância se conectou ao WhatsApp com sucesso. instance.disconnectedUma instância perdeu a conexão com o WhatsApp. instance.qrUm novo QR code está disponível para escaneamento.
Eventos de Grupo e Contato
Evento Descrição group.joinedUm participante entrou em um grupo (incluindo o próprio bot). group.leftUm participante saiu de um grupo. contact.createdUm novo contato foi salvo ou detectado.
Criar um Webhook
Registre um endpoint de webhook para começar a receber eventos.
curl -X POST https://api.wappfy.io/api/webhooks \
-H "X-Api-Key: SUA_CHAVE_API" \
-H "Content-Type: application/json" \
-d '{
"url": "https://seu-servidor.com/webhooks/wappfy",
"events": ["message.received", "message.sent", "message.delivered"],
"instance_id": "inst_abc123",
"secret": "whsec_meu_segredo_assinatura",
"retry_count": 3,
"timeout_ms": 10000
}'
Resposta:
{
"data" : {
"id" : "wh_xyz789" ,
"url" : "https://seu-servidor.com/webhooks/wappfy" ,
"events" : [ "message.received" , "message.sent" , "message.delivered" ],
"instance_id" : "inst_abc123" ,
"is_active" : true ,
"retry_count" : 3 ,
"timeout_ms" : 10000 ,
"created_at" : "2026-02-10T12:00:00Z"
}
}
Opções de Configuração
Campo Tipo Padrão Descrição urlstring obrigatório A URL HTTPS que receberá as requisições POST do webhook. eventsstring[] obrigatório Array de tipos de evento para assinar. instance_idstring nullLimite o webhook a uma instância específica. Se nulo, recebe eventos de todas as instâncias. secretstring nullSegredo usado para gerar assinaturas HMAC para verificação do payload. retry_countnumber 3Número de tentativas de reenvio em caso de falha (0-5). timeout_msnumber 10000Timeout da requisição em milissegundos (1000-30000).
O campo instance_id é opcional. Se omitido, o webhook receberá eventos de todas as instâncias da sua conta.
Listar Webhooks
curl https://api.wappfy.io/api/webhooks \
-H "X-Api-Key: SUA_CHAVE_API"
Resposta:
{
"data" : [
{
"id" : "wh_xyz789" ,
"url" : "https://seu-servidor.com/webhooks/wappfy" ,
"events" : [ "message.received" , "message.sent" , "message.delivered" ],
"instance_id" : "inst_abc123" ,
"is_active" : true ,
"retry_count" : 3 ,
"timeout_ms" : 10000
}
]
}
Atualizar um Webhook
Atualize a URL, eventos ou configuração de um webhook existente.
curl -X PATCH https://api.wappfy.io/api/webhooks/wh_xyz789 \
-H "X-Api-Key: SUA_CHAVE_API" \
-H "Content-Type: application/json" \
-d '{
"events": ["message.received", "message.sent", "message.delivered", "message.read"],
"is_active": true
}'
Excluir um Webhook
curl -X DELETE https://api.wappfy.io/api/webhooks/wh_xyz789 \
-H "X-Api-Key: SUA_CHAVE_API"
Quando um evento ocorre, a Wappfy envia uma requisição POST para a URL do seu webhook com a seguinte estrutura:
{
"id" : "dlv_abc123def456" ,
"event" : "message.received" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T14:30:00Z" ,
"data" : {
"message_id" : "BAE5F2C4D3B2A1" ,
"chat_id" : "5511999998888@s.whatsapp.net" ,
"from" : "5511999998888@s.whatsapp.net" ,
"type" : "text" ,
"text" : "Olá!" ,
"timestamp" : "2026-02-10T14:30:00Z"
}
}
Campos do Payload
Campo Descrição idID único de entrega. Use para deduplicação. eventO tipo de evento que disparou esta entrega. instance_idA instância que gerou o evento. timestampTimestamp ISO 8601 de quando o evento ocorreu. dataPayload específico do evento. O conteúdo varia por tipo de evento.
Verificação de Assinatura HMAC
Se você fornecer um secret ao criar um webhook, cada entrega incluirá um header X-Wappfy-Signature contendo uma assinatura HMAC-SHA256 do corpo da requisição.
Sempre verifique esta assinatura para garantir que a requisição veio da Wappfy e não foi adulterada.
Exemplos de Verificação
Node.js (Express)
Python (Flask)
const crypto = require ( "crypto" );
function verificarAssinaturaWebhook ( req , secret ) {
const signature = req . headers [ "x-wappfy-signature" ];
if ( ! signature ) return false ;
const expectedSignature = crypto
. createHmac ( "sha256" , secret )
. update ( JSON . stringify ( req . body ))
. digest ( "hex" );
return crypto . timingSafeEqual (
Buffer . from ( signature ),
Buffer . from ( expectedSignature )
);
}
// Middleware Express
app . post ( "/webhooks/wappfy" , ( req , res ) => {
const isValid = verificarAssinaturaWebhook ( req , "whsec_meu_segredo_assinatura" );
if ( ! isValid ) {
return res . status ( 401 ). json ({ error: "Assinatura inválida" });
}
const { event , data } = req . body ;
console . log ( `Evento recebido: ${ event } ` , data );
// Sempre responda com 200 rapidamente para evitar retentativas
res . status ( 200 ). json ({ received: true });
});
Sempre use comparação em tempo constante (como timingSafeEqual ou hmac.compare_digest) ao verificar assinaturas para prevenir ataques de temporização.
Comportamento de Retentativas
Se o seu servidor não responder com um código de status 2xx dentro do timeout_ms configurado, a Wappfy tentará reenviar a entrega.
Tentativa Atraso 1a retentativa 10 segundos 2a retentativa 60 segundos 3a retentativa 5 minutos 4a retentativa 30 minutos 5a retentativa 2 horas
As retentativas param quando uma resposta 2xx é recebida ou o retry_count é esgotado. O número padrão de retentativas é 3.
Visualizando o Histórico de Entregas
Consulte o log de entregas de um webhook para ver tentativas passadas e seus resultados.
curl https://api.wappfy.io/api/webhooks/wh_xyz789/deliveries \
-H "X-Api-Key: SUA_CHAVE_API"
Resposta:
{
"data" : [
{
"id" : "dlv_abc123def456" ,
"event" : "message.received" ,
"status" : "delivered" ,
"http_status" : 200 ,
"attempts" : 1 ,
"created_at" : "2026-02-10T14:30:00Z" ,
"delivered_at" : "2026-02-10T14:30:01Z"
},
{
"id" : "dlv_ghi789jkl012" ,
"event" : "message.sent" ,
"status" : "failed" ,
"http_status" : 500 ,
"attempts" : 3 ,
"created_at" : "2026-02-10T14:31:00Z" ,
"last_error" : "Servidor retornou 500 Internal Server Error"
}
]
}
Exemplos de Payload por Evento
{
"id" : "dlv_abc123" ,
"event" : "message.received" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T14:30:00Z" ,
"data" : {
"message_id" : "BAE5F2C4D3B2A1" ,
"chat_id" : "5511999998888@s.whatsapp.net" ,
"from" : "5511999998888@s.whatsapp.net" ,
"type" : "text" ,
"text" : "Olá, preciso de ajuda com meu pedido" ,
"timestamp" : "2026-02-10T14:30:00Z"
}
}
{
"id" : "dlv_def456" ,
"event" : "message.delivered" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T14:30:05Z" ,
"data" : {
"message_id" : "BAE5A1B2C3D4E5" ,
"chat_id" : "5511999998888@s.whatsapp.net" ,
"status" : "delivered"
}
}
{
"id" : "dlv_ghi789" ,
"event" : "message.read" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T14:31:00Z" ,
"data" : {
"message_id" : "BAE5A1B2C3D4E5" ,
"chat_id" : "5511999998888@s.whatsapp.net" ,
"status" : "read"
}
}
{
"id" : "dlv_jkl012" ,
"event" : "message.reaction" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T14:32:00Z" ,
"data" : {
"message_id" : "BAE5F2C4D3B2A1" ,
"chat_id" : "5511999998888@s.whatsapp.net" ,
"from" : "5511999998888@s.whatsapp.net" ,
"reaction" : " \u2764\ufe0f "
}
}
{
"id" : "dlv_uvw234" ,
"event" : "message.failed" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T14:33:00Z" ,
"data" : {
"message_id" : "BAE5X1Y2Z3W4V5" ,
"chat_id" : "5511999998888@s.whatsapp.net" ,
"error" : "Número não encontrado no WhatsApp"
}
}
{
"id" : "dlv_xyz567" ,
"event" : "message.sent" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T14:30:02Z" ,
"data" : {
"message_id" : "BAE5A1B2C3D4E5" ,
"chat_id" : "5511999998888@s.whatsapp.net" ,
"type" : "text" ,
"text" : "Sua resposta automática" ,
"status" : "sent"
}
}
{
"id" : "dlv_mno345" ,
"event" : "instance.connected" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T12:00:00Z" ,
"data" : {
"instance_id" : "inst_abc123" ,
"status" : "connected" ,
"phone_number" : "5511999998888"
}
}
{
"id" : "dlv_abc890" ,
"event" : "instance.disconnected" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T18:00:00Z" ,
"data" : {
"instance_id" : "inst_abc123" ,
"status" : "disconnected" ,
"reason" : "Sessão encerrada pelo dispositivo principal"
}
}
{
"id" : "dlv_pqr678" ,
"event" : "instance.qr" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T11:59:00Z" ,
"data" : {
"instance_id" : "inst_abc123" ,
"qr" : "data:image/png;base64,iVBORw0KGgo..."
}
}
{
"id" : "dlv_stu901" ,
"event" : "group.joined" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T15:00:00Z" ,
"data" : {
"group_id" : "120363012345678901@g.us" ,
"participant" : "5511888887777@s.whatsapp.net"
}
}
{
"id" : "dlv_def234" ,
"event" : "group.left" ,
"instance_id" : "inst_abc123" ,
"timestamp" : "2026-02-10T16:00:00Z" ,
"data" : {
"group_id" : "120363012345678901@g.us" ,
"participant" : "5511888887777@s.whatsapp.net"
}
}
Boas Práticas
Responda rapidamente Retorne um status 200 em até 5 segundos. Processe o evento de forma assíncrona para evitar timeouts.
Deduplique Use o id da entrega para detectar e ignorar entregas duplicadas causadas por retentativas.
Verifique assinaturas Sempre valide o header X-Wappfy-Signature se você configurou um segredo.
Use HTTPS URLs de webhook devem usar HTTPS. Endpoints HTTP serão rejeitados.