Pagalbos centras
Chat API

Webhooks

Paskutinį kartą atnaujinta:

Webhooks apžvalga

Webhooks leidžia ChatLab informuoti Jūsų sistemas tą pačią akimirką, kai kas nors įvyksta Jūsų chatbotuose. Užuot periodiškai teikę užklausas į Management API ar eksportavę duomenis rankiniu būdu, Jūs užregistruojate HTTPS galinį tašką (endpoint), o ChatLab siunčia pasirašytą HTTP POST užklausą realiuoju laiku - kai lankytojas palieka kontaktus (lead), pateikia kontaktų formą, įvertina pokalbį, paprašo žmogaus pagalbos arba kai įvykdomas AI veiksmas.

Tipiniai panaudojimo atvejai:

  • persiųsti naujus kontaktus (leads) tiesiai į Jūsų CRM sistemą tą pačią sekundę, kai jie užfiksuojami
  • informuoti Jūsų komandą „Slack“ platformoje, kai lankytojas paprašo tiesioginio pokalbio (live chat)
  • nukreipti pokalbių įvertinimus bei santraukas į Jūsų analitikos sistemas
  • stebėti AI veiksmų (AI actions) vykdymą ir gauti įspėjimus apie klaidas

Prieinamumas: Jūsų plane turi būti įtraukta Webhooks funkcija.

Kur konfigūruoti: administratoriaus programėlėje atidarykite Account settings -> Webhooks (Paskyros nustatymai -> Webhooks; visai šalia Management API skilties). Webhooks veikia paskyros lygiu - vienas galinis taškas gali gauti įvykius iš visų Jūsų botų arba iš vieno pasirinkto boto.

Galinio taško nustatymas

  1. Atidarykite Account settings -> Webhooks ir spustelėkite Add endpoint (Pridėti galinį tašką).
  2. Užpildykite galinio taško formą:
    • Name (Pavadinimas) - etiketė Jūsų asmeniniam patogumui, pvz., „CRM sync“ arba „Slack alerts“.
    • URL - HTTPS adresas, į kurį ChatLab siųs POST užklausas su įvykiais.
    • Events (Įvykiai) - pasirinkite, kuriuos įvykių tipus turi gauti šis galinis taškas (žr. katalogą žemiau). Pasirinkite tik tai, ko Jums reikia; didelės apimties įvykiai, tokie kaip ai_action.executed, gali sugeneruoti labai daug duomenų srauto.
    • Bot filter (Boto filtras) (neprivaloma) - pasirinkite vieną botą arba All bots (Visi botai) visiems Jūsų paskyros botams.
    • Custom form filter (Tinkintos formos filtras) (neprivaloma) - nukreipia konkrečios tinkintos formos pateikimus į šį galinį tašką. Jis susiaurina tik custom_form.submitted įvykį; visi kiti įvykiai, kuriuos prenumeruojate (leadai, kontaktų užklausos, pokalbiai, Live Chat, AI veiksmai), yra pristatomi nepriklausomai nuo šio nustatymo.
  3. Pateikite formą. Galinio taško raktas (secret) parodomas tik vieną kartą sėkmingo sukūrimo lange - nukopijuokite jį dabar ir saugiai išsaugokite. Jo prireiks parašams tikrinti (žr. skiltį „Saugumas“ žemiau). Vėliau atvirojo teksto pavidalu jo peržiūrėti nebebus įmanoma.

