Nouveau : le pare-feu IA surveille chaque module et explique chaque incident en termes simples. Découvrez comment ça marche

Webhooks

Recevez des appels HTTP signés lorsque des appareils, alarmes, commandes, mises à jour firmware et règles évoluent : configuration, signatures, CloudEvents, relances, tests et API webhook.

Un webhook est une adresse de votre système que Hermetry appelle lorsqu’un événement se produit. Il sert à alimenter un système de tickets, un ERP, un bus de messages ou votre propre service. Les webhooks sont gérés par les administrateurs dans Webhooks (dans la partie Developer du menu). L’envoi de webhooks nécessite une offre qui les inclut.

Créer un webhook

  1. Ouvrez Webhooks et sélectionnez New Webhook.
  2. Saisissez un Name et, facultativement, une Description (« À quoi sert ce webhook ? »).
  3. Saisissez l’URL. Elle doit être en HTTPS : « Webhook URL must be a valid HTTPS URL. »
  4. Sous Events, choisissez au moins un événement. La liste n’affiche que les événements des modules utilisés par votre organisation.
  5. Facultativement :
    • Custom headers (optional) : jusqu’à 20 en-têtes envoyés à chaque appel, par exemple un jeton d’autorisation que votre récepteur vérifie. Content-Type, User-Agent, Host, Content-Length et X-Webhook-* ne peuvent pas être définis. Les valeurs tiennent sur une ligne, 1,000 caractères au maximum.
    • Event filters (optional, advanced) : ne livrer un événement que lorsque son payload correspond (voir ci-dessous).
    • Tags (optional, comma-separated) : étiquettes pour organiser vos webhooks, 20 au maximum.
    • Rate limit (optional, deliveries/minute) : vide signifie illimité.
  6. Enregistrez. Copiez immédiatement le Signing secret : il n’est affiché qu’une seule fois.

Tous les événements des modules IoT sont listés avec des exemples de payload dans la Webhook event reference.

Filtres d’événements

Un filtre d’événement est un objet JSON qui associe un événement aux champs du payload que celui-ci doit respecter. Une livraison est ignorée lorsque le payload ne correspond pas. Les événements sans filtre sont toujours livrés.

{
  "alarm.created": { "severity": "CRITICAL" },
  "device.disconnected": { "profileId": "6f1c0a2e-0000-4000-8000-000000000001" }
}

Chaque chemin désigne un champ de data de l’événement et peut être pointé, par exemple originator.type. Chaque champ indiqué doit être égal à sa valeur (nombres et textes sont comparés comme du texte, donc "2" correspond à 2). 50 événements au maximum peuvent avoir un filtre.

À quoi ressemble une livraison

Hermetry envoie un POST avec ces en-têtes :

En-têteValeur
Content-Typeapplication/json (format par défaut) ou application/cloudevents+json; charset=utf-8
User-AgentHermetry-Webhooks/1.0
X-Webhook-EventLe nom de l’événement, par exemple device.disconnected
X-Webhook-DeliveryL’identifiant de la livraison. Identique à chaque nouvelle tentative et à chaque renvoi d’une même livraison.
X-Webhook-TimestampSecondes Unix au moment où cette tentative a été signée
X-Webhook-Signature-V2sha256= + HMAC-SHA256 de "<timestamp>.<body>" avec votre secret. Utilisez celui-ci.
X-Webhook-SignatureHMAC-SHA256 du seul corps. Ancienne forme, conservée pendant une période de transition.
X-Webhook-Signature-Prev, X-Webhook-Signature-V2-PrevLes mêmes, avec le secret précédent, pendant une rotation de secret
X-Webhook-Manualtrue sur un événement envoyé manuellement par un administrateur
X-Idempotency-KeySur les messages qu’un flux envoie via son bloc webhook

Avec le format par défaut, le corps est une enveloppe :

{
  "webhookId": "…",
  "tenantId": "…",
  "event": "device.disconnected",
  "createdAt": "2026-11-03T12:00:30.000Z",
  "data": { "deviceId": "…", "name": "router-17", "reason": "timeout", "…": "…" }
}

Un événement envoyé manuellement par un administrateur porte aussi "manual": true. Répondez par un statut 2xx quelconque dans le délai imparti. Les 4 premiers Ko du corps de votre réponse sont conservés dans le journal de livraison.

Format CloudEvents

Un point de terminaison peut recevoir à la place des CloudEvents 1.0 en mode structuré. Le formulaire de webhook ne propose pas encore de choix de format : définissez "format": "cloudevents" via l’API (POST ou PATCH /api/webhooks/..., voir ci-dessous). "json" est la valeur par défaut.

{
  "specversion": "1.0",
  "id": "8d2c…",
  "source": "urn:hermetry:tenant:<tenantId>",
  "type": "com.hermetry.device.connected",
  "datacontenttype": "application/json",
  "time": "2026-11-03T10:00:30.000Z",
  "data": { "deviceId": "…", "name": "router-17", "transport": "mqtts", "…": "…" },
  "tenantid": "<tenantId>",
  "webhookid": "<webhookId>"
}

data contient exactement ce que le format par défaut contient sous data. id est identique à chaque nouvelle tentative et à chaque renvoi ; dédoublonnez donc sur source et id. Les en-têtes de signature sont les mêmes dans les deux formats. Les modes batch et binaire ne sont pas proposés.

Vérifier la signature

Vérifiez sur le corps brut, avant de l’analyser, et rejetez les horodatages anciens.

import crypto from 'crypto';

