Configurez des webhooks sortants pour recevoir des notifications en temps réel de Zenovay lorsque des événements de la plateforme se produisent, et découvrez comment Zenovay gère en interne les webhooks de paiement entrants.
Webhooks sortants
Zenovay prend en charge des webhooks sortants configurables par l'utilisateur, afin que vos services puissent réagir aux événements de la plateforme dès qu'ils se produisent, plutôt que d'interroger l'API pour détecter les changements.
Disponibilité par plan
La gestion des webhooks sortants via l'API nécessite un token API personnel, et les tokens API sont une fonctionnalité payante. Ils sont disponibles à partir du plan Pro et au-delà (les plans Free ne peuvent pas créer de tokens API). Créez un token sous Settings → Account → Security & access (app.zenovay.com/settings/account/security). Les webhooks sont limités à l'équipe à laquelle appartient ce token.
Créer un webhook
Les webhooks sont gérés sous /v1/cli/mutate/webhooks sur l'API Zenovay. Passez l'url de destination (doit être https://) et au moins un type d'événement. Créez-en un avec une requête 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"]}'
La réponse contient l'id du webhook et un secret de signature. Le secret est renvoyé uniquement à la création — stockez-le immédiatement dans un endroit sûr. Si vous le perdez, faites tourner le secret (voir ci-dessous) ; l'original ne peut pas être récupéré.
Lister les webhooks
curl https://api.zenovay.com/v1/cli/mutate/webhooks \
-H "Authorization: Bearer YOUR_TOKEN"
Vérifier les signatures de webhook
Chaque livraison de webhook est signée HMAC à l'aide du secret de signature obtenu lors de la création. Vérifiez la signature sur votre endpoint avant de faire confiance au payload, et utilisez une comparaison à temps constant afin que la vérification ne soit pas vulnérable aux attaques temporelles :
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)
);
}
Validez toujours le corps brut de la requête (les octets exacts reçus), et non une version re-sérialisée, afin que la signature que vous calculez corresponde à celle que Zenovay a calculée.
Le nom exact de l'en-tête qui transporte la signature est documenté dans la Référence REST API.
Tester un webhook
Envoyez une livraison de test synthétique pour confirmer que votre endpoint est correctement configuré. La réponse contient le résultat de la tentative de livraison (statut HTTP de votre endpoint et durée) :
curl -X POST https://api.zenovay.com/v1/cli/mutate/webhooks/{id}/test \
-H "Authorization: Bearer YOUR_TOKEN"
Faire tourner le secret de signature
Si un secret fuite ou si vous souhaitez le faire tourner périodiquement, faites-le. Le nouveau secret est renvoyé une seule fois dans la réponse :
curl -X POST https://api.zenovay.com/v1/cli/mutate/webhooks/{id}/rotate \
-H "Authorization: Bearer YOUR_TOKEN"
Après la rotation, mettez à jour votre endpoint pour vérifier avec le nouveau secret. Les anciennes signatures cessent immédiatement d'être valides.
Révoquer un webhook
curl -X DELETE https://api.zenovay.com/v1/cli/mutate/webhooks/{id} \
-H "Authorization: Bearer YOUR_TOKEN"
Les webhooks révoqués cessent immédiatement de recevoir des livraisons. La révocation est irréversible.
Bonnes pratiques
- Répondez avec un 2xx aussi vite que possible. Acquittez d'abord, puis traitez l'événement dans un job en arrière-plan.
- Soyez idempotent. Les nouvelles tentatives réseau peuvent provoquer la réception du même événement plusieurs fois — indexez votre handler sur l'id de l'événement, et non sur l'heure de réception.
- Vérifiez avant de faire confiance. Rejetez toute requête dont le HMAC ne se valide pas, et rejetez les requêtes dont l'horodatage est très en dehors d'une fenêtre acceptable.
- Faites tourner les secrets si quelqu'un en dehors de l'équipe a eu accès à votre configuration ou à vos logs de webhooks.
Webhooks de paiement entrants
Zenovay traite également des webhooks entrants provenant de services externes pour gérer les abonnements et l'infrastructure. Ils s'exécutent à l'intérieur de la plateforme Zenovay et ne nécessitent aucune configuration de votre part.
Sources de webhooks entrants
| Source | Objectif |
|---|---|
| Stripe | Gestion des abonnements, traitement des paiements, finalisation du checkout |
| Surveillance de disponibilité | Déclencheurs de health-check provenant de services de surveillance externes |
Alternatives par polling
Si les webhooks sortants ne conviennent pas à votre cas d'usage (par exemple, si vous avez besoin d'agrégats à un instant donné plutôt que d'un flux d'événements), vous pouvez tout de même créer des intégrations en temps réel en interrogeant l'External API.
L'External API est également une fonctionnalité payante — elle nécessite une clé API, et les plans Free n'incluent pas d'accès API. Les endpoints ci-dessous retournent l'enveloppe standard { success, data, timestamp }, votre payload se trouve donc sous data.
Polling avec l'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);
Le paramètre range accepte 24h, 7d, 30d, 90d ou 1y (par défaut 7d).
Compteur de visiteurs en direct
Utilisez l'endpoint public en direct pour obtenir le compteur de visiteurs actuel sans clé API :
async function getLiveVisitors(trackingCode) {
const response = await fetch(
`https://api.zenovay.com/e/live/${trackingCode}`
);
return await response.json();
}
Exemple d'intégration Slack
Créez un rapport planifié qui poste sur 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}`
})
});
}
Exemple d'intégration CRM
Synchronisez les données analytiques avec votre CRM selon un planning :
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 débit pour le polling
Lorsque vous construisez des intégrations par polling, respectez les limites de débit de l'External API :
| Plan | Requêtes/Minute | Limite mensuelle |
|---|---|---|
| Free | 10 | 1 000 |
| Pro | 30 | 10 000 |
| Scale | 60 | 100 000 |
| Enterprise | 120 | 1 000 000 |
Bonnes pratiques de polling
- Mettez en cache les réponses de l'API localement pour réduire la fréquence des requêtes
- Utilisez des intervalles de polling appropriés (5 minutes minimum recommandé)
- Surveillez l'en-tête
X-RateLimit-Remainingpour éviter d'atteindre les limites - Implémentez un backoff exponentiel si vous recevez des réponses 429