Webhooks

Receba os eventos do workspace no seu servidor, assinados no padrão Standard Webhooks.

Um endpoint de webhook recebe um POST a cada evento que ele assina. Crie endpoints em Configurações → Desenvolvedores → Webhooks (Owner ou Admin) ou com POST /v1/webhooks:

curl https://app.zaplin.com.br/api/v1/webhooks \
  -X POST \
  -H "Authorization: Bearer $ZAPLIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Meu CRM", "url": "https://seuapp.com/zaplin", "events": ["message.received", "stage.changed"]}'
201 Created
{ "id": "…", "secret": "whsec_…" }

O secret assina as entregas e só aparece uma vez. Não há como vê-lo depois: se você o perder, rotacione a chave para receber outra.

O endereço tem que ser HTTPS e público: sem usuário e senha, sem IP, sem localhost e sem domínios .local, .internal ou .localhost.

Eventos

EventoQuando
message.receivedChega uma mensagem de um contato (não de grupo)
message.sentUma mensagem para um contato sai com sucesso, de uma pessoa, automação, campanha, lembrete ou da API
conversation.closedUma conversa é fechada na caixa de entrada ou por uma automação
contact.createdUm contato é criado: à mão, pela API, por formulário, importação, primeira mensagem ou automação
stage.changedUm negócio muda de etapa no pipeline, por uma pessoa ou por uma automação
automation.failedUma execução de automação termina com falha

A entrega

Toda entrega segue a especificação Standard Webhooks: um POST com Content-Type: application/json e três cabeçalhos.

POST /zaplin HTTP/1.1
content-type: application/json
webhook-id: evt_3f9a1c2b7d4e5f60
webhook-timestamp: 1792242191
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
CabeçalhoO que é
webhook-idO id do evento, evt_…: o mesmo em todas as tentativas e reenvios, igual ao id do corpo
webhook-timestampQuando esta tentativa saiu, em segundos Unix; muda a cada tentativa
webhook-signatureUma ou mais v1,<assinatura>, separadas por espaço. Veja a verificação
{
  "id": "evt_3f9a1c2b7d4e5f60",
  "type": "message.received",
  "version": 1,
  "timestamp": "2026-10-17T14:03:11.512Z",
  "organization_id": "…",
  "data": {
    "message": { "id": "…", "text": "Oi, quero saber o preço" },
    "contact": { "name": "Maria Silva", "phone": "+5511987654321" },
    "number": { "id": "…" },
    "contact_id": "…",
    "conversation_id": "…",
    "number_id": "…"
  }
}
CampoO que é
idO id do evento, igual ao webhook-id
typeO evento, da tabela acima
versionA versão do envelope: 1
timestampQuando o evento aconteceu, em ISO 8601 e UTC
organization_idO workspace
dataO que é próprio do evento. Sempre traz contact_id, conversation_id e number_id, que são null quando o evento não tem esse dado

O data de cada evento

source diz quem enviou: member, automation, campaign, reminder, api, system ou phone.

{
  "message": { "id": "…", "text": "Olá!" },
  "contact": { "name": "Maria Silva", "phone": "+5511987654321" },
  "number": { "id": "…" },
  "source": "member",
  "contact_id": "…",
  "conversation_id": "…",
  "number_id": "…"
}

Resposta e novas tentativas

Responda com qualquer 2xx em até 10 segundos. O corpo da sua resposta é ignorado; guardamos os primeiros 500 caracteres para você ver na página do endpoint. Redirecionamentos não são seguidos: contam como falha.

Qualquer outra resposta, ou nenhuma, é uma falha, e a entrega é tentada de novo com espera exponencial a partir de 30 segundos (30 s, 1 min, 2 min, 4 min…): até 12 tentativas, dentro de 24 horas. Depois disso, a entrega fica failed. Se o endereço resolver para um IP privado, ou o DNS falhar, a entrega fica blocked e não é tentada de novo. O endpoint nunca é desligado por falhas.

  • Idempotência: o webhook-id (o id do corpo) é o mesmo em todas as tentativas e reenvios de um evento. Guarde os ids que você já processou e ignore as repetições.
  • Ordem: as entregas podem chegar fora de ordem. Use o timestamp e leia o estado atual pela API quando a ordem importar.
  • Pausa: Pausar entregas, na página do endpoint, guarda os eventos que acontecem nesse meio-tempo; Retomar entregas envia tudo o que ficou guardado.
  • Reenvio: na página do endpoint você vê as últimas 50 entregas (status, código, duração, tentativas e a próxima). Reativar envia uma entrega de novo e Reenviar falhas todas as que ainda falham, na hora, com o mesmo id e corpo. O histórico fica guardado por 30 dias.

Verifique a assinatura

Cada assinatura em webhook-signature é v1, seguido do HMAC-SHA256 em base64 de {webhook-id}.{webhook-timestamp}.{corpo}, sobre o corpo bruto. A chave do HMAC é a parte do segredo depois de whsec_, decodificada de base64. Durante uma rotação chegam duas assinaturas: aceite a entrega quando qualquer uma bater. Recuse um webhook-timestamp com mais de 5 minutos de diferença do seu relógio, contra replays.

As bibliotecas oficiais do Standard Webhooks fazem tudo isso:

// npm install standardwebhooks
import { Webhook } from "standardwebhooks"

const webhook = new Webhook(process.env.ZAPLIN_WEBHOOK_SECRET!) // "whsec_…"

// Um route handler do Next.js: leia o corpo como texto, antes de qualquer parse.
export async function POST(request: Request) {
  const body = await request.text()
  let event
  try {
    // Confere as assinaturas e a janela de 5 minutos; devolve o corpo já lido.
    event = webhook.verify(body, Object.fromEntries(request.headers))
  } catch {
    return new Response(null, { status: 401 })
  }
  // ... trate event.type e event.data, ignorando ids já vistos
  return new Response(null, { status: 204 })
}

Use o corpo bruto

Calcule o HMAC sobre os bytes recebidos, antes de qualquer parse. Um JSON serializado de novo não bate com a assinatura.

Rotacionar a chave

Na página do endpoint, Rotacionar chave gera uma chave nova e a mostra uma vez. A chave anterior continua assinando por 24 horas: nesse tempo o webhook-signature traz duas assinaturas, a da chave nova primeiro, e o seu sistema aceita a entrega com qualquer uma das chaves. Depois, só a chave nova assina.

  1. Clique em Rotacionar chave e copie a chave nova.
  2. Troque a chave no seu sistema e publique, dentro de 24 horas.
  3. Pronto: depois de 24 horas a chave anterior deixa de assinar.

Perdeu a chave? Rotacione para receber outra.

Limites

O plano limita os endpoints de um workspace: 2 no Essencial, 10 no Profissional e 30 no Escala. Acima disso, POST /v1/webhooks recebe 409 com quota.

Nesta página