Kiekvienas galinis taškas taip pat turi:

  • Įjungimo / išjungimo jungiklį (Enable/disable toggle) - sustabdykite pristatymus neištrindami galinio taško. Išjungti galiniai taškai įvykius tiesiog atmeta (jie nėra kaupiami eilėje vėlesniam laikui).
  • Send sample event (Siųsti pavyzdinį įvykį) - nusiunčia pasirašytą bandomąją užklausą į Jūsų URL adresą, kad galėtumėte patikrinti savo gavėjo veikimą nuo pradžios iki galo. Prieš siųsdami galite pasirinkti įvykio tipą ir redaguoti pavyzdines reikšmes, kad Jūsų apdorojimo modulis matytų tikroviškus duomenis. Testas atkeliauja kaip įprastas pristatymas, kurio eventType atitinka Jūsų pasirinkimą (arba kaip webhook.test paprastam ryšio patikrinimui).
  • Roll secret (Pakeisti raktą) - sugeneruoja naują raktą ir panaikina senojo galiojimą. Naudokite tai, jei kilo įtarimas, kad raktas tapo viešai prieinamas. Naujas raktas vėl parodomas tik vieną kartą. Norėdami atlikti kontroliuojamą pakeitimą, sustabdykite galinį tašką, sugeneruokite ir nukopijuokite naują raktą, atnaujinkite gavėją, vėl įjunkite galinį tašką ir nusiųskite pavyzdinį įvykį. Pristatymo sustabdymo metu įvykiai į eilę neįtraukiami. Suplanuokite šį pertrūkį prieš keisdami raktą.
  • Delivery log (Pristatymo žurnalas) - konkretaus galinio taško paskutinių pristatymų sąrašas su laiko žyma, įvykio tipu, Jūsų serverio grąžintu HTTP būsenos kodu ir atsakymo laiku. Čia matomi nesėkmingi pristatymai ir grandinės pertraukiklio (circuit breaker) sustabdymai. Žurnalas saugomas 14 dienų.

Įvykio apvalkalas (envelope)

Kiekvienas pristatymas yra HTTP POST užklausa su Content-Type: application/json. Užklausos turinys visada turi tą patį apvalkalą; data objektas priklauso nuo konkretaus įvykio tipo:

{
  "eventId": "9f1c1c8e-6a2b-4b9e-9d2f-3f8a1e2b4c5d",
  "eventType": "lead.created",
  "timestamp": "2026-08-13T14:22:31Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": { }
}
  • eventId - unikalus kiekvienam įvykiui. Naudokite jį dublikatams pašalinti, jei Jūsų apdorojimas privalo būti idempotentinis.
  • eventType - vienas iš žemiau aprašytų tipų; taip pat siunčiamas X-ChatLab-Event antraštėje.
  • timestamp - ISO 8601 UTC laikas, kada buvo paruoštas pristatymo apvalkalas.
  • botId / botName - botas, kuriam priklauso įvykis.
  • conversationId / sessionId - pokalbio kontekstas, kai taikoma.

Įvykių katalogas

lead.created

Suveikia, kai lankytojas pateikia savo kontaktinius duomenis - per kontaktų surinkimo formą (angl. lead collection form), išankstinę „Live Chat“ formą arba pasirinktinę formą, naudojamą kontaktams rinkti.

