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.
{ "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.
{ "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.
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.