Naar de inhoud springen

Webhooks instellen en handtekening controleren.

Webhooks van de KENJTEC API: de zes gebeurtenissen naar je server, een webhook instellen, de handtekening controleren en hoe mislukte pogingen worden herhaald.

VideoEen webhook instellen
Op deze pagina

De gebeurtenissen

Een webhook is een adres op je server waarnaar we een gebeurtenis sturen zodra die plaatsvindt. Er zijn zes gebeurtenissen:

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 komt bij de eerste gedeeltelijke terugbetaling en bij de volledige terugbetaling. Een checkout die nooit is betaald en verloopt, is geen annulering — daarvoor wordt geen gebeurtenis verstuurd.

Een webhook instellen

Programma's kunnen webhooks ook zelf registreren: POST /v1/webhooks met een sleutel die webhooks:manage heeft — en daarnaast het leesrecht voor de gegevens die de webhook verstuurt (forms:read voor formuliergebeurtenissen, orders:read voor bestellingen).

Ana vult in het onderdeel “Ontwikkelaar” het adres https://deine-firma.com/kenjtec-webhook in, laat alleen “Een bestelling is betaald” aangevinkt en klikt op “Webhook aanmaken” — “Webhook aangemaakt.” verschijnt, samen met het geheim om te kopiëren.De opname toont de Engelse interface.
  1. Open in het dashboard het onderdeel Ontwikkelaar.
  2. Vul onder “Webhooks” het adres van je ontvanger in — het begint met https.
  3. Kies onder “Welke gebeurtenissen?” wat je wilt ontvangen en klik op “Webhook aanmaken”.
  4. Kopieer het geheim dat daarna verschijnt naar je ontvanger.
  5. Klik op “Test versturen” — het resultaat staat er meteen onder.

Wat er binnenkomt

Elke gebeurtenis is een POST met JSON. In data.object staat het object in dezelfde vorm als in de API — een bestelling zoals bij GET /v1/orders/{id}, een antwoord zoals in de lijst met antwoorden. Bij formuliergebeurtenissen staat in data.form bovendien bij welk formulier het antwoord hoort.

order.paid (ingekort)
{
  "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 }
      ]
    }
  }
}

De handtekening controleren

Elke aanroep bevat de header KENJTEC-Signature: t=<tijd>,v1=<handtekening>. De handtekening is een HMAC-SHA256 over de tijd, een punt en de ongewijzigde body van het verzoek — met het geheim van je webhook als sleutel. Verwerp alles met een tijdstip dat meer dan vijf minuten oud is.

Controleer tegen de ruwe body voordat je de JSON inleest: één afwijkende spatie levert al een andere handtekening op. Het geheim vind je altijd onder “Geheim tonen”; “Geheim vernieuwen” maakt het oude meteen ongeldig.

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", ""))

Dezelfde gebeurtenis kan twee keer binnenkomen — bijvoorbeeld als je server antwoordt, maar het antwoord ons niet bereikt. De ID in id (ook in de header KENJTEC-Event-Id) blijft daarbij gelijk: onthoud die en verwerk elke gebeurtenis maar één keer.

Als iets niet aankomt

Elk antwoord met een status van 200 tot 299 binnen tien seconden geldt als afgeleverd. Doorverwijzingen volgen we niet.

Komt een gebeurtenis niet aan, dan proberen we het opnieuw: na 1, 5 en 30 minuten, na 2, 6 en 12 uur en twee keer na 24 uur — ruim drie dagen lang. Komen vijf gebeurtenissen achter elkaar definitief niet aan, dan schakelen we de webhook uit; in het dashboard staat dan waarom, en “Weer inschakelen” zet hem terug.

Onder “Logboek” zie je elke aflevering van de afgelopen 30 dagen met status en inhoud. Van daaruit kun je elke gebeurtenis met “Opnieuw verzenden” nog een keer versturen.

Het afleveringslogboek van de webhook van Café Lumen: drie items “order.paid”, waarvan één “Niet afgeleverd” met “De ontvanger antwoordde met een foutstatus. (503)” en de knop “Opnieuw verzenden”.
De opname toont de Engelse interface.

Webhooks gaan alleen naar openbare https-adressen. Adressen in interne netwerken en adressen van KENJTEC zelf accepteren we niet.

Gerelateerde handleidingen en volgende stappen

Help ons KENJTEC te verbeteren

Google Analytics helpt ons de website te verbeteren. Google ontvangt gebruiks- en apparaatgegevens; verwerking in de VS is mogelijk.

Vrijwillig. Je keuze geldt 180 dagen en je kunt die op elk moment wijzigen in de cookie-instellingen.

Privacyverklaring