Webhooki
Subskrypcje webhooków działają w stylu RestHooks. Zapier tworzy i usuwa subskrypcje automatycznie, gdy użytkownik włącza albo wyłącza wyzwalacz.
Subskrypcja
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"
}
}
Odpowiedź zawiera subskrypcję i sekret do podpisywania. Sekret pokazywany jest tylko raz.
Lista i usuwanie
| Endpoint | Metoda |
|---|---|
/api/v1/webhooks | GET |
/api/v1/webhooks/:id | GET |
/api/v1/webhooks/:id | DELETE |
Wszystkie endpointy webhooków wymagają zakresu webhooks:manage.
Typy zdarzeń
| Zdarzenie | Opis |
|---|---|
lead.created | Pozyskano nowego leada. |
lead.qualified | Lead osiągnął próg kwalifikacji. |
conversation.message_received | W rozmowie pojawiła się nowa wiadomość. |
ticket.created | Utworzono zgłoszenie serwisowe. |
meeting.scheduled | Zarezerwowano spotkanie. |
meeting.cancelled | Odwołano spotkanie. |
Bezpieczeństwo dostarczania
Leezy wysyła każdy webhook z następującymi nagłówkami:
| Nagłówek | Zastosowanie |
|---|---|
X-Leezy-Signature | Podpis HMAC SHA-256 z <timestamp>.<raw_body>, poprzedzony sha256=. |
X-Leezy-Timestamp | Znacznik czasu unix (w sekundach), wchodzi w skład podpisywanych danych. |
X-Leezy-Event | Typ zdarzenia. |
X-Leezy-Delivery | Identyfikator wpisu w logu dostarczeń. |
Aby zweryfikować dostarczenie, przelicz HMAC z ${timestamp}.${raw_body} przy użyciu sekretu subskrypcji i porównaj z X-Leezy-Signature. Znacznik czasu jest częścią podpisywanych danych — odbiorca MUSI odrzucać dostarczenia, w których X-Leezy-Timestamp różni się o więcej niż pięć minut od czasu bieżącego. Bez tego okna przechwycony ładunek można byłoby odtwarzać w nieskończoność, bo ta sama treść zawsze daje ten sam podpis.
Przykład weryfikacji (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),
);
}