{
  "eventId": "9f1c1c8e-6a2b-4b9e-9d2f-3f8a1e2b4c5d",
  "eventType": "lead.created",
  "timestamp": "2026-08-13T14:22:31Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "email": "jane.doe@example.com",
    "name": "Jane Doe",
    "phone": "+1 555 0123",
    "source": "LEAD_COLLECTION_FORM",
    "formCodeName": "lead_form",
    "formName": "Lead form",
    "fields": [
      {"name": "email", "value": "jane.doe@example.com", "type": "email"},
      {"name": "company", "value": "Acme Inc.", "type": "text"},
      {"name": "topics", "value": ["Billing", "Delivery"], "type": "multichoice"},
      {"name": "attachment", "value": "https://api.chatlab.com/aichat/customform/download?key=...&token=...", "type": "file"}
    ],
    "pageUrl": "https://acme.com/pricing"
  }
}
  • source - kaip buvo gauti kontaktiniai duomenys: LEAD_COLLECTION_FORM (kontaktų surinkimo forma), LIVE_CHAT_FORM (išankstinė „Live Chat“ forma), CONVERSATION (DI užfiksavo duomenis pokalbio metu), ADMIN_DATA_UPDATE arba UPDATE_CLIENT_CONTEXT (redaguota „ChatLab“ pusėje). Žmogiškojo palaikymo formos pateikimai niekada nesuaktyvina šio įvykio - vietoje jo jie suaktyvina contact_form.submitted.
  • email, name, phone - kontaktiniai duomenys, susieti su kontakto įrašu.
  • Kai kontaktams rinkti naudojama pasirinktinė forma, kiekvienas joje apibrėžtas laukas įtraukiamas į fields, formos tvarka, o formCodeName / formName identifikuoja formą. Klasikinės kontaktų formos atveju abu yra null, o fields yra tuščias masyvas.
  • Kiekvienas įrašas sąraše fields yra {name, value, type}. name yra techninis lauko pavadinimas, nekintantis redaguojant etiketes - naudokite jį susiejimui su savo CRM.
  • Laukams multichoice reikšmė value yra pasirinktų parinkčių masyvas. Žymimųjų langelių laukai yra atskiri įrašai su reikšmėmis "true" / "false".
  • Laukams file reikšmė value yra įkelto failo atsisiuntimo nuoroda; „webhook“ niekada neperduoda paties failo turinio.
  • pageUrl - puslapis, kuriame lankytojas buvo pateikimo metu.

contact_form.submitted

Suveikia, kai lankytojas pateikia žmogiškojo palaikymo kontaktinę formą arba pasirinktinę formą, skirtą susisiekti su žmogumi.

{
  "eventId": "3a7b9c2d-1e4f-4a6b-8c0d-5e2f7a9b1c3d",
  "eventType": "contact_form.submitted",
  "timestamp": "2026-08-13T14:25:02Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "email": "jane.doe@example.com",
    "message": "I need help with my last invoice.",
    "source": "CUSTOM_FORM",
    "formCodeName": "contact_form",
    "formName": "Contact form",
    "fields": [
      {"name": "email", "value": "jane.doe@example.com", "type": "email"},
      {"name": "order_number", "value": "A-10293", "type": "text"},
      {"name": "message", "value": "I need help with my last invoice.", "type": "textarea"}
    ]
  }
}
  • email - lankytojo nurodytas el. pašto adresas, į kurį turėtų atsakyti Jūsų palaikymo komanda.
  • source - CUSTOM_FORM, kai kontaktinei formai naudojama pasirinktinė forma, ir CONTACT_FORM, kai naudojama integruota forma.
  • formCodeName / formName - identifikuoja už užklausos esančią pasirinktinę formą; abu yra null, jei naudojama integruota forma.
  • Kai naudojama pasirinktinė forma, į fields įtraukiamas kiekvienas joje apibrėžtas laukas (tuo pačiu {name, value, type} formatu kaip ir lead.created). Integruotos kontaktinės formos atveju užpildomi tik email bei message, fields yra tuščias masyvas, o formos identifikatoriai yra null.
  • message - susietas žinutės laukas arba visos užpildytos reikšmės, sujungtos kartu, jei formoje nėra apibrėžto žinutės lauko.

custom_form.submitted

Suveikia kiekvieną kartą pateikus pasirinktinę formą, nepriklausomai nuo jos paskirties. Atkreipkite dėmesį, kad formos, kurių paskirtis yra kontaktų surinkimas arba žmogiškasis kontaktas, taip pat suaktyvina joms skirtą lead.created / contact_form.submitted įvykį - prenumeruokite vieną arba kitą, priklausomai nuo to, ar norite bendro, ar specializuoto rodinio, kad nesukurtumėte dubliuotų verslo veiksmų. Šios dvi įvykių grupės turi skirtingus įvykių ID; conversationId kartu su timestamp nėra patikimas pateikimo identifikatorius.

