Webhookien yleiskatsaus
Webhookien avulla ChatLab voi ilmoittaa järjestelmillesi heti, kun chatboteissasi tapahtuu jotain. Sen sijaan, että kyselisit tietoja Management API:sta tai veisit niitä manuaalisesti, rekisteröit HTTPS-päätepisteen ja ChatLab lähettää siihen allekirjoitetun HTTP POST -pyynnön reaaliajassa - kun vierailija jättää liidin, lähettää yhteydenottolomakkeen, arvioi keskustelun, pyytää ihmisasiakaspalvelijaa tai kun tekoälytoiminto suoritetaan.
Tyypillisiä käyttötarkoituksia:
- siirrä uudet liidit suoraan CRM-järjestelmääsi heti niiden tallennushetkellä
- ilmoita tiimillesi Slackissa, kun vierailija pyytää live-chattia
- syötä keskustelujen arviot ja yhteenvedot suoraan omaan analytiikkaasi
- seuraa AI action -toimintojen (tekoälytoimintojen) suorituksia ja hälytä virheistä
Saatavuus: tilisi täytyy sisältää Webhooks -ominaisuus.
Missä määritys tehdään: avaa hallintasovelluksessa Account settings -> Webhooks (Tilin asetukset -> Webhookit) (aivan Management API -osion vieressä). Webhookit ovat tilitason toiminto - yksi päätepiste voi vastaanottaa tapahtumia kaikista boteistasi tai yhdestä valitusta botista.
Päätepisteen käyttöönotto
- Avaa Account settings -> Webhooks ja napsauta Add endpoint (Lisää päätepiste).
- Täytä päätepisteen lomake:
- Name (Nimi) - oma tunniste viitteeksi, esim. "CRM-synkronointi" tai "Slack-hälytykset".
- URL (Osoite) - HTTPS-osoite, johon ChatLab lähettää tapahtumat POST-pyyntöinä.
- Events (Tapahtumat) - valitse, mitä tapahtumatyyppejä tämä päätepiste vastaanottaa (katso alla oleva luettelo). Valitse vain ne, joita tarvitset; suuren volyymin tapahtumat, kuten
ai_action.executed, voivat aiheuttaa paljon liikennettä. - Bot filter (Bisuodatin) (valinnainen) - valitse yksi botti tai All bots (Kaikki botit) kaikille tilisi boteille.
- Custom form filter (Mukautetun lomakkeen suodatin) (valinnainen) - ohjaa tietyn mukautetun lomakkeen lähetykset tähän päätepisteeseen. Se rajaa vain tapahtumaa
custom_form.submitted; kaikki muut tilaamasi tapahtumat (liidit, yhteydenottopyynnöt, keskustelut, live-chat, tekoälytoiminnot) toimitetaan tästä asetuksesta riippumatta.
- Lähetä lomake. Päätepisteen salaisuus (secret) näytetään vain kerran vahvistusikkunassa - kopioi se heti talteen ja säilytä sitä turvallisesti. Tarvitset sitä allekirjoitusten vahvistamiseen (katso kohta Turvallisuus alla). Selväkielistä salaisuutta ei voi hakea myöhemmin.
Jokaisella päätepisteellä on lisäksi:
- Ota käyttöön / poista käytöstä -kytkin (Enable/disable toggle) - keskeytä toimitukset poistamatta päätepistettä. Käytöstä poistetut päätepisteet hylkäävät tapahtumat hiljaisesti (niitä ei laiteta jonoon myöhempää varten).
- Send sample event (Lähetä esimerkkitapahtuma) - toimittaa allekirjoitetun testipyynnön URL-osoitteeseesi, jotta voit varmistaa vastaanottimesi toiminnan päästä päähän. Voit valita tapahtumatyypin ja muokata esimerkkisisältöjä ennen lähettämistä, jotta käsittelijäsi saa realistista dataa. Testi saapuu tavallisena toimituksena, jonka
eventTypevastaa valintaasi (tai muodossawebhook.test, jos kyseessä on pelkkä yhteyden tarkistus). - Roll secret (Vaihda salaisuus) - luo uuden salaisuuden ja mitätöi vanhan. Käytä tätä, jos salaisuus on saattanut vuotaa. Uusi salaisuus näytetään jälleen vain kerran. Hallitun vaihdon tekemiseksi keskeytä päätepisteen toiminta, generoi ja kopioi uusi salaisuus, päivitä vastaanotin, kytke päätepiste takaisin päälle ja lähetä esimerkkitapahtuma. Keskeytyksen aikana tulleita tapahtumia ei aseteta jonoon. Ota tämä katkos huomioon ennen vaihtoa.
- Delivery log (Toimitusloki) - päätepistekohtainen luettelo viimeaikaisista toimituksista, joka sisältää aikaleiman, tapahtumatyypin, palvelimesi palauttaman HTTP-tilakoodin sekä vasteajan. Epäonnistuneet toimitukset ja automaattiset suojakatkaisut (circuit breaker) näkyvät täällä. Loki säilytetään 14 päivää.
Tapahtumapaketti (Event envelope)
Jokainen toimitus on HTTP POST -pyyntö otsikolla Content-Type: application/json. Rungossa on aina sama pakettirakenne; data-objekti määräytyy tapahtumatyypin mukaan:
{
"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- uniikki tunniste tapahtumaa kohden. Käytä tätä duplikaattien poistamiseen, jos käsittelyn on oltava idempotenttia.eventType- yksi alla dokumentoiduista tyypeistä; lähetetään myösX-ChatLab-Event-otsakkeessa.timestamp- ISO 8601 UTC -aika, jolloin toimituspaketti luotiin.botId/botName- botti, jolle tapahtuma kuuluu.conversationId/sessionId- keskustelukonteksti soveltuvin osin.
Tapahtumaluettelo
lead.created
Käynnistyy, kun vierailija lähettää yhteystietonsa - liidien keruulomakkeen, live-chatin esilomakkeen tai liidien keräämiseen käytetyn mukautetun lomakkeen kautta.
{
"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- tapa, jolla yhteystiedot kerättiin:LEAD_COLLECTION_FORM(liidien keruulomake),LIVE_CHAT_FORM(live-chatin esilomake),CONVERSATION(tekoäly poimi tiedot keskustelun aikana),ADMIN_DATA_UPDATEtaiUPDATE_CLIENT_CONTEXT(muokattu ChatLabin puolelta). Asiakaspalvelulomakkeen lähetykset eivät koskaan käynnistä tätä tapahtumaa - ne käynnistävät sen sijaan tapahtumancontact_form.submitted.email,name,phone- liiditietueeseen yhdistetyt yhteystiedot.- Kun liidien keräämiseen käytetään mukautettua lomaketta, jokainen kyseiseen lomakkeeseen määritetty kenttä sisällytetään kohtaan
fieldslomakkeen mukaisessa järjestyksessä, jaformCodeName/formNameyksilöivät lomakkeen. Perinteisen liidilomakkeen kohdalla molemmat ovatnulljafieldson tyhjä taulukko. - Jokainen merkintä kohdassa
fieldson muotoa{name, value, type}.nameon kentän tekninen nimi, joka pysyy samana otsikkomuutoksista huolimatta - käytä sitä kenttien yhdistämiseen CRM-järjestelmässäsi. multichoice-kentissävalueon valittujen vaihtoehtojen taulukko. Valintaruutukentät ovat yksittäisiä merkintöjä arvoilla"true"/"false".file-kentissävalueon ladatun tiedoston latauslinkki; webhook ei koskaan sisällä tiedoston varsinaista sisältöä.pageUrl- sivu, jolla vierailija oli lomakkeen lähettäessään.
contact_form.submitted
Käynnistyy, kun vierailija lähettää asiakaspalvelun yhteydenottolomakkeen tai asiakaspalvelukontaktiin käytetyn mukautetun lomakkeen.
{
"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- osoite, jonka vierailija jätti ja johon asiakastukitiimisi tulisi vastata.source-CUSTOM_FORM, kun yhteydenottolomakkeen taustalla on mukautettu lomake,CONTACT_FORMsisäänrakennetulle lomakkeelle.formCodeName/formName- yksilöivät pyynnön taustalla olevan mukautetun lomakkeen; molemmat ovatnullsisäänrakennetulle lomakkeelle.- Kun käytetään mukautettua lomaketta, jokainen siihen määritetty kenttä sisällytetään kohtaan
fields(sama{name, value, type}-muoto kuin tapahtumassalead.created). Sisäänrakennetulla yhteydenottolomakkeella vainemailjamessagetäytetään,fieldson tyhjä taulukko ja lomaketunnisteet ovatnull. message- yhdistetty viestikenttä, tai kaikki täytetyt arvot yhdistettynä toisiinsa, jos lomakkeeseen ei ole määritetty erillistä viestikenttää.
custom_form.submitted
Käynnistyy jokaisesta mukautetun lomakkeen lähetyksestä riippumatta lomakkeen käyttötarkoituksesta. Huomaa, että lomakkeet, joiden tarkoituksena on liidien keruu tai asiakaspalvelukontakti, käynnistävät myös niille omistetun lead.created- tai contact_form.submitted -tapahtuman. Tilaa jompikumpi sen mukaan, haluatko yleisen vai erikoistuneen näkymän, jotta et luo päällekkäisiä toimintoja järjestelmääsi. Näillä kahdella tapahtumaperheellä on eri tapahtumatunnukset; conversationId yhdistettynä timestamp-arvoon ei ole luotettava lähetyksen tunniste.
{
"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- lomakkeen pysyvä tekninen nimi, joka ei muutu, vaikka nimeät lomakkeen uudelleen; käytä sitä lähetysten reitittämiseen omassa järjestelmässäsi.formNameon vierailijoille näkyvä otsikko.fieldskäyttää samoja{name, value, type}-merkintöjä kuinlead.created: monivalintojen arvot ovat taulukoita ja tiedostojen arvot ovat latauslinkkejä.purpose-STANDALONE,LEAD_COLLECTIONtaiHUMAN_CONTACTsen mukaan, miten lomake on kytketty chatbotiin.
conversation.started
Käynnistyy, kun vierailija lähettää uuden keskustelun ensimmäisen viestin.
{
"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- vierailijan aloitusviestin tarkka teksti.null, jos keskustelu avattiin ilman viestisisältöä.chatSource- kanava, josta keskustelu tuli:WIDGET,WHATSAPP,MESSENGER,VOICE,VOICE_PHONE,API,BOOKING,AIRBNBtaiIDOBOOKING.byAdmin-true, kun keskustelu tulee chatbotin esikatselusta ChatLabin hallintapaneelista eikä oikealta vierailijalta. Käytä tätä omien testikeskustelujesi rajaamiseen pois CRM-järjestelmästä.countryCode- vierailijan IP-osoitteesta määritetty ISO-maakoodi,nullsilloin kun sitä ei voitu määrittää.ipAddress- vierailijan IP-osoite ChatLabin havaitsemana,nullsilloin kun se ei ole saatavilla. Käsittele sitä GDPR:n mukaisena henkilötietona ja tallenna se vain, jos sinulla on siihen laillinen peruste.
conversation.rated
Käynnistyy, kun vierailija antaa keskustelulle positiivisen tai negatiivisen arvion (katso Keskustelun arviointi).
{
"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-POSITIVEtaiNEGATIVE. Arvion poistaminen ei käynnistä tapahtumaa, joten neutraalia arvoa ei koskaan vastaanoteta.
conversation.summarized
Käynnistyy, kun ChatLab luo yhteenvedon päättyneestä keskustelusta.
{
"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- luotu yhteenvetoteksti. Yhteenvedon luonti on asynkronista ja riippuu botin yhteenvetoasetuksista sekä käsittelyaikataulusta; älä oleta toimitukselle kiinteää viivettä.language- botin sisäinen kielialue, joka välitettiin yhteenvedon luontiin, esimerkiksien_US; älä oleta tämän vastaavan vierailijan keskustelukieltä.
client.summarized
Käynnistyy, kun ChatLab päivittää asiakkaan tekoälyprofiilin. Profiili muodostetaan uudelleen aiemman profiilin sekä juuri päättyneen keskustelun yhteenvedon pohjalta, ja se saatetaan luoda tapahtuman conversation.summarized jälkeen. Toimitusjärjestystä ei taata. Hyötykuorma sisältää sähköpostiosoitteen silloin kun se on tiedossa, mutta ChatLab voi säilyttää tietoja myös asiakkaista, joilla ei ole sähköpostiosoitetta.
{
"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- tunniste asiakkaan yhdistämiseen omaan CRM-järjestelmääsi. Se onnullanonyymeille vierailijoille, jotka eivät koskaan jättäneet osoitettaan, ja tapahtuma käynnistyy heillekin - ohita nämä toimitukset, jos integraatiosi perustuu sähköpostiosoitteeseen.client- yhteystietue, jonka ChatLab pitää tallessa tästä henkilöstä:email,name,phone,countryCodejaipAddress. Jokainen avain on aina läsnä; tuntemattomat arvot ovatnull.clientSummary- koko profiiliteksti pelkkänä tekstinä, ei muutoserona (diff). Se korvaa edellisen yhteenvedon kokonaisuudessaan, joten tallenna se ylikirjoituksena sen sijaan, että lisäisit sen perään.- Profiili muodostetaan uudelleen vain boteille, joissa chat-muisti on käytössä, ja vain keskusteluille, jotka ovat olleet toimettomina riittävän pitkään yhteenvedon tekemistä varten - odota tämän tapahtuman saapuvan minuuttien kuluttua keskustelun päättymisestä, ei välittömästi.
live_chat.requested
Käynnistyy, kun tekoäly siirtää keskustelun Live Chat -toimintoon (live-chat) joko siksi, että vierailija pyysi ihmistä, tai siksi, että botti päätteli ihmisen olevan tarpeen.
{
"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- tällä hetkellä ainaAI, koska siirron tekee aina botin live-chattoiminto, silloinkin kun vierailija pyytää sitä suoraan sanallisesti. Käsittele tätä avoimena luettelotyyppinä: varaudu tuntemattomiin arvoihin sen sijaan, että olettaisit arvon olevan ainaAI.- Tämä tapahtuma kattaa tekoälytoiminnon tekemän siirtopyynnön, ei kaikkia tapoja, joilla vierailija voi avata live-chatin. Se ei vahvista sitä, että asiakaspalvelija olisi liittynyt keskusteluun.
live_chat.started
Käynnistyy, kun live-chatin istunto luodaan sen jälkeen, kun vierailija on lähettänyt siirtolomakkeen. Tämä tapahtuu ennen kuin asiakaspalvelija välttämättä liittyy keskusteluun tai vastaa siihen; älä pidä tätä todisteena ihmisen osallistumisesta.
{
"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": {}
}
dataon tarkoituksellisesti tyhjä. Kaikki tarvittava löytyy kuoresta:botIdyksilöi chatbotin jaconversationId/sessionIdsitovat tapahtuman keskusteluun. Saatat vastaanottaa tämän ilman aiempaalive_chat.requested-tapahtumaa esimerkiksi silloin, kun vierailija käytti widgetin live-chat-painiketta.
live_chat.ended
Käynnistyy, kun live-chat-istunto päättyy.
{
"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- live-chat-istunnon kesto sekunteina istunnon luomisesta laskettuna, mukaan lukien asiakaspalvelijan odotusaika. Kenttä jätetään pois niissä harvoissa tapauksissa, joissa istunto päättyy ennen kuin se ehti koskaan alkaa.
ai_action.executed
Käynnistyy joka kerta, kun botti suorittaa AI action -toiminnon (tekoälytoiminto) - hallinnoidun integraatiokutsun tai mukautetun API-funktion. Tämä on suuren volyymin tapahtuma: aktiivinen verkkokauppabotti voi suorittaa satoja toimintoja päivässä, ja vierailijan yksittäinen viestivuoro voi laukaista niistä useita. Tilaa se erilliseen päätepisteeseen tai varmista, että vastaanottimesi pystyy käsittelemään suuren määrän kutsuja.
{
"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- suoritetun toiminnon nimi siten kuin tekoäly sen näkee, esimerkiksisearch_productshallinnoidulle integraatiolle tai antamasi nimi mukautetulle API-toiminnolle.status-SUCCESStaiERROR.durationMs- toiminnon kesto millisekunteina. Hyödyllinen hitaan integraation havaitsemiseen ennen kuin vierailijat valittavat siitä.errorMessage- epäonnistumisen syy, täytetään vain kunstatusonERROR; muulloinnull.
webhook.test
Lähetetään Send sample event -painikkeesta (lähetä esimerkkitapahtuma), kun suoritat tavallisen yhteyden tarkistuksen. Allekirjoitettu täsmälleen kuten oikea tapahtuma.
{
"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- kiinteä teksti, aina sama. Kuoren kentät sisältävät esimerkkikenttiä, joten älä koskaan käsittelewebhook.test-toimitusta oikeana datana.- Tämä on ainoa tapahtumatyyppi, jota et voi tilata päätepisteeseen: se lähetetään erikseen hallintapaneelista ja saapuu aina klikkaamaasi päätepisteeseen riippumatta siitä, mitä tapahtumia se kuuntelee.
Tietoturva: toimitusten todentaminen
Jokainen toimitus sisältää neljä otsaketta:
| Otsake | Arvo |
|---|---|
X-ChatLab-Signature |
sha256=<hex hmac> - hyötykuorman HMAC-SHA256-allekirjoitus |
X-ChatLab-Timestamp |
Unix-aika sekunteina, jolloin toimitus allekirjoitettiin |
X-ChatLab-Event |
Tapahtumatyyppi, esim. lead.created |
X-ChatLab-Delivery |
Yksilöllinen toimitustunnus, sama kuin leipätekstin eventId |
Allekirjoitus lasketaan HMAC-SHA256-tiivisteenä merkkijonosta {timestamp}.{rawBody} käyttäen päätepisteen salaista avainta (secret), missä {timestamp} on X-ChatLab-Timestamp-otsakkeen arvo ja {rawBody} on pyynnön raaka, jäsentämätön leipäteksti. Vahvista allekirjoitus aina raakoja tavuja vasten - jäsennetyn JSON-datan uudelleensarjoittaminen muuttaa tavujärjestystä ja rikkoo allekirjoituksen.
Suojautuaksesi toistohyökkäyksiltä hylkää toimitukset, joiden X-ChatLab-Timestamp on vanhempi kuin 5 minuuttia.
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);
}
Jos vahvistus epäonnistuu, vastaa tilakoodilla 401 ja hylkää hyötykuorma. Älä koskaan käsittele vahvistamattomia toimituksia - kuka tahansa osoitteesi löytävä voi lähettää siihen mielivaltaista JSON-dataa POST-pyynnöllä.
Toimituksen toimintatapa
Ymmärrä nämä toimitussäännöt ennen webhookien varaan rakentamista:
- Vastaa nopeasti. Päätepisteen on vastattava 3 sekunnin kuluessa, tai toimitus katsotaan epäonnistuneeksi. Vahvista allekirjoitus, aseta tapahtuma luotettavasti jonoon ja kuittaa tilakoodilla
2xxtämän aikarajan puitteissa. Suorita hitaammat CRM-kutsut ja liiketoimintalogiikka asynkronisesti. - Fire-and-forget, enintään kerran. Vastaavat käytössä olevat päätepisteet saavat enintään yhden toimitusyrityksen - uudelleenyrityksiä ei ole. Pysäytetyt päätepisteet ja avoimet virrankatkaisijat voivat estää jopa tämän yrityksen. Jos päätepisteesi on alhaalla, aikakatkaistaan tai se palauttaa muun kuin 2xx-tilakoodin, kyseinen tapahtuma menetetään eikä sitä toimiteta uudelleen. Webhookit ovat ilmoituksia, eivät replikoitu tietovarasto: käytä Bot Talk API conversation endpoints -rajapintoja tai liidien vientiä säilytettyjen tietojen täsmäyttämiseen siltä osin kuin niitä tuetaan. Management API kattaa botin asetukset ja käyttötiedot, ei täydellistä tapahtuma-arkistoa. Joitakin tapahtumia ei voi luoda uudelleen näiden liittymien kautta.
- Virrankatkaisin (circuit breaker). Kun toimitus epäonnistuu 5 kertaa peräkkäin tietyn päätepisteen ja botin parilta, toimitukset kyseiselle parille keskeytetään 5 minuutiksi. Keskeytyksen aikana tapahtuvat tapahtumat hylätään, ja toimituslokissa näkyy
CIRCUIT_OPEN-merkintöjä estettyjen yritysten tunnistamiseksi. Avoimen virrankatkaisijan ohittamia toimituksia ei lasketa mukaan automaattiseen käytöstäpoistoon. - Automaattinen käytöstäpoisto. Tarkistus suoritetaan sillä hetkellä, kun toimitus epäonnistuu, ei koskaan ajastimella. Jos toimitus epäonnistuu eikä 7 päivään ole ollut yhtään onnistunutta toimitusta - laskettuna viimeisimmästä onnistumisesta tai päätepisteen luontipäivästä, jos se ei ole koskaan onnistunut - päätepiste kytketään pois päältä ja saat sähköposti-ilmoituksen. Yksikin
2xx-vastaus milloin tahansa nollaa tämän laskurin. Päätepistettä, joka ei vastaanota liikennettä, ei koskaan poisteta käytöstä, koska mikään ei epäonnistu. Ota se uudelleen käyttöön Account settings (Tilin asetukset) -osiosta, kun vastaanottimesi on korjattu; virhelaskuri ja automaattisen käytöstäpoiston aikaleima tyhjennetään, kun kytket sen takaisin päälle, eikä sen poissaolon aikana menetettyjä tapahtumia täydennetä jälkikäteen. - 410 Gone. Jos päätepisteesi vastaa HTTP-tilakoodilla
410 Gone, ChatLab poistaa sen käytöstä välittömästi. Käytä tätä päätepisteen ohjelmalliseen poistamiseen vastaanottavalta puolelta. - Idempotenssi. Toimitusten kaksoiskappaleita ei normaalissa toiminnassa pitäisi esiintyä, mutta jos käsittelysi on oltava täysin idempotenttia, poista kaksoiskappaleet käyttämällä
eventId-tunnistetta (saatavilla myösX-ChatLab-Delivery-otsakkeessa).
Toimitusjärjestystä ei taata. Tallenna tapahtumatunniste ja tee liiketoimintalogiikasta idempotenttia. Huolehdi omista säilytysajoistasi ja pääsynhallinnastasi webhook-kuormille, jotka saattavat sisältää henkilötietoja ja tiedostojen latauslinkkejä.
Allekirjoitusesimerkit käyttävät kirjastoja Node.js crypto ja PHP:n hash_equals. Tallenna pyynnön raakarunko (raw body) ennen sen jäsentämistä.
Rajoitukset
- Enintään 10 webhook-päätepistettä tiliä kohden.
- Toimituslokien säilytysaika: 14 päivää. Vanhemmat merkinnät poistetaan automaattisesti.
Liittyvät artikkelit
- Liidien kerääminen - lomake tapahtuman
lead.createdtaustalla - Human Support Contact form - lomake tapahtuman
contact_form.submittedtaustalla - Live Chat - työnkulku tapahtumien
live_chat.*taustalla - Keskustelun arviointi - peukku ylös/alas tapahtuman
conversation.ratedtaustalla - AI Actions - integraatiot tapahtuman
ai_action.executedtaustalla - Chat API - selaimen widget-takaisinkutsut (asiakaspuolen vastine webhoodeille)
- Management API - REST-rajapinta botin hallintaan ja käyttötietoihin