Webhooks

In this guide, we will look at how to register and consume webhooks to integrate your app with Punt Uit. With webhooks, your app can know when something happens in Punt Uit, such as shipping or receiving products or tracking the status of an outbound.

Registering webhooks

To subscribe to a webhook, you need to have a URL in your app that Punt Uit can call. You can use the Punt Uit API to create a new subscription.

Registering a new webhook

curl
--location
--request POST 'https://partner.punt-uit.nl/api/fulfilment/v3/subscriptions'
  --header 'Authorization: Bearer ey...'
  --header 'Content-Type: application/json'
  --data-raw {
    "notificationUrl": https://<yourdomain>.com/logger,
    "event": "shipment-shipped"
  }

Now, whenever something of interest happens in your app, a webhook is fired off by Punt Uit. In the next section, we'll look at how to consume webhooks.

Consuming webhooks

When your app receives a webhook request from Punt Uit, check the type attribute to see what event caused it. The first part of the event type will tell you the payload type, e.g., a order, shipment, etc.

Example webhook payload

{
  "type": "shipped",
  "resource": "shipment",
  "identifier": "1a2d1c669b0811ed840606955cf36fa4"
}

In the example above, a shipment was sent, the payload type is a sent and the resource is a shipment.


Event types

  • Name
    outbound-status
    Type
    Description

    The status of an outbound has changed.

  • Name
    shipment-shipped
    Type
    Description

    We shipped items for an outbound.

  • Name
    receipt-received
    Type
    Description

    Products received for an inbound.

  • Name
    inbound-status
    Type
    Description

    The status of an inbound has changed.

  • Name
    label-status
    Type
    Description

    The status of a shipment for a label has changed.


Retries

When handling the webhook please accept the message and return 200 as quick as possible. Not after processing. When we do not get a 200 return in <timeout> the message will be retried in the following way: By default, we will retry sending the event for 24 hours and up to 185 times with an exponential back off and jitter , or randomized delay. If an event isn't delivered after all retry attempts are exhausted, the event is dropped.


Idempotency

We strongly advice using idempotency in your code. Using idempotency in API webhooks can bring several benefits, such as:

  • It allows for retries: If a webhook fails, the system can retry it later without any negative consequences, as the same request will produce the same outcome.
  • It increases robustness: Because the same request can be safely retried, the system is less likely to get into an inconsistent state if a webhook fails.
  • It allows for deduplication: If a webhook is triggered multiple times due to a bug or network error, the duplicated requests can be safely ignored, as they will have the same effect as a single request.
  • It eliminates the need to check if the same request had already been processed.

In summary, using idempotency in API webhooks improves reliability by allowing for retries and deduplication, and reduces complexity by eliminating the need to check for duplicates.


Security

To know for sure that a webhook was, in fact, sent by Punt Uit instead of a malicious actor, you can verify the request signature. Each webhook request contains a header named x-hook-signature, and you can verify this signature by using your secret webhook key. The signature is an HMAC hash of the request payload hashed using your secret key. Here is an example of how to verify the signature in your app:

Verifying a request

const CryptoJS = require('crypto-js');

const generateHash = (payload, secret) => {
  const hash = CryptoJS.HmacSHA256(payload, secret);
  return CryptoJS.enc.Base64.stringify(hash);
}

...

const theirSignature = event.headers['x-hook-signature'];
const expectedSignature = generateHash(JSON.stringify(event.body), <yourwebhooksecret>);
if (theirSignature !== expectedSignature) {
  console.error('unauthorized api call. x-hook-signature does not match.');
}

If your generated signature matches the x-hook-signature header, you can be sure that the request was truly coming from Punt Uit. It's essential to keep your secret webhook key safe — otherwise, you can no longer be sure that a given webhook was sent by Punt Uit.