{
  "eventId": "6c1d8e3f-2a5b-4c7d-9e0f-1a4b6c8d0e2f",
  "eventType": "custom_form.submitted",
  "timestamp": "2026-08-13T14:27:45Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "formCodeName": "warranty_claim",
    "formName": "Warranty claim",
    "fields": [
      {"name": "order_number", "value": "A-10293", "type": "text"},
      {"name": "issue", "value": "Damaged on arrival", "type": "textarea"},
      {"name": "photo", "value": "https://api.chatlab.com/aichat/customform/download?key=...&token=...", "type": "file"}
    ],
    "purpose": "STANDALONE"
  }
}
  • formCodeName - nekintantis techninis formos pavadinimas, kuris nesikeičia perpervadinus formą; naudokite jį pateikimų nukreipimui savo sistemoje. formName yra lankytojams rodomas pavadinimas.
  • fields naudoja tuos pačius {name, value, type} įrašus kaip ir lead.created: kelių pasirinkimų reikšmės yra masyvai, failų reikšmės yra atsisiuntimo nuorodos.
  • purpose - STANDALONE, LEAD_COLLECTION arba HUMAN_CONTACT, priklausomai nuo to, kaip forma yra susieta su pokalbių robotu.

conversation.started

Suveikia, kai lankytojas išsiunčia pirmąją naujo pokalbio žinutę.

{
  "eventId": "8e2f0a4b-3c6d-4e8f-a1b2-2c5d7e9f1a3b",
  "eventType": "conversation.started",
  "timestamp": "2026-08-13T14:20:11Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "firstMessage": "Do you ship to Canada?",
    "chatSource": "WIDGET",
    "byAdmin": false,
    "countryCode": "PL",
    "ipAddress": "83.12.44.7"
  }
}
  • firstMessage - tikslus lankytojo pradinės žinutės tekstas. null, jei pokalbis buvo pradėtas be žinutės turinio.
  • chatSource - kanalas, kuriuo gautas pokalbis: WIDGET, WHATSAPP, MESSENGER, VOICE, VOICE_PHONE, API, BOOKING, AIRBNB arba IDOBOOKING.
  • byAdmin - true, kai pokalbis vyksta iš pokalbių roboto peržiūros „ChatLab“ valdymo skydelyje, o ne iš tikro lankytojo. Naudokite tai, kad bandomieji pokalbiai nepatektų į Jūsų CRM.
  • countryCode - ISO šalies kodas, nustatytas pagal lankytojo IP adresą; null, kai nepavyko nustatyti.
  • ipAddress - „ChatLab“ matomas lankytojo IP adresas; null, kai neprieinamas. Pagal BDAR laikykite jį asmens duomenimis ir saugokite tik turėdami teisėtą pagrindą.

conversation.rated

Suveikia, kai lankytojas pateikia teigiamą arba neigiamą pokalbio įvertinimą (žr. Pokalbio įvertinimas).

{
  "eventId": "1b4c6d8e-5f0a-4b2c-8d3e-4f7a9b1c3d5e",
  "eventType": "conversation.rated",
  "timestamp": "2026-08-13T14:31:09Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "rating": "POSITIVE"
  }
}
  • rating - POSITIVE arba NEGATIVE. Įvertinimo pašalinimas įvykio nesuaktyvina, todėl neutralios reikšmės niekada negausite.

conversation.summarized

Suveikia, kai „ChatLab“ sugeneruoja baigto pokalbio santrauką.

{
  "eventId": "4d7e9f1a-6b2c-4d4e-9f0a-5b8c0d2e4f6a",
  "eventType": "conversation.summarized",
  "timestamp": "2026-08-13T14:45:00Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "summary": "Visitor asked about shipping to Canada and delivery times. The bot confirmed availability and quoted 5-7 business days. Visitor left satisfied.",
    "language": "en_US"
  }
}
  • summary - sugeneruotas santraukos tekstas. Santraukos generavimas yra asinchroninis ir priklauso nuo roboto santraukų konfigūracijos bei apdorojimo grafiko; nesitikėkite fiksuoto pristatymo laiko.
  • language - vidinė roboto lokalė, perduota santraukos generavimui, pavyzdžiui, en_US; nemanykite, kad ji sutampa su lankytojo pokalbio kalba.

