Webhooks

I denne artikel:


    Introduktion

       Du kan bruge webhooks til at modtage notifikationer om særlige begivenheder i shoppen. Webhooks lader din applikation reagere på begivenheder umiddelbart efter de sker i shoppen, i stedet for periodisk at skulle hente data via API'et. For eksempel kan du bruge webhooks til at udløse en handling i din applikation når en kunde opretter en ordre, eller når en ordre afsendes. Ved at bruge webhooks kan du lave færre API kald alt i alt, hvilket gør at din applikation er mere effektiv og opdateres hurtigt.

     

    Webhooks indhold

    Efter du har oprettet et webhook, vil du med hvert event som indeholder det emne du har specificeret, modtage en notifikation herom. Denne notifikation indeholder et JSON indkodet payload med relevante data og HTTP headers, som indeholder emnet for notifikationen.

    I HTTP anmodningens body ligger et JSON indkodet payload. I øjeblikket suppleres udelukkende ID'et af det påvirkede element (gælder både for ordrer og produkter). For eksempel vil en orders/created notifikation for et ordre ID some-order-id indeholde følgende i sit HTTP request body:

    {"id":"some-order-id"}

    Ud over informationerne i body, suppleres med yderligere informationer via følgende headers (i forlængelse af eksemplet ovenfor):

    • X-Hmac-Sha256: yRpDZI7InNvbWUtb5JkZXItaWQifV1dE5VjyVtZZ7m9moybIzqd7bRQnclM0jLcG4SDJgfQ
    • X-Webhook-Topic: orders/created
    • X-Shop-Domain: https://...(URI)

    Du behøver ikke nødvendigvis bruge denne information til noget, men den kan benyttes til at udbygge funktionaliteten og sikkerheden i din applikation. For eksempel X-Hmac-Sha256 benyttes til at verificere webhooks og X-Shop-Domain benyttes til at identificere hvilken shop det udløste event er associeret med.

     

    Understøttede handlinger

    Følgende er en komplet liste over understøttede handlinger, efter kategori:

    Kategori Handlinger (events)
    Ordrer orders/cancelledorders/createdorders/fulfilledorders/invoiceorders/partially-fulfilledorders/updated
    Produkter products/createdproducts/updatedproducts/deleted

     

    Konfiguration af Webhooks

    Opsætning af webhooks via shoppens administration
    Du finder webhooks under Indstillinger > Webhooks:

    Hvis du endnu ikke har oprettet nogle webhooks møder du denne side. Klik på "Opret webhook":

    Angiv et Navn, vælg hvilket Event dit webhooks skal reagere på og indsæt den ønskede Adresse (Adresse feltet udgør din "Target-URL" som shoppen poster til):

    Emner i administrationen versus data i payload

    I dropdown listen Event (handlinger) har du disse valgmuligheder, der afspejler følgende Payload:

    Ordre oprettet svarer til orders/created
    Ordre opdateret svarer til orders/updated
    Ordre faktureret svarer til orders/invoice
    Ordre sendt (status ændring) svarer til orders/fulfilled
    Ordre delvist sendt (status ændring) svarer til orders/partially-fulfilled
    Ordre annulleret (status ændring) svarer til orders/cancelled

     

    Efter oprettelse kan du aktivere og deaktivere dit webhook direkte fra oversigten:

     

    Historik

    Hvis du klikker på et navn i oversigten vises detaljerne for det pågældende webhook. Her vises f.eks. antal forsøg hvis levering af webhooket fejler –Se mere vedr. tidsintervaller her. Det er også her du har mulighed for at redigere dit webhook. Klik på "Historik" for at få vist aktivitesloggen for alle dine webhooks:

    I historikken har du mulighed for at filtrere og søge på events og svarkoder. Hvis levering er gennemført med status kode 200 (som beskrevet nærmere her) vil status for succesfuld levering være markeret i første kolonne. I dette eksempel kan vi se at status er markeret med en "404" fejl, hvilket i så fald bør undersøges nærmere. Klik på "Payload" for at få en forhåndsvisning af hvad dit webhook har i Payload:

    I dette eksempel har vi oprettet vores webhook med eventet "Ordre oprettet". I historikken kan vi se vores første kald indeholder følgende payload:

    Playload viser ordre nummeret på den ordre som har udløst vores webhook.

     

    Arbejde med webhooks

     

    Test af webhooks

    For at teste dit webhook bør du oprette en ordre og ændre status på denne, således at det event som du abonnerer på, bliver udløst. Du kan f.eks. køre din test fra en lokal server, eller benytte en service som Beeceptor mv. Hvis du benytter en lokal server, skal du være opmærksom på at denne skal gøres tilgængelig for kald udefra. Dette kan f.eks. gøres igennem services som Pagekite eller ngrok.

     

    Webhook endpoints

    For at en notifikation fra et webhook kan udløse en handling i din applikation, skal du opsætte et endpoint (destination) som dit webhook kan ramme. Dette endpoint skal være en HTTPS-adresse som kan håndtere notifikationer fra udløste events, som beskrevet i følgende afsnit.

     

    Modtagelse af webhooks

    Når du har konfigureret dit webhook, udløser Hostedshop en HTTP POST request til URI'en specificeret i feltet address på den pågældende webhook, hver gang handlingen som angivet i topic sker i shoppen.

     

    Reaktion på et webhook

    For at give til kende, at du har modtaget data fra et webhook, skal din applikation svare med et 200 OK status response. Et hvert response uden for 200 området, vil indikere at din applikation ikke har modtaget data. Bemærk: Webhooks har timeout på 5 sekunder. Ved levering af webhook følger vores system ikke redirects.

     

    Når levering fejler

    Når levering af et webhook fejler, forsøges levering gentaget efter 5 minutter. Følgende tabel angiver intervaller for leveringsforsøg:

    #fejl gentagelses forsinkelse total forsinkelse
    1 5 min 5 min
    2 10 min 15 min
    3 15 min 30 min
    4 30 min 1 time
    5 1 time 2 timer
    6 1 time 3 timer
    7 1 time 4 timer
    8 1 time 5 timer
    9 1 time 6 timer
    10 2 timer 8 timer
    11 2 timer 10 timer
    12 2 timer 12 timer
    13 3 timer 15 timer
    14 3 timer 18 timer
    15 4 timer 22 timer
    16 4 timer 26 timer
    17 4 timer 30 timer
    18 6 timer 36 timer
    19 12 timer 48 timer

    Når levering af et webhook er fejlet 20 gange over en 48-timers periode, foretages ingen yderligere forsøg.

     

    Verificering af webhooks

    For at højne sikkerheden i din applikation anbefales det at du verificerer, at det kald du får ind, også kommer fra den pågældende webshop. Notifikationer fra webhooks sendt fra shoppen er digitalt signeret med en secret key (Token), som kan tilgås ved at klikke på "Token":

    Signeringsnøglen er unik for shopløsningen som handlingen udløses fra og er den samme for alle webhooks der måtte være konfigureret på shoppen:

    For at verificere at et request kommer fra Hostedshop, skal du beregne den BASE64-indkodede HMAC-streng i det request payload du modtager, og sammenligne denne med værdien i X-Hmac-Sha256 headeren.

      Følgende eksempel benytter PHP til at verificere et webhook request

    
        declare(strict_types = 1);
    
        \define('MY_SECRET_KEY', 'my-secret-key');
    
        function verifyWebhook($payload, $hmacHeader) : bool
        {
            $calculatedHMAC = \base64_encode(
            \hash_hmac('sha256', $payload, \MY_SECRET_KEY, true)
            );
    
            return \hash_equals($hmacHeader, $calculatedHMAC);
        }
    
        $providedHMAC = $_SERVER['HTTP_X_HMAC_SHA256'];
        $data = \file_get_contents('php://input');
        
        $verified = verifyWebhook($data, $providedHMAC);
        \printf('Webhook verified: %s', \var_export($verified, true));
    
    

      Følgende eksempel benytter Go til at verificere et webhook request

    
        import (
                "crypto/hmac"
                "crypto/sha256"
                "encoding/base64"
                "net/http"
        )
    
        const hmacHeader = "X-Hmac-Sha256"
    
        func verifyWebhook(payload, secretKey []byte, request *http.Request) (bool, error) {
             received := request.Header.Get(hmacHeader)
             receivedHMAC := []byte(received)
    
             hash := hmac.New(sha256.New, secretKey)
             hash.Write(payload)
             sum := hash.Sum(nil)
    
             encoded := base64.StdEncoding.EncodeToString(sum)
             calculatedHMAC := []byte(encoded)
    
             return hmac.Equal(receivedHMAC, calculatedHMAC), nil
        }