Webhooki - wysyłanie zdarzeń z Chateo do Twoich systemów

Jak dodać adres webhooka, jakie zdarzenia wysyła Chateo, jak sprawdzić podpis, co dzieje się przy błędach i jak przeglądać dostawy.

Instalacja i platformy

Webhook to adres w Twoim systemie, na który Chateo wysyła wiadomość (żądanie HTTP), gdy w czatach coś się wydarzy: ktoś zaczyna rozmowę, pisze wiadomość, zostawia dane w formularzu offline albo ocenia rozmowę. Dzięki temu Twój system dowiaduje się o tym od razu, bez odpytywania Chateo.

Przykłady użycia w sklepie „Sklep z kawą":

  • CRM - każda wiadomość z formularza offline zakłada kontakt lub zgłoszenie sprzedażowe.
  • Powiadomienia zespołu - zakończona rozmowa z oceną bad wysyła alert do kanału, który obserwuje obsługa.
  • Własna analiza - zdarzenia trafiają do hurtowni danych, a Ty liczysz czas pierwszej odpowiedzi i oceny po swojemu.

Webhookami zarządza właściciel konta lub administrator. Konsultanci i administratorzy ograniczeni do wybranych stron nie widzą tej sekcji.

Dostępność w pakietach

Webhooki są dostępne w pakiecie Biznes (do 10 adresów). Aktualny stan swojego konta zobaczysz w Ustawienia > Webhooki (np. „Adresy: 1 z 10"). Jeśli pakiet nie obejmuje webhooków, zobaczysz komunikat Webhooki są dostępne w pakiecie Biznes. Adresy dodane wcześniej (np. przed zmianą pakietu) nadal widać na liście: możesz obejrzeć ich szczegóły i historię dostaw, wyłączyć je albo usunąć, ale Chateo nie wysyła na nie zdarzeń. Szczegóły pakietów: Pakiety i płatności.

Dodanie adresu

  1. Wejdź w Ustawienia > Webhooki i kliknij Dodaj adres.
  2. W polu Adres URL wpisz adres swojego odbiornika. Adres musi zaczynać się od https://, mieć standardowy port 443, być nazwą domeny (nie adresem IP) i być dostępny z internetu. Adresy wskazujące na sieć prywatną są odrzucane.
  3. Opcjonalnie dodaj Opis (opcjonalnie), np. „CRM sprzedaży".
  4. W polu Zdarzenia zaznacz te, które chcesz dostawać.
  5. W polu Strony wybierz Wszystkie strony albo Wybrane strony.
  6. Jeśli masz włączoną weryfikację dwuetapową, wpisz Kod z aplikacji uwierzytelniającej.
  7. Kliknij Dodaj adres.

Zaraz po dodaniu zobaczysz okno Klucz podpisu. Skopiuj klucz od razu - ze względów bezpieczeństwa nie pokażemy go ponownie. Okno zamkniesz tylko przyciskiem Skopiowałem, zamknij (klawisz Esc ani kliknięcie obok go nie zamykają). Klucz zaczyna się od whsec_ i służy do sprawdzania podpisu (niżej). Przechowuj go w sekretach swojej aplikacji, nie w kodzie.

Właściciel konta i administratorzy z dostępem do wszystkich stron dostają e-mail o każdym nowym adresie i o każdej zmianie adresu (ten e-mail wysyłamy zawsze, także gdy wyłączyłeś powiadomienia o skrzynkach), żeby nikt niepostrzeżenie nie wyprowadzał rozmów z konta. Jeśli to nie Ty dodałeś adres, usuń go i zmień hasło.

Zdarzenia

Każde żądanie to JSON w tej samej kopercie:

  • id - unikalny identyfikator zdarzenia (taki sam przy każdym ponowieniu),
  • type - rodzaj zdarzenia,
  • api_version - wersja formatu (obecnie 2026-11-01; adres zostaje przy wersji, z którą go dodano),
  • created_at - czas zdarzenia (UTC),
  • account_id - identyfikator Twojego konta w Chateo,
  • portal - strona, której dotyczy zdarzenie (id i domain),
  • data - szczegóły zależne od rodzaju zdarzenia.

W ścieżkach stron (page_path) usuwamy parametry zapytania i fragment po #, bo często zawierają adresy e-mail albo tokeny zamówień. Nie wysyłamy adresów IP, danych przeglądarki ani lokalizacji. Załączniki mają tylko opis (rodzaj i rozmiar), bez linku do pliku. W kolejnych wersjach do kopert mogą dochodzić nowe pola - nie traktuj nieznanych pól jako błędu.

Rozpoczęta rozmowa (conversation.started)

Kiedy odwiedzający albo konsultant rozpoczyna rozmowę. Rozmowa z reguły proaktywnej liczy się dopiero wtedy, gdy odwiedzający odpisze. customer_id to Twój identyfikator klienta i jest wypełniony tylko wtedy, gdy sklep przekazał go w zweryfikowany sposób.

{
  "id": "0193f1c2-7a10-7c3e-9d11-5b2f6a4e8c01",
  "type": "conversation.started",
  "api_version": "2026-11-01",
  "created_at": "2026-11-09T12:00:00.000Z",
  "account_id": "0193e000-1111-7222-8333-944455556666",
  "portal": { "id": "0193e000-aaaa-7bbb-8ccc-9dddeeeeffff", "domain": "sklep-z-kawa.example.com" },
  "data": {
    "conversation": { "id": "0193f1c2-7a0f-7000-8000-0123456789ab", "started_by": "visitor", "page_path": "/kawa/ziarnista" },
    "visitor": { "id": "0193f1b0-0000-7000-8000-00000000abcd", "customer_id": null }
  }
}

Nowa wiadomość (message.created)

Wiadomość odwiedzającego lub konsultanta. Wiadomości bota i systemowe nie są wysyłane. W text jest treść wpisana przez rozmówcę. Przy bardzo długiej treści tekst jest skracany, a truncated ma wartość true. Dla wiadomości konsultanta dochodzi obiekt operator (imię wyświetlane, bez adresu e-mail).

{
  "id": "0193f1c3-1b20-7a4e-8e22-6c3f7b5f9d02",
  "type": "message.created",
  "api_version": "2026-11-01",
  "created_at": "2026-11-09T12:01:10.000Z",
  "account_id": "0193e000-1111-7222-8333-944455556666",
  "portal": { "id": "0193e000-aaaa-7bbb-8ccc-9dddeeeeffff", "domain": "sklep-z-kawa.example.com" },
  "data": {
    "conversation_id": "0193f1c2-7a0f-7000-8000-0123456789ab",
    "message": {
      "id": "0193f1c3-1b1f-7000-8000-0123456789cd",
      "sender_type": "operator",
      "text": "Dzień dobry, ta kawa jest świeżo palona w tym tygodniu.",
      "truncated": false,
      "attachments": [],
      "created_at": "2026-11-09T12:01:10.000Z"
    },
    "operator": { "id": "0193e001-0000-7000-8000-000000000001", "name": "Anna" }
  }
}

Zakończona rozmowa (conversation.closed)

Rozmowa zamknięta przez odwiedzającego, konsultanta albo automatycznie po bezczynności (closed_by: visitor, operator, inactivity). first_reply_seconds to czas pierwszej odpowiedzi (albo null). Obiekt operator pojawia się, gdy rozmowa miała przypisanego konsultanta.

{
  "id": "0193f1d0-4c30-7b5f-8f33-7d4a8c6a0e03",
  "type": "conversation.closed",
  "api_version": "2026-11-01",
  "created_at": "2026-11-09T12:20:00.000Z",
  "account_id": "0193e000-1111-7222-8333-944455556666",
  "portal": { "id": "0193e000-aaaa-7bbb-8ccc-9dddeeeeffff", "domain": "sklep-z-kawa.example.com" },
  "data": {
    "conversation": {
      "id": "0193f1c2-7a0f-7000-8000-0123456789ab",
      "closed_by": "operator",
      "started_at": "2026-11-09T12:00:00.000Z",
      "closed_at": "2026-11-09T12:20:00.000Z",
      "visitor_messages": 4,
      "operator_messages": 5,
      "first_reply_seconds": 38
    },
    "operator": { "id": "0193e001-0000-7000-8000-000000000001", "name": "Anna" }
  }
}

Wiadomość z formularza offline (offline_message.created)

Gdy nikogo nie ma i odwiedzający zostawia e-mail oraz wiadomość. To zdarzenie zawiera adres e-mail i dowolny tekst, więc traktuj je jak dane kontaktowe.

{
  "id": "0193f2a0-5d40-7c6a-9044-8e5b9d7b1f04",
  "type": "offline_message.created",
  "api_version": "2026-11-01",
  "created_at": "2026-11-09T22:15:00.000Z",
  "account_id": "0193e000-1111-7222-8333-944455556666",
  "portal": { "id": "0193e000-aaaa-7bbb-8ccc-9dddeeeeffff", "domain": "sklep-z-kawa.example.com" },
  "data": {
    "conversation_id": "0193f2a0-5d3f-7000-8000-0123456789ef",
    "email": "[email protected]",
    "text": "Czy macie kawę bezkofeinową w paczkach po kilogramie?",
    "truncated": false,
    "page_path": "/kawa/bezkofeinowa"
  }
}

Ocena rozmowy (rating.submitted)

Odwiedzający ocenił rozmowę: rating to 1, 2 lub 3, a rating_label to odpowiednio bad, ok, good. Komentarz może być pusty (null). Jeśli odwiedzający najpierw wybierze ocenę, a potem dopisze komentarz, dostaniesz dwa zdarzenia dla tej samej rozmowy.

{
  "id": "0193f1d5-6e50-7d7b-8155-9f6c0e8c2a05",
  "type": "rating.submitted",
  "api_version": "2026-11-01",
  "created_at": "2026-11-09T12:21:30.000Z",
  "account_id": "0193e000-1111-7222-8333-944455556666",
  "portal": { "id": "0193e000-aaaa-7bbb-8ccc-9dddeeeeffff", "domain": "sklep-z-kawa.example.com" },
  "data": {
    "conversation_id": "0193f1c2-7a0f-7000-8000-0123456789ab",
    "rating": 3,
    "rating_label": "good",
    "comment": "Szybka i konkretna odpowiedź, dziękuję."
  }
}

Test (webhook.test)

Zdarzenie wysyłane tylko przyciskiem Wyślij test. Nie wybierasz go w liście zdarzeń. W data ma jedno pole message z tekstem „Test z Chateo". Przyda się do sprawdzenia adresu i weryfikacji podpisu.

Nagłówki żądania

NagłówekZnaczenie
Content-Typezawsze application/json
User-AgentChateo-Webhooks/1.0 (+https://chateo.pl/pomoc/webhooki)
Chateo-Event-Ididentyfikator zdarzenia, taki sam przy każdym ponowieniu - użyj go do usuwania duplikatów
Chateo-Event-Typerodzaj zdarzenia, np. message.created
Chateo-Delivery-Ididentyfikator tej dostawy
Chateo-Attemptnumer próby (1, 2, 3...)
Chateo-Signaturepodpis żądania (patrz niżej)

Sprawdzanie podpisu

Każde żądanie jest podpisane Twoim kluczem, więc możesz upewnić się, że pochodzi z Chateo i nie zostało zmienione. Nagłówek ma postać:

Chateo-Signature: t=1731153600,v1=<64 znaki szesnastkowe>
  • t - czas wysłania w sekundach (czas uniksowy),
  • v1 - podpis zapisany szesnastkowo małymi literami: HMAC-SHA256 z tekstu t, kropki i surowej treści żądania (dokładnie tych bajtów, które dostałeś, przed parsowaniem JSON). Kluczem jest cały ciąg klucza podpisu razem z whsec_, jako tekst UTF-8 (nie dekoduj go z base64).

Po zmianie klucza (niżej) nagłówek zawiera dwa wpisy v1= - nowy i stary. Wystarczy, że zgadza się którykolwiek.

Odrzucaj żądania, w których t różni się od Twojego czasu o więcej niż 300 sekund (ochrona przed ponownym odtworzeniem), i porównuj podpisy funkcją odporną na ataki czasowe. Zanim porównasz podpis, sprawdź, że ma dokładnie 64 znaki szesnastkowe (małe litery) - inaczej uznaj go za błędny. Bez tego sprawdzenia zniekształcony nagłówek może wywołać wyjątek w funkcji porównującej (np. timingSafeEqual w Node.js) i błąd 500 zamiast odrzucenia żądania.

Wektor testowy do sprawdzenia własnej implementacji: klucz whsec_exampleExampleExampleExampleExampleExample1, t = 1731153600, treść {"type":"webhook.test"} daje podpis f59c85f79a52044aeeea07a9b984a3fd429313675bca8fad225bddf60f59029d.

Node.js

Użyj surowej treści, np. w Express: app.post('/chateo', express.raw({ type: 'application/json' }), handler).

const crypto = require('node:crypto');

function verifyChateo(rawBody, header, secret, toleranceSec = 300) {
  const parts = header.split(',').map((p) => p.trim().split('='));
  const t = Number(parts.find(([k]) => k === 't')?.[1]);
  const sigs = parts.filter(([k]) => k === 'v1').map(([, v]) => v);
  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
  return sigs.some((s) => {
    // Dokładnie 64 znaki szesnastkowe (małe litery) - inaczej podpis jest błędny, bez wyjątku.
    if (typeof s !== 'string' || !/^[0-9a-f]{64}$/.test(s)) return false;
    const given = Buffer.from(s, 'hex');
    return given.length === 32 && expected.length === 32 && crypto.timingSafeEqual(given, expected);
  });
}

// w obsłudze żądania:
// verifyChateo(req.body.toString('utf8'), req.get('Chateo-Signature') ?? '', process.env.CHATEO_WEBHOOK_SECRET)

PHP

<?php // PHP 7.4+
function chateo_verify(string $payload, string $header, string $secret, int $tolerance = 300): bool {
    $t = null; $sigs = [];
    foreach (explode(',', $header) as $part) {
        [$k, $v] = array_pad(explode('=', trim($part), 2), 2, '');
        if ($k === 't' && ctype_digit($v)) { $t = (int) $v; } elseif ($k === 'v1') { $sigs[] = $v; }
    }
    if ($t === null || abs(time() - $t) > $tolerance) { return false; }
    $expected = hash_hmac('sha256', $t . '.' . $payload, $secret, true); // 32 bajty
    foreach ($sigs as $s) {
        // Dokładnie 64 znaki szesnastkowe (małe litery) - inaczej podpis jest błędny.
        if (preg_match('/^[0-9a-f]{64}$/', $s) !== 1) { continue; }
        $given = hex2bin($s);
        if ($given !== false && strlen($given) === 32 && hash_equals($expected, $given)) { return true; }
    }
    return false;
}

$payload = file_get_contents('php://input');
if (!chateo_verify($payload, $_SERVER['HTTP_CHATEO_SIGNATURE'] ?? '', getenv('CHATEO_WEBHOOK_SECRET'))) {
    http_response_code(400);
    exit;
}
http_response_code(200); // odpowiedz szybko, resztę przetwarzaj osobno

Odpowiedź, ponowienia i duplikaty

  • Za sukces uznajemy każdą odpowiedź 2xx w ciągu 10 sekund. Odpowiadaj szybko, a zdarzenie przetwarzaj osobno.
  • Przekierowania (3xx) traktujemy jako błąd i nie podążamy za nimi - podaj docelowy adres bezpośrednio.
  • Przy błędzie ponawiamy wysyłkę: po 1 minucie, 5 minutach, 30 minutach, 2, 6, 12 i 24 godzinach (z niewielkim losowym rozrzutem). To łącznie 8 prób w ciągu około 45 godzin. Potem dostawa dostaje status Nieudane.
  • Dostawa może trafić do Ciebie więcej niż raz. Zapisuj Chateo-Event-Id i ignoruj zdarzenia, które już przetworzyłeś.
  • Kolejność zdarzeń nie jest gwarantowana. Jeśli jej potrzebujesz, sortuj po created_at.

Automatyczne wyłączenie

Jeśli Twój serwer przez ponad dobę nie przyjmuje zdarzeń i było już wiele nieudanych prób z rzędu, Chateo wyłącza adres (status Wyłączony automatycznie), a zaległe dostawy kończą się jako Nieudane. Właściciel i administratorzy z dostępem do wszystkich stron dostają o tym e-mail (zawsze, także przy wyłączonych powiadomieniach o skrzynkach), raz na jedno wyłączenie. Gdy naprawisz serwer, kliknij Włącz ponownie. Zdarzeń z czasu przerwy nie odtwarzamy automatycznie - możesz je wysłać ponownie z listy dostaw, dopóki są dostępne (niżej).

Adres możesz też wyłączyć sam przyciskiem Wyłącz (na przykład na czas prac na serwerze) i potem włączyć przyciskiem Włącz.

Wyślij test i lista dostaw

Przy każdym adresie jest przycisk Wyślij test. Wynik zobaczysz od razu, np. „Test dostarczony - HTTP 200, 120 ms", albo przyczynę błędu, np. „brak odpowiedzi w 10 s", „nie znaleziono adresu", „błąd certyfikatu HTTPS", „nie udało się połączyć", „serwer odpowiedział kodem 500".

Po kliknięciu Szczegóły zobaczysz sekcję Ostatnie dostawy z kolumnami Czas, Zdarzenie, Status, Kod HTTP, Próby i Czas odpowiedzi. Statusy to Dostarczone, Ponawiane, Oczekuje, Wysyłane i Nieudane; listę możesz przefiltrować. Po rozwinięciu wiersza (Pokaż) widać odpowiedź Twojego serwera (pierwsze 256 znaków), błąd i czas następnej próby. Przycisk Wyślij ponownie wysyła dane zdarzenie jeszcze raz.

Historię dostaw przechowujemy ograniczony czas, a treść zdarzenia krócej niż wpis w historii. Starszych zdarzeń nie da się wysłać ponownie: Zdarzenie jest starsze niż 7 dni - nie można go wysłać ponownie.

Zmiana klucza podpisu

Jeśli klucz mógł wyciec, kliknij Wygeneruj nowy klucz przy adresie (z kodem z aplikacji uwierzytelniającej, jeśli ją masz). Nowy klucz działa od razu, a stary podpisuje żądania jeszcze przez 24 godziny, żebyś zdążył podmienić go u siebie bez przerwy w dostawach. Datę końca zobaczysz przy adresie. Nowy klucz pokazujemy tylko raz.

Zapier, Make, n8n

W Zapier, Make i n8n użyj wyzwalacza typu „Catch Hook" (odbiornik webhooków) i wklej jego adres https:// do pola Adres URL. Kliknij Wyślij test, żeby narzędzie zobaczyło przykładowe dane. Weryfikacja podpisu w tych narzędziach jest opcjonalna i wymaga własnego kroku z kodem - przy niewrażliwych danych często można ją pominąć, ale wtedy każdy, kto pozna adres, może do niego pisać.

Prywatność

Do Twojego systemu trafiają dane osobowe Twoich rozmówców: treść wiadomości, a w formularzu offline także adres e-mail. Od momentu wysłania Ty jesteś administratorem tych danych w swoim systemie - uwzględnij odbiorcę webhooków w rejestrze czynności przetwarzania i w informacji o prywatności. Więcej: Prywatność i RODO.

  • Nie wysyłamy adresów IP, danych przeglądarki ani lokalizacji, a adresy stron są bez parametrów zapytania.
  • Gdy usuwasz dane odwiedzającego, usuwamy też jego zdarzenia z historii dostaw Chateo (to, co już trafiło do Twojego systemu, usuwasz u siebie).
  • Usunięcie adresu zatrzymuje wysyłkę od razu i kasuje jego historię dostaw.

Rozwiązywanie problemów

KomunikatCo zrobić
Ten adres wskazuje na sieć prywatnąUżyj publicznej nazwy domeny. Adresy lokalne i wewnętrzne są blokowane ze względów bezpieczeństwa.
Adres musi zaczynać się od https://Skonfiguruj certyfikat HTTPS na odbiorniku.
Użyj standardowego portu HTTPS (443).Wystaw odbiornik na porcie 443 (np. przez serwer pośredniczący).
brak odpowiedzi w 10 sOdpowiadaj 200 od razu, a zdarzenie przetwarzaj w tle.
błąd certyfikatu HTTPSSprawdź, czy certyfikat jest ważny, wystawiony na tę domenę i ma pełny łańcuch.
nie znaleziono adresuSprawdź nazwę domeny w adresie URL i rekordy DNS.
nie udało się połączyćSprawdź, czy serwer działa i przepuszcza ruch z internetu na port 443.
serwer odpowiedział kodem 4xx lub 5xxObejrzyj odpowiedź w Ostatnie dostawy i logi własnego serwera. Sprawdź też podpis - zła weryfikacja zwykle kończy się kodem 400 lub 401.
Ten adres jest już dodany.Każdy adres można dodać do konta tylko raz.
Osiągnięto limit adresów w Twoim pakiecieUsuń nieużywany adres albo zmień pakiet: Pakiety i płatności.

Jeśli te kroki nie pomagają, napisz do nas przez czat na chateo.pl i podaj czas oraz rodzaj zdarzenia z listy dostaw.

Czy ten artykuł pomógł?

Zobacz swoich odwiedzających na żywo.

Zapisy ruszą wkrótce. Zostaw e-mail na liście oczekujących, a damy znać jako pierwszym.

Zapisz się na listę-20% na pierwszy rok · 14 dni bez karty