client.summarized

Suveikia, kai „ChatLab“ atnaujina kliento DI profilį. Profilis atkuriamas iš ankstesnio profilio bei ką tik pasibaigusio pokalbio santraukos ir gali būti sugeneruotas po conversation.summarized. Pristatymo eiliškumas nėra garantuojamas. Duomenų rinkinyje pateikiamas el. paštas, kai jis yra žinomas, tačiau „ChatLab“ gali turėti ir klientų be el. pašto adreso.

{
  "eventId": "b5d8f1a3-7c2e-4d9b-a6f0-1e3c5a7b9d2f",
  "eventType": "client.summarized",
  "timestamp": "2026-08-18T09:12:04Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "clientEmail": "jane.doe@example.com",
    "client": {
      "email": "jane.doe@example.com",
      "name": "Jane Doe",
      "phone": "+1 555 0123",
      "countryCode": "PL",
      "ipAddress": "83.12.44.7"
    },
    "clientSummary": "Returning customer interested in international shipping. Asked about delivery times to Canada twice and about return costs once."
  }
}
  • clientEmail - identifikatorius, skirtas susieti klientą su Jūsų CRM. Anoniminiams lankytojams, kurie niekada nenurodė adreso, jis yra null, o įvykis jiems vis tiek suveikia - praleiskite šiuos pristatymus, jei Jūsų integracija remiasi el. pašto adresu.
  • client - kontaktinis įrašas, kurį „ChatLab“ turi apie šį asmenį: email, name, phone, countryCode ir ipAddress. Kiekvienas raktas pateikiamas visada; nežinomos reikšmės yra null.
  • clientSummary - visas profilio tekstas kaip paprastas tekstas, o ne skirtumai (angl. diff). Jis pakeičia bet kurią buvusią santrauką, todėl išsaugokite jį perrašydami, o ne pridėdami prie pabaigos.
  • Profilis atkuriamas tik tiems robotams, kuriuose įjungta pokalbių atmintis (angl. chat memory), ir tik tiems pokalbiams, kurie buvo neaktyvūs pakankamai ilgai, kad būtų apibendrinti - tikėkitės šio įvykio praėjus kelioms minutėms po pokalbio pabaigos, o ne iš karto.

live_chat.requested

Suveikia, kai DI perduoda pokalbį į Live Chat (gyvą pokalbį), nes lankytojas paprašė žmogaus arba robotas nusprendė, kad reikalingas žmogus.

{
  "eventId": "7a0b2c4d-8e3f-4a5b-b0c1-6d9e1f3a5b7c",
  "eventType": "live_chat.requested",
  "timestamp": "2026-08-13T14:33:20Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "requestedBy": "AI"
  }
}
  • requestedBy - šiuo metu visada AI, nes perdavimą visada inicijuoja roboto tiesioginio pokalbio veiksmas, įskaitant atvejus, kai lankytojas to paprašo paprastais žodžiais. Vertinkite tai kaip atvirą enum: apdorokite nežinomas reikšmes, o ne tikėkitės tik AI.
  • Šis įvykis apima DI veiksmą, prašantį perdavimo, o ne visus būdus, kuriais lankytojas gali atidaryti gyvą pokalbį. Tai neįrodo, kad operatorius prisijungė.

live_chat.started

Suveikia, kai sukuriamas tiesioginio pokalbio seansas po to, kai pateikiama lankytojo perdavimo forma. Tai įvyksta anksčiau, nei operatorius būtinai prisijungia ar atsako; nelaikykite to žmogaus įsitraukimo įrodymu.

