Webhooki dla nowych leadów
Webhook wysyła każdy nowy lead z Twoich kanałów czatu, takich jak czat na stronie, Messenger i Instagram, do innej aplikacji zaraz po jego zebraniu: do CRM, Zapiera, Make, n8n albo Twojego własnego kodu. KnowStack wykonuje podpisany POST HTTPS z danymi kontaktowymi leada i rozmową do tej chwili.
Webhooki leadów są dostępne w planach Business i Enterprise oraz w bezpłatnym okresie próbnym. Skonfigurujesz je, jeśli Twoja rola może zarządzać użytkownikami, na przykład Company Admin.
Dodawanie webhooka
- Skopiuj adres webhooka z aplikacji, która ma odbierać leady. Musi zaczynać się od https://.
- W KnowStack otwórz Ustawienia, wybierz „Integracje” i przejdź do sekcji „Wysyłaj leady do swojego CRM”.
- W części „Dodaj webhook” wpisz w polu „Nazwa” nazwę, którą łatwo rozpoznasz, wklej adres w polu „Adres webhooka” i kliknij „Dodaj webhook”.
- Skopiuj wyświetlony klucz podpisu. Zaczyna się od whsec_ i jest pokazywany tylko raz. Potem kliknij „Zapisałem go”.
- Otwórz menu webhooka i kliknij „Wyślij test”. Wynik pojawi się od razu, a także w sekcji „Dziennik wysyłek”.
Wysyłane są tylko leady zebrane po dodaniu webhooka; wcześniejsze zostają w KnowStack. Możesz dodać kilka webhooków, a każdy nowy lead trafia do wszystkich aktywnych.
Adres musi być publiczny: tylko https, na standardowym porcie, bez nazwy użytkownika i hasła. Adresy w sieci prywatnej lub lokalnej są odrzucane, także gdy publiczna nazwa zacznie później na taką wskazywać. Przekierowania nie są obsługiwane, więc wklej adres docelowy.
Kiedy wysyłane są żądania
| Zdarzenie | Kiedy | Co zawiera |
|---|---|---|
| lead.created | Czat zbiera nowy lead | Lead i rozmowa do tej chwili |
| lead.updated | Imię, e-mail lub telefon pojawia się później w tym samym leadzie | Aktualne dane leada i lista changed z nowymi polami, bez rozmowy |
| test | Klikasz „Wyślij test” | Przykładowy lead z id 0 i krótka przykładowa rozmowa |
Wiadomości napisane po utworzeniu leada nigdy nie są wysyłane. Żądanie lead.updated wychodzi dopiero po przyjęciu lead.created i tylko wtedy, gdy pole zmieniło się z pustego na wypełnione.
Nagłówki żądania
| Nagłówek | Wartość |
|---|---|
| Content-Type | application/json |
| User-Agent | LeadWebhook/1.0 |
| X-Webhook-Event | lead.created, lead.updated lub test |
| X-Webhook-Delivery | Identyfikator wysyłki. Ponowna próba tej samej wysyłki go zachowuje, więc używaj go do pomijania duplikatów |
| X-Webhook-Timestamp | Moment podpisania w sekundach Unix |
| X-Webhook-Signature | v1= i szesnastkowy HMAC-SHA256 ze znacznika czasu, kropki i surowej treści, obliczony Twoim kluczem podpisu |
Treść (wersja 1)
Treść to JSON w UTF-8, wysyłany bez podziałów wierszy i pokazany tu w sformatowanej postaci. Wartości w nawiasach ostrych oznaczają Twoje własne: nazwa produktu to KnowStack, a adres to ten, pod którym się logujesz. Żądanie lead.created:
{
"version": 1,
"event": "lead.created",
"deliveryId": "4821",
"occurredAt": "2026-01-15T10:03:12.000Z",
"lead": {
"id": 1375,
"name": "Anna Novak",
"email": "[email protected]",
"phone": null,
"channel": "web_chat",
"channelLabel": "Website chat",
"source": "<product name> · Website chat",
"question": "Do you have availability next week?",
"firstPageUrl": "https://example.com/pricing",
"locale": "en",
"capturedAt": "2026-01-15T10:02:40.000Z",
"conversationUrl": "https://<your app address>/dashboard/channels/website-chat?conversation=812"
},
"transcript": [
{ "from": "customer", "text": "Hi, do you have availability next week?", "at": "2026-01-15T10:00:05.000Z" },
{ "from": "ai", "text": "Yes, we do. Could I take your email so the team can confirm a time?", "at": "2026-01-15T10:00:09.000Z" },
{ "from": "customer", "text": "Sure, [email protected]", "at": "2026-01-15T10:02:40.000Z" }
],
"transcriptIncomplete": false
}
| Pole | Znaczenie |
|---|---|
| version | W tym formacie zawsze 1. Zmiana, która mogłaby zepsuć Twój kod, dostanie nowy numer |
| event, deliveryId | Te same wartości co w nagłówkach X-Webhook-Event i X-Webhook-Delivery |
| occurredAt | Moment zbudowania żądania w formacie ISO 8601 (UTC) |
| lead.id | Identyfikator leada w KnowStack. lead.updated ma ten sam identyfikator, więc znajdziesz utworzony rekord |
| lead.name, lead.email, lead.phone | Dane kontaktowe. Każde z nich może mieć wartość null |
| lead.channel | Gdzie odbył się czat: obecnie web_chat, messenger lub instagram. Wraz z nowymi kanałami pojawią się nowe wartości, więc akceptuj dowolny tekst |
| lead.channelLabel, lead.source | Wyświetlana nazwa kanału i gotowe źródło leada, na przykład "KnowStack · Instagram", w języku osoby, która dodała webhook |
| lead.question | Pytanie zadane przez klienta przy zbieraniu leada albo null |
| lead.firstPageUrl, lead.locale | Strona, na której zaczął się czat na stronie, i język odwiedzającego. W innych kanałach zwykle null |
| lead.capturedAt | Moment pozostawienia danych kontaktowych |
| lead.conversationUrl | Link do rozmowy w KnowStack dla osób, które mogą zalogować się do Twojej firmy |
| transcript | Rozmowa do chwili utworzenia leada, od najstarszej wiadomości, maksymalnie 500 wiadomości. Każda ma from (customer, ai lub team), text i at |
| transcriptIncomplete | true, gdy starsze wiadomości zostały już usunięte zgodnie z ustawieniami przechowywania. Takie wiadomości mają text równe null i purged równe true |
Treść lead.updated ma te same pola version, event, deliveryId, occurredAt i lead, z aktualnymi wartościami leada. Zamiast rozmowy zawiera changed, listę pól wypełnionych od ostatniego żądania, na przykład ["phone"].
Weryfikacja podpisu
- Odczytaj surową treść żądania, zanim przetworzysz ją jako JSON.
- Połącz wartość X-Webhook-Timestamp, kropkę i surową treść.
- Oblicz HMAC-SHA256 tego tekstu swoim kluczem podpisu, pełną wartością razem z whsec_, i zapisz go szesnastkowo.
- Porównaj v1= z tą wartością z nagłówkiem X-Webhook-Signature, używając porównania w stałym czasie.
- Odrzuć żądanie, jeśli znacznik czasu różni się od Twojego zegara o więcej niż 5 minut. Dzięki temu nikt nie odtworzy starego żądania.
Przykład dla Node.js z Express:
const crypto = require('crypto');
const express = require('express');
const SECRET = process.env.LEAD_WEBHOOK_SECRET; // whsec_...
const app = express();
// Keep the body raw: the signature covers the exact bytes that were sent.
app.post('/leads', express.raw({ type: 'application/json' }), (req, res) => {
const timestamp = req.get('X-Webhook-Timestamp') || '';
const received = req.get('X-Webhook-Signature') || '';
const expected = 'v1=' + crypto
.createHmac('sha256', SECRET)
.update(timestamp + '.' + req.body)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
const valid = received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!fresh || !valid) return res.status(401).end();
const body = JSON.parse(req.body);
// req.get('X-Webhook-Delivery') identifies the delivery: skip it if you
// have already handled it.
console.log(body.event, body.lead.id);
res.status(204).end();
});
app.listen(3000);
Do sprawdzenia kodu: klucz whsec_test, znacznik czasu 1761559200 i treść {"a":1} dają podpis v1=ed347bcd87edf5b36afc10e41346740621d7f3c26b13ee1a4cc1eb7cddd0786f.
Odpowiedzi i ponowne próby
| Twoja odpowiedź | Co się dzieje |
|---|---|
| 2xx | Dostarczono |
| 408, 429, 5xx, przekroczony czas lub błąd sieci | Ponowne próby w coraz dłuższych odstępach przez około 24 godziny, potem oznaczenie jako nieudane. Retry-After przy 429 jest respektowany, maksymalnie do godziny |
| 410 | Webhook od razu przechodzi w stan „Wymaga uwagi” |
| 401, 403 lub 404 trzy razy bez udanej wysyłki pomiędzy | Webhook przechodzi w stan „Wymaga uwagi” |
| Każdy inny kod, także przekierowanie | Oznaczenie jako nieudane, bez ponownych prób |
Odpowiedz w ciągu 10 sekund, inaczej próba liczy się jako przekroczenie czasu. Odczytywane są tylko pierwsze 64 KB Twojej odpowiedzi. Najpierw odpowiedz, a czasochłonną pracę wykonaj potem.
Gdy webhook wymaga uwagi
Dopóki webhook ma stan „Wymaga uwagi” lub „Wstrzymany”, nowe leady czekają w kolejce zamiast przepadać. Gdy webhook przestaje działać, osoby zarządzające użytkownikami dostają jedno powiadomienie w dzwonku, a także w Telegramie, jeśli go połączyły. Napraw aplikację odbierającą albo popraw adres przez „Edytuj”, lub kliknij „Wznów”, jeśli adres był prawidłowy. Wysyłanie rusza ponownie, zaczynając od leadów, które czekały.
„Dziennik wysyłek” w menu webhooka pokazuje ostatnie 50 żądań z wynikiem i kodem odpowiedzi. Kliknij „Ponów” przy nieudanym, aby wysłać je jeszcze raz z tym samym identyfikatorem wysyłki. W zakładce „Leady” każdego kanału czatu znacznik pokazuje, czy lead dotarł do CRM; dla leada, który nie został wysłany, wybierz „Wyślij ponownie do CRM” w menu jego wiersza. Jeśli leady nadal nie docierają, a webhook pozostaje aktywny, jego wiersz pokazuje „Ostatnie wysyłki nie powiodły się”, a osoby zarządzające użytkownikami dostają powiadomienie, najwyżej raz dziennie.
Klucz podpisu
Jeśli klucz wyciekł, wybierz „Nowy klucz podpisu” w menu webhooka. Stary klucz od razu przestaje działać, więc od razu wpisz nowy w aplikacji odbierającej.
Jeśli Twoja firma przejdzie na plan bez webhooków leadów, nowe leady nie są wysyłane. Leady, które w tym czasie trafią do aktywnego webhooka, są pomijane i po zmianie planu na wyższy nie zostaną wysłane same; po zmianie planu możesz wysłać każdy z nich przez „Wyślij ponownie do CRM”. Leady czekające przy wstrzymanym webhooku lub takim, który wymaga uwagi, zostają w kolejce i zostaną wysłane, gdy zmienisz plan i wznowisz webhook. Twoje webhooki zostają na liście i nadal możesz je wstrzymać lub usunąć.