Configure webhooks de saída para receber notificações em tempo real do Zenovay quando ocorrerem eventos da plataforma e aprenda como o Zenovay processa internamente os webhooks de pagamento de entrada.
Webhooks de Saída
O Zenovay oferece suporte a webhooks de saída configuráveis pelo usuário, para que seus serviços possam reagir aos eventos da plataforma assim que acontecerem, em vez de fazer polling na API em busca de mudanças.
Disponibilidade por plano
O gerenciamento de webhooks de saída através da API requer um token de API pessoal, e tokens de API são uma funcionalidade paga. Eles estão disponíveis a partir do plano Pro e superiores (planos Free não podem criar tokens de API). Crie um token em Settings → Account → Security & access (app.zenovay.com/settings/account/security). Os webhooks estão limitados à equipe à qual esse token pertence.
Criando um webhook
Os webhooks são gerenciados em /v1/cli/mutate/webhooks na API do Zenovay. Passe a url de destino (deve ser https://) e pelo menos um tipo de evento. Crie um com uma requisição POST:
curl -X POST https://api.zenovay.com/v1/cli/mutate/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url":"https://yoursite.com/zenovay-hook","events":["traffic_spike"]}'
A resposta inclui o id do webhook e um secret de assinatura. O secret é retornado somente na criação — armazene-o em um local seguro imediatamente. Se você perdê-lo, rotacione o secret (veja abaixo); o original não pode ser recuperado.
Listando webhooks
curl https://api.zenovay.com/v1/cli/mutate/webhooks \
-H "Authorization: Bearer YOUR_TOKEN"
Verificando assinaturas de webhook
Cada entrega de webhook é assinada com HMAC usando o secret de assinatura obtido na criação. Verifique a assinatura no seu endpoint antes de confiar no payload e use uma comparação de tempo constante para que a verificação não fique vulnerável a ataques de temporização:
import crypto from 'crypto';
function verifyZenovayWebhook(rawBody, signatureHeader, secret) {
// The signature header value is prefixed with the algorithm,
// e.g. "sha256=<hex>". Strip the prefix before comparing.
const received = (signatureHeader || '').replace(/^sha256=/, '');
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
// timingSafeEqual throws if the buffers differ in length, so
// length-check first, then compare in constant time.
if (expected.length !== received.length) return false;
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(received)
);
}
Sempre valide o corpo bruto da requisição (os bytes exatos recebidos), não uma versão reserializada, para que a assinatura que você calcula corresponda à que o Zenovay calculou.
O nome exato do header que carrega a assinatura está documentado na Referência da API REST.
Testando um webhook
Envie uma entrega de teste sintética para confirmar que seu endpoint está configurado corretamente. A resposta inclui o resultado da tentativa de entrega (status HTTP do seu endpoint e tempo):
curl -X POST https://api.zenovay.com/v1/cli/mutate/webhooks/{id}/test \
-H "Authorization: Bearer YOUR_TOKEN"
Rotacionando o secret de assinatura
Se um secret vazar ou se você quiser rotacioná-lo periodicamente, faça isso. O novo secret é retornado apenas uma vez na resposta:
curl -X POST https://api.zenovay.com/v1/cli/mutate/webhooks/{id}/rotate \
-H "Authorization: Bearer YOUR_TOKEN"
Após a rotação, atualize seu endpoint para verificar com o novo secret. As assinaturas antigas param de validar imediatamente.
Revogando um webhook
curl -X DELETE https://api.zenovay.com/v1/cli/mutate/webhooks/{id} \
-H "Authorization: Bearer YOUR_TOKEN"
Webhooks revogados param de receber entregas imediatamente. A revogação não pode ser desfeita.
Melhores práticas
- Responda com 2xx o mais rápido possível. Confirme primeiro e depois processe o evento em um job em segundo plano.
- Seja idempotente. Novas tentativas de rede podem fazer com que o mesmo evento chegue mais de uma vez — indexe seu handler pelo id do evento, não pelo horário de recebimento.
- Verifique antes de confiar. Rejeite qualquer requisição cujo HMAC não valide e rejeite requisições cujo timestamp esteja muito fora de uma janela aceitável.
- Rotacione secrets se alguém de fora da equipe teve acesso à sua configuração ou aos logs de webhooks.
Webhooks de Pagamento de Entrada
O Zenovay também processa webhooks de entrada de serviços externos para gerenciar assinaturas e infraestrutura. Eles são executados dentro da plataforma Zenovay e não requerem nenhuma configuração da sua parte.
Fontes de webhooks de entrada
| Fonte | Finalidade |
|---|---|
| Stripe | Gerenciamento de assinaturas, processamento de pagamentos, conclusão de checkout |
| Monitoramento de Uptime | Acionamentos de health-check por serviços externos de monitoramento |
Alternativas por polling
Se os webhooks de saída não atenderem ao seu caso de uso (por exemplo, você precisa de agregados pontuais em vez de um fluxo de eventos), você ainda pode criar integrações em tempo real fazendo polling na External API.
A External API também é uma funcionalidade paga — requer uma chave de API, e planos Free não incluem acesso API. Os endpoints abaixo retornam a envoltura padrão { success, data, timestamp }, então seu payload fica sob data.
Polling com a External API
const API_KEY = process.env.ZENOVAY_API_KEY;
const WEBSITE_ID = process.env.ZENOVAY_WEBSITE_ID;
async function checkAnalytics() {
const response = await fetch(
`https://api.zenovay.com/api/external/v1/analytics/${WEBSITE_ID}?range=24h`,
{
headers: { 'X-API-Key': API_KEY }
}
);
const { data } = await response.json();
if (data.summary.total_visitors > threshold) {
await sendSlackNotification(data);
}
}
// Poll every 5 minutes
setInterval(checkAnalytics, 5 * 60 * 1000);
O parâmetro range aceita 24h, 7d, 30d, 90d ou 1y (padrão é 7d).
Contagem de visitantes ao vivo
Use o endpoint público de visitantes ao vivo para verificar a contagem atual sem uma chave de API:
async function getLiveVisitors(trackingCode) {
const response = await fetch(
`https://api.zenovay.com/e/live/${trackingCode}`
);
return await response.json();
}
Exemplo de integração com Slack
Crie um relatório agendado que publica no Slack:
async function sendDailyReport() {
const response = await fetch(
`https://api.zenovay.com/api/external/v1/analytics/${WEBSITE_ID}?range=24h`,
{
headers: { 'X-API-Key': API_KEY }
}
);
const { data } = await response.json();
const { summary } = data;
await fetch(SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `Daily Analytics Report:\n` +
`Visitors: ${summary.total_visitors}\n` +
`Unique Visitors: ${summary.unique_visitors}\n` +
`Page Views: ${summary.total_page_views}`
})
});
}
Exemplo de integração com CRM
Sincronize dados de analytics com seu CRM em um cronograma:
async function syncToCRM() {
const response = await fetch(
`https://api.zenovay.com/api/external/v1/analytics/${WEBSITE_ID}/visitors`,
{
headers: { 'X-API-Key': API_KEY }
}
);
const { data } = await response.json();
for (const visitor of data.visitors) {
await crm.contacts.update({
country: visitor.country_name,
city: visitor.city,
last_seen: visitor.visited_at
});
}
}
Limites de Taxa para Polling
Ao criar integrações com polling, respeite os limites de taxa da External API:
| Plano | Requisições/Minuto | Limite Mensal |
|---|---|---|
| Free | 10 | 1.000 |
| Pro | 30 | 10.000 |
| Scale | 60 | 100.000 |
| Enterprise | 120 | 1.000.000 |
Melhores práticas de polling
- Armazene em cache as respostas da API localmente para reduzir a frequência de requisições
- Use intervalos de polling adequados (mínimo de 5 minutos recomendado)
- Monitore o header
X-RateLimit-Remainingpara evitar atingir os limites - Implemente backoff exponencial se receber respostas 429