Webhooks
REST API PhishSpot (Rozdział 27) pozwala pobierać dane na żądanie. Webhooks odwracają kierunek: zamiast Ty pollujesz nas, my wywołujemy POST do Twojego URL-a w momencie, gdy coś się dzieje. Wpięty w SIEM webhook zamienia zdarzenie opened kampanii w alert bezpieczeństwa parę sekund po kliknięciu użytkownika. Wpięty w LMS — aktualizuje rekord uczącego się bez nocnej synchronizacji.
Ten rozdział opisuje dostępne zdarzenia, jak zarejestrować endpoint, co przychodzi na kablu i jak działają retry oraz podpisywanie.
26.1 Webhooks vs polling
Dział zatytułowany „26.1 Webhooks vs polling”Polling to pytanie „jest coś nowego?” w pętli — i ignorowanie odpowiedzi większość czasu. Marnuje wywołania API, ma wbudowane opóźnienie (dowiadujesz się o zdarzeniach przy następnym pollu, nie w momencie ich wystąpienia), źle się skaluje (dłuższe polly tracą zdarzenia, krótsze obciążają API).
Webhooks odwracają to. Rejestrujesz URL raz; my dostarczamy każde zdarzenie pod ten adres dokładnie wtedy, gdy wystąpi. Te same dane, niższe opóźnienie, mniej requestów. Minus: musisz mieć osiągalny endpoint HTTPS, żeby odbierać dostawy — ale dla celu integracji (SIEM, SOAR, LMS, bot, narzędzie wewnętrzne) to zwykle trywialne.
26.2 Tworzenie endpointu
Dział zatytułowany „26.2 Tworzenie endpointu”
- Otwórz Ustawienia konta → Webhooks. Strona endpoints listuje istniejące webhooki z kolumnami Nazwa, URL, Zdarzenia (liczba subskrybowanych typów), Status (Włączony / Wyłączony), Dostawy (łącznie + liczba nieudanych) i Akcje.
- Kliknij Nowy webhook. Formularz ma cztery pola:
- Nazwa — przyjazna etykieta. Przykłady z działającego setupu: „SIEM Splunk — security events”, „LMS Bridge — training sync”, „Slack Notify — #security channel”.
- URL webhooka — gdzie POST-ujemy dostawy. Musi być HTTPS. Platforma odrzuca URL-e wskazujące na localhost, link-local (169.254/16) i każdy zakres prywatny RFC1918 (10/8, 172.16/12, 192.168/16). Blokuje też
*.phishspot.com. Cel: webhook nie może być nadużyty do sondowania sieci wewnętrznej. - Subskrybuj zdarzenia — checkboxy dla każdego typu (patrz §26.3). Zaznacz co najmniej jedno.
- Włącz endpoint webhooka — przełącznik. Wyłączony oznacza, że trzymamy rekord, ale nic nie wysyłamy.
- Zapisz. PhishSpot generuje klucz podpisu (64-znakowy hex z
SecureRandom.hex(32)) i wyświetla go w całości na stronie szczegółów endpointu, z przyciskiem kopiowania. Zapisz go w bezpiecznym miejscu; nigdzie indziej go nie pokazujemy ponownie.
Endpoint jest aktywny natychmiast. Każde subskrybowane zdarzenie, które wystąpi od teraz, zostanie wysłane POST-em pod Twój URL.
26.3 Dostępne typy zdarzeń
Dział zatytułowany „26.3 Dostępne typy zdarzeń”Dziewięć typów zdarzeń jest dostępnych dziś, pogrupowanych po subiekcie:
| Typ zdarzenia | Kiedy się odpala |
|---|---|
campaign.created | Powstaje nowa kampania (ręcznie albo z iteracji autopilotu). |
campaign.updated | Zmienia się stan kampanii, odbiorcy albo treść. |
campaign.deleted | Kampania zostaje usunięta. |
contact.created | Dodano kontakt (CSV, ręcznie albo synchronizacja katalogu). |
contact.updated | Zmienia się email, dział, stanowisko, członkostwo w grupie albo external state. |
contact.deleted | Kontakt zostaje usunięty z konta. |
deliverable.created | Wysyłka kampanii produkuje rekord deliverable (jeden per odbiorca). |
deliverable.updated | Stan odbiorcy się zmienia (sent → opened → clicked → submitted → educated, albo bounced). |
spam_whitelist.updated | Lista IP / domen nadawcy dla konta się zmienia — patrz Rozdział 22 §22.5. |
Endpoint może subskrybować dowolną kombinację. Typowy SIEM subskrybuje contact.* i deliverable.*, żeby widzieć kogo atakujemy i jak reagują. Typowy bridge do LMS subskrybuje tylko deliverable.updated, bo interesuje go jedynie postęp w szkoleniach.
26.4 Dostawa: payload + podpis
Dział zatytułowany „26.4 Dostawa: payload + podpis”Każda dostawa to HTTP POST z ciałem JSON. Ciało to zdarzenie — ten sam rekord, który możesz pobrać przez API. Kształt:
{ "id": "550e8400-e29b-41d4-a716-446655440000", "type": "contact.created", "created_at": "2026-05-20T14:22:33.000Z", "api_version": 1, "data": { "id": 42, "email": "anna.kowalska@cydefen.pl" }}id— UUID identyfikujący to zdarzenie; klucz idempotentności. Powtórki tego samego zdarzenia używają tego samegoid.type— nazwa typu zdarzenia (jeden z dziewięciu w §26.3).created_at— ISO-8601 UTC, kiedy zdarzenie wystąpiło.api_version— wersja schematu jako integer.1dla powyższego formatu. Przyszłe zmiany łamiące kształt podniosą tę wartość, a my powiadomimy z wyprzedzeniem.data— pola specyficzne dla subiektu. Na raziedatazawieraidsubiektu i kluczowe atrybuty identyfikujące; pełen rekord pobierzesz z REST API używającid.
Podpisywanie. Każdy POST niesie nagłówek X-Webhook-Signature zawierający HMAC-SHA256 ciała JSON, wyliczone z kluczem podpisu endpointu. Weryfikacja po Twojej stronie:
expected = OpenSSL::HMAC.hexdigest("SHA256", signing_secret, request.raw_post)signature = request.headers["X-Webhook-Signature"]ActiveSupport::SecurityUtils.secure_compare(expected, signature) or render status: 401import hmac, hashlibexpected = hmac.new(secret.encode(), request.body, hashlib.sha256).hexdigest()if not hmac.compare_digest(expected, request.headers["X-Webhook-Signature"]): abort(401)Akceptuj tylko POST-y podpisane sekretem — nigdy nie ufaj niepodpisanemu requestowi, który twierdzi, że jest z PhishSpot.
26.5 Retry
Dział zatytułowany „26.5 Retry”Jeśli Twój endpoint odpowie czymś innym niż HTTP 2xx, dostawa trafia do kolejki retry. Retry idzie według ustalonego harmonogramu:
| Próba | Opóźnienie od poprzedniej |
|---|---|
| 1 | (natychmiast) |
| 2 | +15 sekund |
| 3 | +1 minuta |
| 4 | +5 minut |
| 5 | +15 minut |
| 6 | +1 godzina |
Po 5 retry (łącznie 6 prób) dostawa jest oznaczana Failed i już nie retrowana. Licznik consecutive_failures endpointu rośnie przy każdej całkowicie nieudanej dostawie. Po przekroczeniu 5 kolejnych niepowodzeń admini konta dostają mail jeden raz (z 7-dniowym cooldownem, żeby nie spamować, gdy endpoint jest źle skonfigurowany od dawna). Sam endpoint zostaje włączony — nie wyłączamy go automatycznie, bo większość awarii jest przejściowa i samonaprawiające się dostawy powinny móc się udać.
Jeśli chcesz ręcznie ponowić jedną nieudaną dostawę po naprawie po swojej stronie, otwórz stronę szczegółów dostawy (§26.6) i kliknij Ponów. To tworzy świeżą dostawę dla tego samego zdarzenia, z wyzerowanymi licznikami prób.
26.6 Historia dostaw
Dział zatytułowany „26.6 Historia dostaw”Strona szczegółów endpointu (kliknij dowolną nazwę endpointu na liście) pokazuje wszystko, co wiemy o tym endpoincie:
- Szczegóły endpointu — nazwa, URL, wersja API, klucz podpisu (z przyciskiem kopiowania), subskrybowane zdarzenia.
- Status — przełącznik Włączony / Wyłączony.
- Ostatnie dostawy — tabela ostatnich 50 dostaw z kolumnami:
- Typ zdarzenia (np.
contact.created) - Status — Oczekuje / Dostarcza / Dostarczone / Nieudane
- Próby — aktualna liczba prób / max (np.
1 / 5,5 / 5) - Ostatnia próba — znacznik czasu
- Akcje — Zobacz szczegóły, Ponów dostawę
- Typ zdarzenia (np.
Kliknij Zobacz szczegóły na dowolnym wierszu dostawy, aby otworzyć stronę szczegółów. Pokazuje pełny payload (sformatowany JSON), docelowy URL i log per-próba: numer próby, kod HTTP, czas odpowiedzi w ms i ciało odpowiedzi (albo komunikat błędu, jeśli request nie doszedł). To Twoja główna powierzchnia debugowania, gdy integracja się psuje.


26.7 Wskazówki operacyjne
Dział zatytułowany „26.7 Wskazówki operacyjne”- Potwierdzaj szybko. Twój handler powinien przyjąć dostawę (zwrócić 2xx) i przetwarzać asynchronicznie. My się poddajemy wolnym responderom — a wolni responderzy kaskadują się w retry, które kaskadują się w maile o „consecutive failures”.
- Obsłuż duplikaty. Problemy sieciowe mogą sprawić, że to samo zdarzenie dotrze dwa razy. Deduplikuj po polu
id— jest stabilne między retry. - Weryfikuj podpis. Nie działaj na webhooku, którego podpis się nie zgadza. POST chroniony sekretem to jedyne uwierzytelnienie; bez niego integrację może odtworzyć każdy, kto zgadnie URL.
- Spodziewaj się szczytów. Kampania z 1000 odbiorców produkuje 1000 zdarzeń
deliverable.createdw krótkim oknie. Upewnij się, że Twój handler się skaluje. - Rotuj sekret jeśli wycieknie. Usuń i utwórz endpoint na nowo — UI nie oferuje dziś rotacji „w miejscu”.
26.8 Odnośniki
Dział zatytułowany „26.8 Odnośniki”- REST API do pobierania tych samych danych na żądanie: Rozdział 27 Referencja REST API.
- Integracja auto-odświeżania whitelisty używająca tego samego pipeline’u dostaw: Rozdział 22 Whitelist filtra antyspamowego.
- Kontakty, do których odnoszą się zdarzenia
contact.*: Rozdział 5 Kontakty. - Kampanie, do których odnoszą się zdarzenia
campaign.*: Rozdział 4 Kampanie. - Zdarzenia synchronizacji katalogu, które generują większość ruchu
contact.*w produkcji: Rozdział 25 Synchronizacja katalogu.