Zum Hauptinhalt springen

Webhooks

Webhook-Abonnements folgen einer API im RestHooks-Stil. Zapier legt Abonnements automatisch an und entfernt sie wieder, sobald ein Auslöser aktiviert oder deaktiviert wird.

Abonnieren

POST /api/v1/webhooks/subscribe
Authorization: Bearer lzy_at_your_access_token
Content-Type: application/json
{
"target_url": "https://hooks.zapier.com/hooks/catch/123/abc/",
"event_types": ["lead.created"],
"filters": {
"chatbot_id": "optional-chatbot-id"
}
}

Die Antwort enthält das Abonnement und ein Signaturgeheimnis. Dieses wird nur einmal angezeigt.

Auflisten und Löschen

EndpunktMethode
/api/v1/webhooksGET
/api/v1/webhooks/:idGET
/api/v1/webhooks/:idDELETE

Alle Webhook-Endpunkte setzen den Scope webhooks:manage voraus.

Ereignistypen

EreignisBeschreibung
lead.createdEin neuer Lead wurde erfasst.
lead.qualifiedEin Lead hat die Qualifizierungsschwelle erreicht.
conversation.message_receivedIn einem Gespräch ist eine neue Nachricht eingegangen.
ticket.createdEin Support-Ticket wurde angelegt.
meeting.scheduledEin Termin wurde gebucht.
meeting.cancelledEin Termin wurde storniert.

Sicherheit der Zustellung

Leezy sendet zu jedem Webhook diese Header:

HeaderZweck
X-Leezy-SignatureHMAC-SHA-256-Signatur über <timestamp>.<raw_body>, mit Präfix sha256=.
X-Leezy-TimestampUnix-Zeitstempel (Sekunden), Teil der signierten Eingabe.
X-Leezy-EventEreignistyp.
X-Leezy-DeliveryID des Zustellprotokolls.

Zur Prüfung wird der HMAC über ${timestamp}.${raw_body} mit dem Abonnementgeheimnis neu berechnet und mit X-Leezy-Signature verglichen. Der Zeitstempel ist Teil der signierten Eingabe — Empfänger MÜSSEN Zustellungen ablehnen, deren X-Leezy-Timestamp mehr als fünf Minuten von der eigenen Zeit abweicht. Ohne dieses Zeitfenster ließe sich eine abgefangene Nachricht beliebig oft wiederholen, da derselbe Rumpf stets dieselbe Signatur ergibt.

Beispiel zur Prüfung (Node.js):

import crypto from "node:crypto";

function verifyLeezySignature(rawBody, headers, secret) {
const timestamp = headers["x-leezy-timestamp"];
const signature = headers["x-leezy-signature"];
const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!timestamp || ageSeconds > 300) return false;

const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");

return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);
}