Aller au contenu

Configurer un webhook et vérifier la signature.

Les webhooks de l'API KENJTEC : les six événements envoyés à votre serveur, configurer un webhook, vérifier la signature et la relance des envois échoués.

VidéoConfigurer un webhook
Sur cette page

Les événements

Un webhook est une adresse de votre serveur à laquelle nous envoyons un événement dès qu’il se produit. Il existe six événements :

form.response.created   Eine neue Antwort auf eines deiner Formulare
form.response.updated   Jemand hat seine Antwort über den Bearbeitungslink geändert
order.paid              Eine Bestellung ist bezahlt
order.fulfilled         Eine Bestellung ist versendet oder übergeben
order.canceled          Eine bestätigte Bestellung wurde storniert
order.refunded          Eine Bestellung wurde erstattet

order.refunded arrive lors du premier remboursement partiel et lors du remboursement complet. Une session de paiement qui n'a jamais été payée et qui expire n'est pas une annulation — aucun événement n'est envoyé dans ce cas.

Configurer un webhook

Les programmes peuvent aussi enregistrer eux-mêmes des webhooks : POST /v1/webhooks avec une clé qui porte webhooks:manage — ainsi que le droit de lecture des données envoyées par le webhook (forms:read pour les événements de formulaire, orders:read pour les commandes).

Dans l'espace « Développeur », Ana saisit l'adresse https://example.com/kenjtec-webhook, ne laisse cochée que « Une commande est payée » et clique sur « Créer un webhook » — « Webhook créé. » s'affiche avec le secret à copier.L’enregistrement montre l’interface en anglais.
  1. Ouvrez l'espace Développeur dans le tableau de bord.
  2. Sous « Webhooks », saisissez l'adresse de votre destinataire — elle commence par https.
  3. Sous « Quels événements ? », choisissez ce que vous voulez recevoir, puis cliquez sur « Créer un webhook ».
  4. Copiez dans votre destinataire le secret qui s'affiche ensuite.
  5. Cliquez sur « Envoyer un test » — le résultat s'affiche aussitôt en dessous.

Ce qui arrive

Chaque événement est un POST avec du JSON. data.object contient l'objet sous la même forme que dans l'API — une commande comme avec GET /v1/orders/{id}, une réponse comme dans la liste des réponses. Pour les événements de formulaire, data.form indique en plus à quel formulaire la réponse appartient.

order.paid (abrégé)
{
  "id": "evt_Q2x9kLmP4vT7aB1cD3eF5gH7",
  "object": "event",
  "type": "order.paid",
  "api_version": "2026-09-23",
  "created_at": "2026-09-23T14:05:12Z",
  "data": {
    "object": {
      "id": 5531,
      "object": "order",
      "number": 42,
      "status": "confirmed",
      "payment_status": "paid",
      "currency": "EUR",
      "total": 3890,
      "customer": { "email": "mara@example.com", "name": "Mara Sol" },
      "items": [
        { "name": "Kaffeebohnen, 500 g", "sku": "KAF-500", "quantity": 2, "unit_price": 1690 }
      ]
    }
  }
}

Vérifier la signature

Chaque appel porte l'en-tête KENJTEC-Signature: t=<heure>,v1=<signature>. La signature est un HMAC-SHA256 calculé sur l'heure, un point et le corps non modifié de la requête — avec le secret de votre webhook comme clé. Rejetez tout ce dont l'heure remonte à plus de cinq minutes.

Vérifiez sur le corps brut avant de lire le JSON : un seul espace différent donne une autre signature. Vous trouvez le secret à tout moment sous « Afficher le secret » ; « Renouveler le secret » rend l'ancien immédiatement invalide.

Node.js
import crypto from "node:crypto";

// raw: the unparsed request body (Buffer), header: the KENJTEC-Signature header
export function verify(raw, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret)
    .update(`${parts.t}.`).update(raw).digest("hex");
  const given = String(parts.v1 ?? "");
  return given.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(given));
}
Python
import hashlib, hmac, time

def verify(raw: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > 300:
        return False
    expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Le même événement peut arriver deux fois — par exemple lorsque votre serveur répond mais que la réponse ne nous parvient pas. L'identifiant dans id (également dans l'en-tête KENJTEC-Event-Id) reste alors le même : mémorisez-le et ne traitez chaque événement qu'une seule fois.

Quand quelque chose n'arrive pas

Toute réponse avec un statut de 200 à 299 reçue dans les dix secondes est considérée comme livrée. Nous ne suivons pas les redirections.

Si un événement n'arrive pas, nous réessayons : après 1, 5 et 30 minutes, après 2, 6 et 12 heures, puis deux fois après 24 heures — pendant un peu plus de trois jours. Si cinq événements de suite échouent définitivement, nous désactivons le webhook ; le tableau de bord indique alors pourquoi, et « Réactiver » le réinitialise.

Sous « Journal », vous voyez chaque livraison des 30 derniers jours avec son statut et son contenu. De là, vous pouvez renvoyer n'importe quel événement avec « Renvoyer ».

Le journal de livraison du webhook de Café Lumen : trois entrées « order.paid », dont une « Non livré » avec « Le destinataire a répondu avec un statut d'erreur. (503) » et le bouton « Renvoyer ».
L’enregistrement montre l’interface en anglais.

Les webhooks ne sont envoyés qu'à des adresses https publiques. Nous n'acceptons pas les adresses de réseaux internes ni les adresses de KENJTEC lui-même.

Guides associés et prochaines étapes

Aidez-nous à améliorer KENJTEC

Google Analytics nous aide à améliorer le site. Google reçoit des données d’utilisation et sur l’appareil, qui peuvent être traitées aux États-Unis.

C’est facultatif. Votre choix est conservé 180 jours et vous pouvez le modifier à tout moment dans les paramètres des cookies.

Politique de confidentialité