{
  "eventId": "0c3d5e7f-9a4b-4c6d-a1b2-7e0f2a4b6c8d",
  "eventType": "live_chat.started",
  "timestamp": "2026-08-13T14:33:55Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {}
}
  • data sąmoningai yra tuščias. Viskas, ko Jums reikia, yra apvalkale: botId identifikuoja pokalbių robotą, o conversationId / sessionId susieja įvykį su pokalbiu. Galite jį gauti be ankstesnio live_chat.requested, pavyzdžiui, kai lankytojas pasinaudojo valdiklio tiesioginio pokalbio valdikliu.

live_chat.ended

Suveikia, kai baigiasi tiesioginio pokalbio seansas.

{
  "eventId": "2e5f7a9b-0c5d-4e7f-b2c3-8f1a3b5c7d9e",
  "eventType": "live_chat.ended",
  "timestamp": "2026-08-13T14:52:41Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "durationSeconds": 1126
  }
}
  • durationSeconds - praėjusi tiesioginio pokalbio seanso trukmė sekundėmis, skaičiuojama nuo seanso sukūrimo, įskaitant operatoriaus laukimo laiką. Šis laukas praleidžiamas retais atvejais, kai seansas baigiasi taip ir neprasidėjęs.

ai_action.executed

Suveikia kiekvieną kartą, kai robotas įvykdo DI veiksmą (angl. AI action) - valdomą integracijos iškvietimą arba pasirinktinę API funkciją. Tai didelės apimties įvykis: aktyvus el. prekybos robotas gali atlikti šimtus veiksmų per dieną, o viena lankytojo užklausa gali suaktyvinti kelis. Prenumeruokite jį tam skirtame galiniame taške arba įsitikinkite, kad Jūsų imtuvas gali apdoroti tokį srautą.

{
  "eventId": "5f8a0b2c-1d6e-4f8a-c3d4-9a2b4c6d8e0f",
  "eventType": "ai_action.executed",
  "timestamp": "2026-08-13T14:21:03Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "actionName": "search_products",
    "status": "SUCCESS",
    "durationMs": 842,
    "errorMessage": null
  }
}
  • actionName - įvykdyto veiksmo pavadinimas, kaip jį mato DI, pavyzdžiui, search_products valdomai integracijai arba Jūsų suteiktas pasirinktinio API veiksmo pavadinimas.
  • status - SUCCESS arba ERROR.
  • durationMs - kiek laiko truko veiksmas milisekundėmis. Naudinga norint pastebėti lėtą integraciją anksčiau, nei lankytojai pradės ja skųstis.
  • errorMessage - klaidos priežastis, užpildoma tik tada, kai status yra ERROR; priešingu atveju null.

webhook.test

Išsiunčiamas paspaudus mygtuką Send sample event (Siųsti pavyzdinį įvykį), kai atliekate paprastą ryšio patikrinimą. Pasirašytas lygiai taip pat, kaip ir tikras įvykis.

{
  "eventId": "9b2c4d6e-3f8a-4b0c-d5e6-0b3c5d7e9f1a",
  "eventType": "webhook.test",
  "timestamp": "2026-08-13T14:10:00Z",
  "botId": 1234,
  "botName": "Support Bot",
  "conversationId": "conv_a1b2c3",
  "sessionId": "sess_x9y8z7",
  "data": {
    "message": "Test delivery from ChatLab"
  }
}
  • message - fiksuotas tekstas, visada toks pat. Apvalkalo laukuose pateikiamos pavyzdinės reikšmės, todėl niekada nelaikykite webhook.test pristatymo tikrais duomenimis.
  • Tai vienintelis įvykio tipas, kurio negalite užsiprenumeruoti galiniame taške: jis siunčiamas pagal pareikalavimą iš valdymo skydelio ir visada pasiekia galinį tašką, kurį paspaudėte, nepriklausomai nuo to, kokių įvykių jis klausosi.

