Pular para o conteúdo principal

Configurar

Cadastrando um endpoint​

curl -X POST https://api.joinotify.com/webhook-endpoints \
-H 'Authorization: Bearer sk_live_xxx' \
-H 'Content-Type: application/json' \
-d '{
"name": "producao",
"url": "https://seu-servidor.com/webhooks/joinotify",
"events": ["messages"]
}'
201 Created
{
"data": {
"id": "whe_01J8ZK...",
"name": "producao",
"url": "https://seu-servidor.com/webhooks/joinotify",
"events": ["messages"],
"active": true,
"secret": "whsec_AbCdEf0123456789abcdefgh"
},
"warning": "Store the \"secret\" now — use it to validate the X-Joinotify-Signature-256 header."
}

Diferente das chaves de API, o segredo de webhook pode ser consultado depois:

curl https://api.joinotify.com/webhook-endpoints/whe_01J8ZK.../secret \
-H 'Authorization: Bearer sk_live_xxx'

Requisitos da URL​

Em produção recusamos:

  • http:// — só HTTPS
  • Hosts privados: localhost, 127.*, 10.*, 192.168.*, 169.254.*, 172.16-31.*, *.internal, *.local

É uma proteção contra SSRF: sem ela, um endpoint apontando para a rede interna viraria um scanner.

Para desenvolvimento local, use um túnel:

ngrok http 3000

Filtros​

curl -X POST https://api.joinotify.com/webhook-endpoints \
-H 'Authorization: Bearer sk_live_xxx' \
-H 'Content-Type: application/json' \
-d '{
"name": "atendimento-loja-1",
"url": "https://seu-servidor.com/webhooks/loja-1",
"events": ["messages", "smb_message_echoes"],
"phoneNumberId": "106540352242922"
}'
CampoEfeito
events: []Assina todos os eventos
events: ["messages"]Só o que estiver na lista
wabaIdSó eventos daquela conta empresarial
phoneNumberIdSó eventos daquele número
O filtro por número descarta eventos sem número

Eventos de conta (account_update, account_alerts) e de template (message_template_status_update) não têm número associado. Um endpoint filtrado por phoneNumberId não os recebe.

Se você quer tudo, deixe um endpoint sem filtro.

Vários endpoints​

Nada impede ter mais de um — e costuma ser uma boa ideia:

# Um para o produto
{ "name": "app", "url": "https://app.exemplo.com/webhooks", "events": ["messages"] }

# Outro para auditoria, assinando tudo
{ "name": "auditoria", "url": "https://logs.exemplo.com/webhooks", "events": [] }

Cada endpoint tem seu próprio segredo, sua própria fila e seu próprio contador de falhas. Um endpoint quebrado não afeta os outros.

Testando​

curl -X POST https://api.joinotify.com/webhook-endpoints/whe_01J8ZK.../test \
-H 'Authorization: Bearer sk_live_xxx'

Dispara um evento sintético e entrega na hora, sem passar pela fila. A resposta traz o status HTTP e o corpo que o seu servidor devolveu — é a forma mais rápida de conferir se a validação de assinatura está correta.

{
"data": {
"id": "whd_01J8ZM...",
"status": "delivered",
"responseStatus": 200,
"responseBody": "OK",
"durationMs": 142
}
}

O payload de teste é um evento messages com joinotify_test: true — filtre por esse campo se o seu handler grava tudo no banco.

Atualizando​

curl -X PATCH https://api.joinotify.com/webhook-endpoints/whe_01J8ZK... \
-H 'Authorization: Bearer sk_live_xxx' \
-H 'Content-Type: application/json' \
-d '{ "events": ["messages", "smb_message_echoes", "history"] }'

Campos omitidos ficam como estão. Reativar um endpoint desativado (active: true) zera o contador de falhas.

Pausando e removendo​

# Pausar — preserva histórico e segredo
curl -X PATCH https://api.joinotify.com/webhook-endpoints/whe_01J8ZK... \
-H 'Authorization: Bearer sk_live_xxx' \
-H 'Content-Type: application/json' \
-d '{ "active": false }'

# Remover — descarta as entregas pendentes
curl -X DELETE https://api.joinotify.com/webhook-endpoints/whe_01J8ZK... \
-H 'Authorization: Bearer sk_live_xxx'

Para uma manutenção, pause. Remover é definitivo.

Rotacionando o segredo​

curl -X POST https://api.joinotify.com/webhook-endpoints/whe_01J8ZK.../rotate-secret \
-H 'Authorization: Bearer sk_live_xxx'

A troca é imediata e não há convivência entre os dois segredos. Duas formas de fazer sem perder evento:

Sem downtime — faça o seu handler aceitar dois segredos por um período: valide contra o novo e, se falhar, contra o antigo. Rotacione, confirme, remova o antigo.

Aceitando falhas — rotacione e publique o novo segredo. As entregas que falharem no intervalo são reentregues automaticamente em 60 segundos.