Zum Inhalt springen

Webhooks einrichten und Signatur prüfen.

Webhooks der KENJTEC API: die sechs Ereignisse an deinen Server, einen Webhook einrichten, die Signatur prüfen und wie Fehlschläge wiederholt werden.

VideoEinen Webhook einrichten
Auf dieser Seite

Die Ereignisse

Ein Webhook ist eine Adresse deines Servers, an die wir ein Ereignis schicken, sobald es passiert. Sechs Ereignisse gibt es:

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 kommt bei der ersten Teilerstattung und bei der vollständigen Erstattung. Eine Kasse, die nie bezahlt wurde und verfällt, ist kein Storno — dafür kommt kein Ereignis.

Einen Webhook einrichten

Programme können Webhooks auch selbst eintragen: POST /v1/webhooks mit einem Schlüssel, der webhooks:manage trägt — und dazu das Leserecht der Daten, die der Webhook schickt (forms:read für Formular-Ereignisse, orders:read für Bestellungen).

Ana trägt im Bereich „Entwickler“ die Adresse https://deine-firma.com/kenjtec-webhook ein, lässt nur „Eine Bestellung ist bezahlt“ angehakt und klickt auf „Webhook anlegen“ — „Webhook angelegt.“ erscheint mit dem Geheimnis zum Kopieren.
  1. Öffne im Dashboard den Bereich Entwickler.
  2. Trage unter „Webhooks“ die Adresse deines Empfängers ein — sie beginnt mit https.
  3. Wähle unter „Welche Ereignisse?“ aus, was du bekommen willst, und klicke auf „Webhook anlegen“.
  4. Kopiere das Geheimnis, das danach erscheint, in deinen Empfänger.
  5. Klicke auf „Test senden“ — das Ergebnis steht sofort darunter.

Was ankommt

Jedes Ereignis ist ein POST mit JSON. In data.object steht das Objekt in derselben Form wie in der API — eine Bestellung wie bei GET /v1/orders/{id}, eine Antwort wie in der Liste der Antworten. Bei Formular-Ereignissen steht in data.form zusätzlich, zu welchem Formular die Antwort gehört.

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

Die Signatur prüfen

Jeder Aufruf trägt die Kopfzeile KENJTEC-Signature: t=<Zeit>,v1=<Signatur>. Die Signatur ist ein HMAC-SHA256 über die Zeit, einen Punkt und den unveränderten Körper der Anfrage — mit dem Geheimnis deines Webhooks als Schlüssel. Verwirf alles, dessen Zeit mehr als fünf Minuten zurückliegt.

Prüfe gegen den rohen Körper, bevor du das JSON einliest: Schon ein anderes Leerzeichen ergibt eine andere Signatur. Das Geheimnis findest du jederzeit unter „Geheimnis zeigen“; „Geheimnis erneuern“ macht das alte sofort ungültig.

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

Dasselbe Ereignis kann zweimal ankommen — etwa wenn dein Server antwortet, die Antwort uns aber nicht erreicht. Die Kennung in id (auch in der Kopfzeile KENJTEC-Event-Id) bleibt dabei gleich: Merke sie dir und verarbeite jedes Ereignis nur einmal.

Wenn etwas nicht ankommt

Als angekommen gilt jede Antwort mit einem Status von 200 bis 299 innerhalb von zehn Sekunden. Weiterleitungen folgen wir nicht.

Kommt ein Ereignis nicht an, versuchen wir es erneut: nach 1, 5 und 30 Minuten, nach 2, 6 und 12 Stunden und zweimal nach 24 Stunden — gut drei Tage lang. Kommen fünf Ereignisse in Folge endgültig nicht an, schalten wir den Webhook ab; im Dashboard steht dann, warum, und „Wieder einschalten“ setzt ihn zurück.

Unter „Protokoll“ siehst du jede Zustellung der letzten 30 Tage mit Status und Inhalt. Von dort lässt sich jedes Ereignis mit „Erneut senden“ noch einmal schicken.

Das Zustellprotokoll des Webhooks von Café Lumen: drei Einträge „order.paid“, einer davon „Nicht zugestellt“ mit „Der Empfänger antwortete mit einem Fehlerstatus. (503)“ und dem Knopf „Erneut senden“.

Webhooks gehen nur an öffentliche https-Adressen. Adressen in internen Netzen und Adressen von KENJTEC selbst nehmen wir nicht an.

Passende Anleitungen und nächste Schritte

Hilf uns, KENJTEC zu verbessern

Google Analytics hilft uns, die Website zu verbessern. Google erhält Nutzungs- und Gerätedaten; eine Verarbeitung in den USA ist möglich.

Freiwillig. Deine Wahl gilt 180 Tage und ist jederzeit in den Cookie-Einstellungen änderbar.

Datenschutzerklärung