Saugumas: pristatymų patvirtinimas

Kiekvienas pristatymas turi keturias antraštes:

Antraštė Reikšmė
X-ChatLab-Signature sha256=<hex hmac> - duomenų paketo HMAC-SHA256 parašas
X-ChatLab-Timestamp „Unix“ laikas sekundėmis, kada pristatymas buvo pasirašytas
X-ChatLab-Event Įvykio tipas, pvz., lead.created
X-ChatLab-Delivery Unikalus pristatymo ID, sutampantis su teksto eventId

Parašas apskaičiuojamas kaip HMAC-SHA256 pagal eilutę {timestamp}.{rawBody}, naudojant Jūsų galinio taško paslaptį (angl. endpoint secret), kur {timestamp} yra X-ChatLab-Timestamp reikšmė, o {rawBody} yra neapdorotas, neanalizuotas užklausos tekstas. Visada tikrinkite pagal neapdorotus baitus - pakartotinai serializuotas apdorotas JSON pakeis baitų seką ir sugadins parašą.

Norėdami apsisaugoti nuo pakartotinio siuntimo atakų (angl. replay attacks), atmeskite pristatymus, kurių X-ChatLab-Timestamp yra senesnis nei 5 minutės.

Node.js

const crypto = require('crypto');

function verifyChatLabSignature(req, secret) {
    const signature = req.headers['x-chatlab-signature'];
    const timestamp = req.headers['x-chatlab-timestamp'];
    if (typeof signature !== 'string' || typeof timestamp !== 'string') return false;
    if (!/^\d+$/.test(timestamp) || !Number.isSafeInteger(Number(timestamp))) return false;
    if (!Buffer.isBuffer(req.rawBody)) return false;

    // Reject stale deliveries (older than 5 minutes)
    const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
    if (ageSeconds > 300) return false;

    // rawBody must be the raw request body bytes, not re-serialized JSON.
    // With Express: app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } }))
    const expected = 'sha256=' + crypto
        .createHmac('sha256', secret)
        .update(timestamp + '.')
        .update(req.rawBody)
        .digest('hex');

    const a = Buffer.from(signature);
    const b = Buffer.from(expected);
    return a.length === b.length && crypto.timingSafeEqual(a, b);
}

PHP

<?php
function verifyChatLabSignature(string $secret): bool
{
    $signature = $_SERVER['HTTP_X_CHATLAB_SIGNATURE'] ?? '';
    $timestamp = $_SERVER['HTTP_X_CHATLAB_TIMESTAMP'] ?? '';
    if ($signature === '' || $timestamp === '' || !ctype_digit($timestamp)) {
        return false;
    }

    // Reject stale deliveries (older than 5 minutes)
    if (abs(time() - (int) $timestamp) > 300) {
        return false;
    }

    $rawBody = file_get_contents('php://input');
    $expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);

    return hash_equals($expected, $signature);
}

Jei patvirtinimas nepavyksta, atsakykite su 401 ir atmeskite duomenų paketą. Niekada neapdorokite nepatvirtintų pristatymų - bet kas, sužinojęs Jūsų URL, gali nusiųsti į jį bet kokį JSON.

Pristatymo elgsena