function verifyWebhook(body: string, timestamp: string, signatureV2: string, secret: string): boolean {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(`${timestamp}.${body}`).digest('hex');
  // Reject deliveries older than 5 minutes.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureV2);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Pendant une rotation de secret, acceptez un appel lorsque X-Webhook-Signature-V2 ou X-Webhook-Signature-V2-Prev correspond.

Livraison, nouvelles tentatives et lettres mortes

ParamètreValeur par défautPlage
Request Timeout (ms)15,0001,000 à 120,000
Max Delivery Attempts (première tentative incluse)31 à 10
Retry Backoff (ms) : l’attente avant la nouvelle tentative 1, 2, …60000,300000,9000001 à 9 valeurs, chacune de 1,000 à 86,400,000 ; au-delà de la liste, la dernière valeur
Circuit Breaker Threshold : nombre d’échecs consécutifs avant la désactivation du point de terminaison101 à 100,000
Default Rate Limit (per minute) : pour les points de terminaison qui n’en ont pasillimitévide ou 0 = illimité

Définissez-les dans Webhooks > paramètres (le bouton en forme d’engrenage). Une livraison est soit PENDING, SUCCESS, FAILED (sera relancée) soit DEAD_LETTERED (toutes les tentatives utilisées).

  • Chaque livraison est journalisée avec son statut, ses tentatives, le code de réponse, l’erreur, la durée et l’heure de la prochaine tentative.
  • Un point de terminaison au-delà de sa limite de débit reçoit ses livraisons environ 60 secondes plus tard ; rien n’est perdu.
  • Après le seuil d’échecs consécutifs, le point de terminaison est désactivé et apparaît comme désactivé automatiquement. Les nouvelles tentatives en file d’attente s’arrêtent. Réactivez-le pour réinitialiser le compteur, puis relancez ou rejouez ce qui a échoué.
  • Les livraisons sont au moins une fois. Dédoublonnez sur X-Webhook-Delivery (ou sur l’id CloudEvents).
  • L’ordre d’arrivée des événements n’est pas garanti. Utilisez les heures contenues dans le payload.

Les événements de connexion et de modification des appareils disposent de leur propre garde-fou de volume : au plus 600 de chaque type par organisation et par minute par défaut. Voir la Webhook event reference.

Renouveler le secret

Sélectionnez Rotate signing secret (rôle Owner). Le nouveau secret n’est affiché qu’une fois. L’ancien secret reste valide 48 heures, et pendant ce temps chaque appel porte les deux signatures. Renouveler à nouveau pendant que cette fenêtre est ouverte ne remplace que le secret actuel ; le précédent conserve sa date de fin.

Test

Depuis les actions de ligne d’un webhook ou sur sa page :

  • Send test event envoie immédiatement un événement nommé test et affiche le résultat (« Test delivered — HTTP 200 in 85 ms »). Un test ne compte jamais dans le disjoncteur.
  • Trigger event… envoie un événement réel et signé de votre choix avec un exemple de payload (objet JSON, 64 Ko au maximum), marqué manual: true et X-Webhook-Manual: true. Il respecte le filtre d’événements du point de terminaison : un exemple que le filtre écarterait est refusé.
  • View deliveries liste les livraisons ; une livraison échouée ou en lettre morte peut être renvoyée, et toutes les lettres mortes peuvent être rejouées en une fois.

Règles réseau

Les adresses des webhooks doivent être des adresses HTTPS publiques. Les adresses privées, de boucle locale, à liaison locale et de métadonnées cloud sont refusées à l’enregistrement et de nouveau à chaque appel, et les redirections ne sont pas suivies. Pour une cible interne voulue, un administrateur peut définir un ipAllowlist explicite (jusqu’à 50 adresses ou plages CIDR) sur le webhook via l’API.

L’API des webhooks

Les chemins commencent par /tenant/<tenantId>. Tous nécessitent les droits d’un administrateur.

MéthodeCheminAction
GET/api/webhooks/eventsLes événements auxquels vous pouvez vous abonner
GET, POST/api/webhooksListe (page à partir de 1, pageSize, search, sort, isActive, autoDisabled) ; création : 201 { webhook, secret }
GET, PATCH, DELETE/api/webhooks/{webhookId}Lire, modifier, supprimer
POST/api/webhooks/{webhookId}/rotate-secret{ webhook, newSecret, overlapMs } (Owner)
POST/api/webhooks/{webhookId}/test{ delivery }
POST/api/webhooks/{webhookId}/trigger{ event, payload } → { message, deliveryId }
GET/api/webhooks/{webhookId}/deliveries{ data, total } ; filtres status, event, createdFrom, createdTo
POST/api/webhooks/{webhookId}/deliveries/{deliveryId}/redeliverRemettre en file une livraison FAILED ou DEAD_LETTERED
GET, POST/api/webhooks/{webhookId}/deliveries/replay-dead-letterCompter, ou remettre en file, chaque dead letter
GET/api/webhooks/metrics, /api/webhooks/reportStatistiques de livraison (?webhookId=&days=)

Corps de création : name, description, url, events, headers, eventFilters, tags, rateLimitPerMinute (1 à 100,000), ipAllowlist, format (json ou cloudevents).

RefusSignification
403 WEBHOOKS_NOT_IN_PLANVotre offre ne comprend pas les webhooks
409 ENDPOINT_DISABLEDL’endpoint est désactivé ; activez-le d’abord
409 DELIVERY_NOT_REDELIVERABLELa livraison est en attente ou a déjà réussi
422 EVENT_FILTERED_OUTLe filtre de l’endpoint éliminerait l’exemple que vous avez déclenché
422Un événement qu’aucun module de votre organisation ne propose