Skip to content

    Track events using webhooks

    This guide is for developers who want to subscribe to different events that affect a payment using webhooks.

    Complexity: Medium
    Coding: Yes (Backend)
    Platform:

    Before you start

    This guide assumes that you already have integrated Nets Easy checkout so that you can create payments using the test environment.

    Why use webhooks?

    Webhooks (or HTTP callbacks) allow you to subscribe to different events that affect a payment and to be notified directly when these events happen. When an event occurs in Easy, for example when a charge is made or a payment is refunded, this event can be sent along with the associated data.

    To keep your backend in sync with Nets Easy, we highly recommend that you use webhooks. The advantages are many:

    • Webhooks are robust against various runtime failures (network failures and other temporary processing failures). Nets Easy reposts the events until you acknowledge the webhook by returning a 200 HTTP status code.
    • Webhooks are efficient since they avoid polling Nets Easy for state changes.
    • Some payment methods (mobile wallets for example) don't guarantee that your customer will return to your checkout page after a completed payment. By using webhooks, you are able to track all payment events even though your customer has left your site.

    This guide shows you the steps you need to take in order to receive notifications from Nets Easy.

    Step 1: Receive a webhook

    To be able to receive a webhook, you first need to set up an HTTPS endpoint on your site. The endpoint should read and parse the JSON body of the request in order to get the data associated with the event that was triggered.

    The data associated with each event varies. However, all events share the same basic structure. Here is an example:

    Webhook payload example

    { 
       "id": "bcec42e7ba964e568b14691f259cfa3a",
       "merchantId":100017120,
       "timestamp": "2018-01-12T09:40:19.8919+00:00",
       "event": "payment.created",
       "data": { 
          ...
       }
    }

    The data object contains properties specific to each type of event. See the Webhooks API reference for more information about the various properties.

    It's time to implement the webhooks endpoint on your website. The following code shows how to read and parse the event payment.created:

    Process payment.created event

    webhooks-endpoint.php
    <?php
    
    $json = file_get_contents('php://input');
    $payload = json_decode($json, true);
    if (json_last_error() != JSON_ERROR_NONE) {
        echo (json_last_error_msg());
        var_dump($result);
        exit("Unable to parse json request body");
    }
    
    // Read properties common to all events
    $name = $payload['event'];
    $id = $payload['id'];
    $merchantNumber = $payload['merchantNumber'];
    if (empty($merchantNumber)) {
        // Some of the events use the key "merchantId"
        // for the merchant number.
        $merchantNumber = $payload['merchantId'];
    }
    $timestamp = $payload['timestamp'];
    $data = $payload['data'];
    $paymentId = $data['paymentId'];
    
    if ($name == "payment.created") {
      // Process payment.created event here
      // ...
    }

    To acknowledge the webhook sent from Easy, a 200 HTTP status code is required. Any other status code, even other 2XX codes, will be treated as a failed attempt.

    If the webhook was not successfully posted to your endpoint, Easy will continue to send the webhook with an increasing waiting time between each attempt. If your site still has not responded with 200 after this period, the webhook will not be attempted any more.

    Step 2: Test your webhook endpoint

    You can use any HTTP(S) client for testing and verifying that your webhook endpoint works as expected. However, two tools that are popular for sending JSON over HTTP(S) are Insomnia and Postman.

    In the following screen shot, Insomnia is used to test an endpoint receiving a webhook. You can see that the endpoint returns the response code 200 (OK).

    Insomnia screen shot

    Test your endpoint using the following payload from the create-payment event. Make sure that your endpoint returns the response code 200.

    Payload for the payment.created event

    {
        "id": "458a4e068f454f768a40b9e576914820",
        "merchantId": 100017120,
        "timestamp": "2021-05-04T22:08:16.6623+02:00",
        "event": "payment.created",
        "data": {
            "order": {
                "amount": {
                    "amount": 180000,
                    "currency": "SEK"
                },
                "reference": "42369",
                "orderItems": [
                    {
                        "grossTotalAmount": 180000,
                        "name": "A product",
                        "netTotalAmount": 180000,
                        "quantity": 2,
                        "reference": "43",
                        "taxRate": 0,
                        "taxAmount": 0,
                        "unit": "hours",
                        "unitPrice": 90000
                    }
                ]
            },
            "paymentId": "02a900006091a9a96937598058c4e474"
        }
    }

    You can find complete example request bodies in the API reference for Webhooks.

    Nets Easy requires a secure connection using HTTPS when sending webhook notifications to your endpoint.

    Make sure you can send and parse a sample webhook notification request over HTTPS before moving on to the next step.

    Step 3: Subscribe to events

    Once your HTTPS endpoint has been implemented and tested, you can now subscribe to various events using the Payment API.

    Webhooks are configured per payment and can be specified in the request body of the following methods:

    The methods accepts a notifications object that contains a list of webhooks.

    In the following example, you can see how to subscribe to the 'create.payment' event using the Create payment method:

    Subscribe to events

    {
       "order": {
          "items": [
             {
                "reference": "43",
                "name": "Hosted product",
                "quantity": 1,
                "unit": "hours",
                "unitPrice": 13300,
                "grossTotalAmount": 13300,
                "netTotalAmount": 13300
             }
          ],
          "amount": 13300,
          "currency": "SEK",
          "reference": "Hosted Demo Order"
       },
       "checkout": {
          "integrationType": "HostedPaymentPage",
          "returnUrl": "https://<YOUR_WEBSITE>/completed.html",
          "termsUrl": "https://<YOUR_WEBSITE>/terms.html"
       },
       "notifications": {
          "webhooks": [
             {
                "eventName": "payment.created",
                "url": "https://<YOUR_WEBSITE>/webhooks-endpoint.php",
                "authorization": "<AUTH_KEY>"
             },
             {
                "eventName": "payment.checkout.completed",
                "url": "https://<YOUR_WEBSITE>/webhooks-endpoint.php",
                "authorization": "<AUTH_KEY>"
             }
          ]
       }
    }

    Each webhook specifies an eventName and an url that should be invoked whenever the specied event is triggered in Nets Easy for the associated payment.

    The value specified in the authorization property will be set in the HTTP Authorization request header sent from Nets Easy. You can also define customer headers that will be added to the HTTP request for a specific webhook. Here is an example where two additional headers (HeaderX and HeaderY) will be added to the webhook notification request:

    Using customer headers

    {
       "order": {
         ...
       },
       "checkout": {
         ...
       },
       "notifications": {
          "webhooks": [
             {
                "eventName": "payment.created",
                "url": "https://<YOUR_WEBSITE>/webhooks-endpoint.php",
                "authorization": "<AUTH_KEY>",
                "headers": [
                   {
                      "HeaderX": "some_value"
                   },
                   {
                      "HeaderY": "some_value"
                   }
                ]
             }
          ]
       }
    }