Hvad er et webhook?
Et webhook går i alt sin enkelthed ud på, at hver gang der sker en hændelse (når et call tracking opkald afsluttes i dette tilfælde), så sender vi en forespørgsel til en web-adresse som du konfigurerer. Denne forespørgsel indeholder de væsentligste data vedrørende opkaldet, som du kan gemme eller behandle efter behov. Med vores webhook integration, kan opkaldsdata således synkroniseres mellem vores og dit system. Måske ønsker du at gemme opkaldsdata i din egen database for at sammenkæde data på kryds og tværs. Eller måske ønsker du at tilføje opkald som leads eller kunde i dit CRM-system. Mulighederne er mange. Et webhook gør det væsentligt nemmere at modtage data automatisk end fx en API adgang, da det kræver væsentligt færre udviklingstimer at få opsat. Derudover har et webhook også den fordel, at du modtager data i tæt på realtid.
Vil du vide hvordan Webhook-integrationen opsættes i Trailhub, så se denne guide.
Tekniske detaljer
Umiddelbart efter et opkald er blevet afsluttet, sendes en POST
request til den konfigurererede adresse. Request body består af et JSON objekt bestående af nedenstående felter.
Felt | Type | Beskrivelse |
event | string |
Hvilken hændelse der forårsagede forespørgslen. I øjeblikket er værdien altid call.ended . Vi anbefaler dog at dette felt tjekkes for at håndtere andre event typer der måtte blive tilføjet i fremtiden. |
uuid | UUID (v4) |
Det unikke ID for opkaldet. |
status | string
Værdier:
|
Status for opkaldet. ERROR betyder, at der skete en tele-teknisk eller uspecificeret fejl. Såfremt værdien er ANSWERED , blev opkaldet besvaret, hvorimod dette ikke er tilfældet hvis værdien er UNANSWERED . |
campaign | object |
Et objekt som indeholder detaljer om den kampagne, som opkaldet tilhører. |
campaign.uuid | UUID (v4) |
Det unikke ID for opkaldets kampagne. |
campaign.name | string |
Navnet på den tilhørende kampagne. |
campaign.type | string
Værdier:
|
Typen af kampagne. |
started_at | ISO 8601 |
Hvornår opkaldet startede. |
connected_at | ISO 8601 | NULL |
Hvornår opkaldet blev besvaret. NULL hvis opkaldet ikke blev besvaret, eller hvis status er ERROR . |
ended_at | ISO 8601 | NULL |
Hvornår opkaldet blev afsluttet. NULL hvis status er ERROR . |
duration | integer | NULL |
Varigheden af opkaldet i sekunder. NULL hvis opkaldet ikke blev besvaret, eller hvis status er ERROR . |
caller_id | E.164 | NULL |
Telefon nummeret der blev ringet fra. Hvis der bliver ringet fra et anonymt nummer, er værdien NULL . |
ct_phone_number | E.164 |
Telefon nummeret der blev ringet til (call tracking nummeret). |
params * | object |
Et objekt som indeholder en række standard parametre tilknyttet Trailhub sessionen.
Bemærk at de enkelte parametre udelades hvis der ingen værdi er, så tjek altid om et parameter er tilgængeligt før det bruges. |
params.gclid | string |
Google Click ID. |
params.fbclid | string |
Facebook Click ID. |
params.msclkid | string |
Microsoft Click ID. |
params.utm_campaign | string |
Værdien af utm_campaign query parametret. |
params.utm_source | string |
Værdien af utm_source query parametret. |
params.utm_medium | string |
Værdien af utm_medium query parametret. |
params.utm_content | string |
Værdien af utm_content query parametret. |
params.utm_term | string |
Værdien af utm_term query parametret. |
params.ga_cid | string |
Google Analytics Client ID (CID). Tilføjes kun hvis Google Analytics integrationen er slået til. |
params.ga_sid | string |
Google Analytics Session ID (SID). Tilføjes kun hvis Google Analytics 4 integrationen er slået til. |
params._gcl_aw | string |
Værdien af _gcl_aw cookie. |
params._fbc | string |
Værdien af _fbc cookie. |
params._fbp | string |
Værdien af _fbp cookie. |
consent * | object |
Detaljer om hvilke cookies den besøgende gav consent for. Tilføjes kun hvis den besøgende har afgivet consent og vi lykkedes med at læse denne.
I øjeblikket understøttes Cookiebot og CookieInformation. |
consent.platform | string |
Hvilken Consent Management Platform (CMP) der er implementeret.
Værdier: |
consent.necessary | boolean |
Hvorvidt den besøgende har tilladt nødvendige cookies. |
consent.functional | boolean |
Hvorvidt den besøgende har tilladt funktionelle cookies. |
consent.statistics | boolean |
Hvorvidt den besøgende har tilladt statistik cookies. |
consent.marketing | boolean |
Hvorvidt den besøgende har tilladt marketing cookies. |
page_url * | string | NULL |
Den fulde sti på siden der blev ringet fra. |
page_title * | string | NULL |
Titlen på siden der blev ringet fra. |
* Tilføjes kun for opkald på dynamiske kampagner.
Forespørgslen bliver sendt med en User-Agent
header som er sat til trailhub/<version>
, fx trailhub/1.0
.
Adressen vi sender forespørgsler til, skal kryptere trafik med TLS (ofte kendt som SSL eller HTTPS). Dette er af hensyn til sikkerhed, da vi vil beskytte dine såvel som vores data bedst muligt. Vi understøtter derfor heller ikke self-signed certifikater.
For at en forespørgsel kategoriseres som succesfuldt, skal adressen besvare vores forespørgsel med en HTTP status der er imellem 200
og 300
(2xx
), førstnævnte inklusiv. Såfremt dette ikke er tilfældet, forsøger vi at sende forespørgslen igen, indtil den accepteres eller alle forsøg er opbrugte. Læs mere i afsnittet om timeouts og retries. Dette betyder også, at vi ikke understøtter redirects for webhooks.
Bemærk at adressen skal være offentligt tilgængelig (dog meget gerne beskyttet ved hjælp af autentificering). Dette skyldes, at vores servere kører i skyen, så vi har ikke mulighed for at dele en liste af IP adresser som kan whitelistes.
Headers
Det er muligt at konfigurere op til fem HTTP headers som som vi sender med hver forespørgsel. Dette bruges typisk i forbindelse med autentificering, men kan være nyttigt såfremt det ønskes at sende ekstra værdier med forespørgsler. Et alternativ til dette kan også være URL parametre. Vi anbefaler at ikke-standard headers prefixes med X-
, fx X-My-Header
. Vi anbefaler så vidt muligt at der ikke benyttes standard HTTP headers (med undtagelse af de, som er relaterede til autentificering), da disse kan blive overskrevne af vores HTTP klient.
Autentificering
Af hensyn til sikkerhed, anbefaler vi at den konfigurerede adresse kræver autentificering, således at den ikke er offentligt tilgængelig. Dette kan gøres på forskellige måder. Nedenfor kan du se, hvordan autentificering kan konfigureres for webhook integrationen, afhængig af hvordan autentificeringen er opsat på din webhook adresse.
Alt data som indtastes i forbindelse med opsætningen, bliver gemt krypteret på vores servere, så eventuelt følsomme data opbevares sikkert.
Query Parameter & Custom Header
Dette er de nemmeste måder at sikre webhook adressen på. Indsæt ganske enkelt et query parameter i adressen vi skal sende forespørgsler til, fx https://api.example.com/webhook?token=abc123
. Navnet på parametret er valgfrit. Når vi sender en forespørgsel til adressen, skal værdien for parametret (token
i dette tilfælde) valideres til at matche den indtastede værdi (abc123
i dette eksempel). Eftersom vi kun tillader krypteret trafik fra vores servere, bliver parametret samt stien på adressen krypteret med TLS, og kan derfor ikke opsnappes af uvedkommende mellem vores og jeres server. Vi krypterer ydermere hele den konfigurerede adresse på vores servere. Alternativt kan værdien også sendes med som en custom HTTP header, fx navngivet X-API-Token
.
Som nævnt er dette de nemmeste måder at autentificere forespørgsler på, men vi anbefaler at benytte en af nedenstående standard løsninger.
HTTP Basic Authentication
»HTTP basic access authentication« er en standard måde at autentificere på over HTTP, da den er indbygget direkte i HTTP specifikationen, og understøttes således af alle browsere, HTTP klienter, osv. Opsætningen består af at tilføje en Authorization
HTTP header med værdien Basic <credentials>
. <credentials>
skal her være username:password
som en base64 encoded tekst, fx Basic dXNlcm5hbWU6cGFzc3dvcmQ=
. Som en hjælp, kan du under opsætningen undlade at base64 encode værdien; når opsætningen gemmes, sørger vi for at encode værdien korrekt.
Bearer Token
Ved at tilføje en Authorization
HTTP header med værdien Bearer <credentials>
, kan man sende en token med hver forespørgsel, som så valideres på modtagers server. <credentials>
er i dette tilfælde den token som sendes med, mens Bearer
indikerer typen af autentificering. En såkaldt »bearer token« bruges ofte i OAuth 2.0 API’er, eller i forbindelse med JSON Web Tokens (JWT).
Shared Secret (HMAC)
En »shared secret« er en hemmelig værdi som er delt imellem parter – helst kun to. Tilføjes en shared secret til opsætningen, benytter vi denne til at beregne en hash værdi for det JSON objekt som sendes i request body. Til at beregne denne hash værdi, benytter vi den indtastede shared secret. Resultatet er en såkaldt HMAC. Vi benytter SHA-256 hashing algoritmen til dette, og værdien tilføjes til en X-Signature
header som sendes med hver forespørgsel. Det er vigtigt at understrege, at dette ikke betyder, at vi krypterer eller hasher selve det data vi sender; hash værdien har ikke til formål at skjule data for uvedkommende. Den tillader i stedet modtageren at validere både afsenderen af data, samt integriteten af det sendte data. Når en forespørgsel modtages, beregner modtageren en hash værdi ud fra det sendte data og den samme shared secret. Det er vigtigt at der benyttes den samme hashing algoritme til formålet. Hvis den beregnede hash værdi matcher den som vi har tilsendt i X-Signature
headeren, så kan du stole på, at det modtagne data kommer fra os, samt at data ikke er blevet modificeret på vejen.
Da denne form for autentificering afhænger af den konfigurerede shared secret, er det ekstremt vigtigt at denne beskyttes og holdes hemmelig. Hvis andre får adgang til denne nøgle, kan de fabrikere en forespørgsel der ser ud som om den kommer fra os. Løsningen er derfor kun ligeså god som i det omfang nøglen holdes hemmelig mellem parterne (jeres og vores system). Derfor gør vi ekstra meget ud af at opbevare jeres nøgle sikkert, og vi krypterer den således med vores egen nøgle før vi lagrer den.
Timeouts & Retries
Når vi sender en forespørgsel, venter vi i op til fem sekunder på et svar. Modtager vi ikke et svar indenfor fem sekunder, betegner vi forespørgslen som fejlet. Det samme gør sig gældende hvis et eventuelt svar ikke har en 2xx
status kode. For at minimere risikoen for at opkald mistes såfremt den konfigurerede adresse er utilgængelig, forsøger vi at gensende fejlede forespørgsler op til ni gange. Det vil sige, at vi i alt prøver at sende et opkald ti gange. Er adressen stadig utilgængelig efter ti forsøg, opgiver vi at sende opkaldet. Det er derfor vigtigt at minimere eventuel nedetid på den konfigurerede adresse, da det kan have indflydelse på vores evne til at levere opkald. Udfald kan dog forekomme, eksempelvist på grund af ustabile netværksforbindelser. Derfor venter vi 15 minutter mellem hvert forsøg, således at kortvarig nedetid ikke resulterer i mistede opkald.
Det kan sjældent forekomme, at vi leverer et opkald mere end én gang. Dette kan ske, hvis modtager ikke besvarer en forespørgsel indenfor fem sekunder, men faktisk behandler forespørgslen korrekt – ved eksempelvist at gemme opkaldet i en database. Fordi vores forespørgslen får timeout, betragter vi denne som fejlet, og prøver igen senere. Dette vil således kun ske hvis systemet på modtager adressen er ustabilt og svarer ekstremt langsomt (fem sekunder er lang tid). Selvom dette meget sjældent bør forekomme (forudsat at modtager systemet opererer stabilt), anbefaler vi for en sikkerheds skyld at tjekke, om et givent opkald allerede er blevet modtaget. Dette kan gøres ved hjælp af uuid
feltet.