Webhooks


Webhooks allow you to subscribe to events that happen within the Stannp Direct Mail platform. We will send a HTTP POST request to the webhook's configured URL. Webhooks can be used to update any external software or notify you on key events such as the day a mailpiece is expected to be delivered.

Creating an Webhook


Webhooks can be created and managed on the webhooks page which can be found in your Stannp account settings.

On first creation of a webhook we will send a test request to the url you provide to look for a http 200 status. If this is not recieved your webhook will not be created.

Validation Request Body
{
    "webhook_id":0,
    "event":"test_url",
    "created":"0000-00-00 00:00:00",
    "retries":"0"
}

Webhook Payload


When a webhook is triggered we send a request to the specified URL. The request will include a payload in the following format.

The payload will always contain an array of objects that have been triggered, even if just one item. This is because a it's often that the events could be triggered simultaneously for many objects. The objects name will depend on the events subscribed eg mailpieces, campaigns or recipients.

You can see a list of object definitions in our object reference documentation page.

Standard Webhook Payload
{
    "webhook_id":1234,
    "event":"mailpiece_status",
    "created":"0000-00-00 00:00:00",
    "retries":"0",
    "mailpieces":[
        {
            ...[mailpiece object]... 
        }
    ]
}

Webhook Security


We offer the option for signed webhook events. To enable this is simple, you must set a secret when initially creating your webhook. We recommend using a random string with high entropy however this can be whatever you like.

When you have a secret token set the signature can be found in the X-Stannp-Sigature header. The hash for the signature is generated with a HMAC digest using sha256

Validating Payloads


To validate that the request has come from Stannp you will need to first recreate the hash by hashing the raw message body against your stored secret. This can then be compared against the hash sent with the request.

We strongly recommend using a proper hash comparator method, such as php's hash_equals() rather than a plain == operator.

Example request validation
define('STANNP_WEBHOOK_SECRET', 'my_shared_secret');

function verify_webhook($data, $hmac_header)
{
  $calculated_hmac = hash_hmac('sha256', $data, STANNP_WEBHOOK_SECRET);
  return hash_equals($hmac_header, $calculated_hmac);
}


$hmac_header = $_SERVER['HTTP_X_STANNP_SIGNATURE'];
$data = file_get_contents('php://input');
$verified = verify_webhook($data, $hmac_header);

if (!$verified) {
    // Payload cannot be verified, request should be rejected
}

#!/bin/bash

STANNP_WEBHOOK_SECRET="my_shared_secret"
WEBHOOK_URL="your_webhook_url" # Replace with your actual webhook URL

HMAC_HEADER="$(curl -s -D - $WEBHOOK_URL | grep -i '^X-STANNP-SIGNATURE: ' | tr -d '\r' | cut -d ' ' -f 2)"
DATA=$(curl -s $WEBHOOK_URL)

calculated_hmac=$(echo -n "$DATA" | openssl dgst -sha256 -hmac "$STANNP_WEBHOOK_SECRET" -binary | base64)

if [ "$HMAC_HEADER" == "$calculated_hmac" ]; then
  echo "Webhook verified successfully"
else
  echo "Webhook verification failed"
fi
import hashlib
import hmac
from flask import Flask, request

app = Flask(__name__)

STANNP_WEBHOOK_SECRET = 'my_shared_secret'

def verify_webhook(data, hmac_header):
    calculated_hmac = hmac.new(STANNP_WEBHOOK_SECRET.encode('utf-8'), data.encode('utf-8'), hashlib.sha256).hexdigest()
    return hmac.compare_digest(hmac_header, calculated_hmac)

@app.route('/webhook', methods=['POST'])
def webhook():
    hmac_header = request.headers.get('X-STANNP-SIGNATURE')
    data = request.get_data(as_text=True)
    
    verified = verify_webhook(data, hmac_header)

    if not verified:
        return "Webhook verification failed", 403

    # Process the webhook payload here

    return "Webhook verified successfully"

if __name__ == '__main__':
    app.run(port=5000)

using System;
using System.Collections.Specialized;
using System.Security.Cryptography;
using System.Text;
using System.Web;

class Program
{
    private const string STANNP_WEBHOOK_SECRET = "my_shared_secret";

    static void Main()
    {
        // Simulating the incoming HTTP request
        NameValueCollection headers = new NameValueCollection
        {
            { "HTTP_X_STANNP_SIGNATURE", "your_received_hmac_header" } // Replace with your actual received header
        };

        string data = "your_received_data"; // Replace with your actual received data

        bool verified = VerifyWebhook(data, headers["HTTP_X_STANNP_SIGNATURE"]);

        if (!verified)
        {
            // Payload cannot be verified, request should be rejected
            Console.WriteLine("Webhook verification failed");
        }
        else
        {
            // Payload is verified, process the webhook
            Console.WriteLine("Webhook verified successfully");
        }
    }

    static bool VerifyWebhook(string data, string hmacHeader)
    {
        byte[] secretBytes = Encoding.UTF8.GetBytes(STANNP_WEBHOOK_SECRET);
        byte[] dataBytes = Encoding.UTF8.GetBytes(data);

        using (HMACSHA256 hmac = new HMACSHA256(secretBytes))
        {
            byte[] calculatedHmacBytes = hmac.ComputeHash(dataBytes);
            string calculatedHmac = BitConverter.ToString(calculatedHmacBytes).Replace("-", "").ToLower();

            return hmacHeader.Equals(calculatedHmac, StringComparison.OrdinalIgnoreCase);
        }
    }
}

Triggerable Events


Events are when something happens within the Stannp platform. Common events include status changes to a campaign or individual mailpiece. When configuring your webhook you can choose which events to subscribe to. Then when that event happens, such as a campaign has been despatched the webhook will be triggered. Currently you can subscribe to the following events.

Campaign Status: This event triggers whenever the campaign status changes. Status codes include: producing, dispatched, cancelled.

Mailpiece Status: This event triggers whenever the mailpiece status changes. Status codes include: producing, dispatched, cancelled, local_delivery, delivered, returned.

Recipient Blacklisted: This event triggers whenever a recipient has been blacklisted.

Recipient Event: This event triggers whenever a new recipient event is recorded.