Prieš kurdami integracijas naudodami webhook, susipažinkite su šiomis pristatymo taisyklėmis:

  • Atsakykite greitai. Jūsų galutinis taškas turi atsakyti per 3 sekundes, kitaip pristatymas bus laikomas nesėkmingu. Patvirtinkite parašą, patikimai įtraukite įvykį į eilę ir patvirtinkite gavimą su 2xx kodu per šį laikotarpį. Lėtesnes CRM užklausas ir verslo logikos apdorojimą atlikite asinchroniškai.
  • Vienkartinis išsiuntimas be patvirtinimo („fire-and-forget“), ne daugiau kaip vieną kartą („at-most-once“). Atitinkantys įjungti galutiniai taškai gauna ne daugiau kaip vieną pristatymo bandymą - pakartotinių bandymų nėra. Pristabdyti galutiniai taškai ir suveikę grandinės pertraukikliai („circuit breakers“) gali neleisti atlikti net ir šio bandymo. Jei jūsų galutinis taškas neveikia, baigiasi jo skirtasis laikas arba jis grąžina ne 2xx būsenos kodą, tas įvykis prarandamas ir nebebus pristatytas iš naujo. Webhook pranešimai yra notifikacijos, o ne dubliuojama duomenų saugykla: išsaugotiems duomenims suderinti naudokite Bot Talk API pokalbių galutinius taškus arba potencialių klientų eksportavimą, kur tai palaikoma. Management API apima boto nustatymus ir naudojimo duomenis, o ne visą įvykių archyvą. Kai kurių įvykių per šias sąsajas atkurti neįmanoma.
  • Grandinės pertraukiklis („circuit breaker“). Užfiksavus 5 iš eilės nesėkmingus pristatymus konkrečiai galutinio taško ir boto porai, pristatymai šiai porai pristabdomi 5 minutėms. Per šią pauzę įvykę įvykiai atmetami, o pristatymo žurnale rodomi CIRCUIT_OPEN įrašai, nurodantys užblokuotus bandymus. Pristatymai, praleisti dėl suveikusio grandinės pertraukiklio, neįskaičiuojami į automatinio išjungimo limitą.
  • Automatinis išjungimas. Šis patikrinimas atliekamas tik nepavykus pristatymui, o ne pagal suplanuotą laikmatį. Jei pristatymas nepavyksta ir 7 dienas nebuvo nė vieno sėkmingo pristatymo - skaičiuojant nuo paskutinės sėkmės arba nuo galutinio taško sukūrimo datos, jei sėkmingų bandymų dar nebuvo - galutinis taškas išjungiamas ir Jūs gaunate pranešimą el. paštu. Bet kuriuo metu gautas bent vienas 2xx kodas anuliuoja šį laikotarpį. Galutinis taškas, kuris negauna jokio srauto, niekada neišjungiamas, nes niekas nepatiria nesėkmės. Pataisę savo gavėją, vėl jį įjunkite skiltyje Account settings (paskyros nustatymai); vėl įjungus, nesėkmių skaitiklis ir automatinio išjungimo žyma yra išvalomi, o išjungimo metu praleisti įvykiai nėra atkuriami.
  • 410 Gone. Jei jūsų galutinis taškas atsako HTTP kodu 410 Gone, ChatLab jį nedelsiant išjungia. Naudokite tai norėdami programiškai nutraukti galutinio taško veikimą iš gavėjo pusės.
  • Idempotentiškumas. Įprastai veikiant sistemai pasikartojančių pristatymų neturėtų pasitaikyti, tačiau jei jūsų apdorojimas turi būti griežtai idempotentinis, pašalinkite dublikatus pagal eventId (taip pat prieinamą antraštėje X-ChatLab-Delivery).

Pristatymo eiliškumas nėra garantuojamas. Išsaugokite įvykio ID ir pasirūpinkite, kad verslo procesų apdorojimas būtų idempotentinis. Patys nustatykite prieigos kontrolę ir saugojimo terminus webhook naudingosioms apkrovoms, kuriose gali būti asmens duomenų ir failų atsisiuntimo nuorodų.

Parašo tikrinimo pavyzdžiuose naudojama Node.js crypto biblioteka ir PHP funkcija hash_equals. Užfiksuokite neapdorotą užklausos turinį („raw body“) prieš jį analizuodami.

Apribojimai

  • Iki 10 webhook galutinių taškų vienai paskyrai.
  • Pristatymo žurnalo saugojimo trukmė: 14 dienų. Senesni įrašai pašalinami automatiškai.

Susiję straipsniai