facebook pixel

Using Webhooks


In this guide

1. Goals of this guide

This guide will walk you through the process of setting up webhooks in your Pylon API settings.

This guide is intended for a technical audience—in particular, you should be comfortable with how HTTP requests and webhooks work. If that isn't you, you may want to send this guide to your IT team or website contractor.

2. Configuring webhook destinations

To start receiving webhooks, you must create a Webhook destination in your account's API settings. Provide the URL which events should be delivered to, and select one or more event types from the list. Only events of the selected types will be delivered to this specific destination.

When you create the destination, you will see its secret on your screen. Be sure to save this secret somewhere so you can verify incoming requests.

You may register more than one destination if, for example, you have different services which are interested in different changes. If you don't have a server ready to receive webhook requests, you can create a temporary URL using a service like Hookbin.

3. Event delivery

Once a webhook destination is configured and is in the active state, it will start receiving events that are created in your account. Every event is dispatched to each webhook destination that is configured to listen for it.

When this happens, an attempt is created to deliver an event to a destination. Each attempt will cause an HTTP POST request to the destination's URL, containing one of the event paylods documented here.

A failed attempt is any attempt to which the destination server responds with a non-2XX HTTP status code. Our webhook delivery will also time out after 10s, so if your server takes longer than that to respond the attempt will count as a failure.

Failing attempts will retry up to four more times, according to the following schedule:

Attempt numberIncremental delayCumulative delay
100
2100s1m40s
31,000s18m20s
410,000s3h5m
5100,000s30h51m40s

Note that the final attempt will occur about 31 hours after the event was initially created.

4. Inactive webhook destinations

If there are no successful attempt deliveries to a webhook destination for 7 days, the destination will change to the inactive state.

When an endpoint is in the inactive state, no attempts will be made to deliver any events to this endpoint. Any events which are already in a delivery sequence will continue to be retried. For example, an event which has been attempted twice, both times failing, will proceed to attempt the remaining 3 times even if the destination is inactive.

The only way to resume delivering new events to this destination is to manually reactivate it in the API settings interface.

5. Securing your destination endpoints

Every delivery attempt made to your destination URL contains a cryptographic signature. The signature is sent to your server as an HTTP header. Here's an example of an HTTP request sent to your server:

POST /pylon-webhook-destination HTTP/1.1
Host: your-application.com
User-Agent: Pylon Webhooks
Pylon-Webhook-Signature: hs256=fc9fa8630026dc66e20d370af4a661b63ad19c5845e916b013fcb69e4c8a5a62
Pylon-Webhook-Timestamp: 1624235417
Pylon-Webhook-Version: 2021-07
Content-Length: 207
Content-Type: application/json

{"data": {...}}

You can check the content of the Pylon-Webhook-Signature header to verify that the request was made by Pylon, and not forged by some third-party. To verify the signature, perform the following steps:

  1. Retrieve the timestamp from the Pylon-Webhook-Timestamp header (in the example above, this would be 1624235417)
  2. Retrieve the request's body content verbatim (in the example above, this would be {"data": {...}})
  3. Calculate the HMAC of concat(timestamp, '.', payload) using the SHA256 algorithm and the secret of your webhook destination. See below for examples in different languages.
  4. Compare the result to the contents of the Pylon-Webhook-Signature header. Note that the header is prefixed with hs256= which you should ignore in your comparison.

All examples below assume that your webhooks's secret is stored in the PYLON_WEBHOOK_SECRET environment variable.

PHP verification example

$secret = getenv('PYLON_WEBHOOK_SECRET');
$signature = $_SERVER['HTTP_PYLON_WEBHOOK_SIGNATURE'];
$timestamp = $_SERVER['HTTP_PYLON_WEBHOOK_TIMESTAMP'];
$content = file_get_contents('php://input');

$verifySignature = 'hs256=' . hash_hmac('sha256', "$timestamp.$content", $secret);
if ($verifySignature !== $signature) {
    throw new RuntimeException("signature does not match!");
}

Python3 verification example

import hmac
import hashlib
import os

secret = os.getenv('PYLON_WEBHOOK_SECRET')
timestamp = b'TIMESTAMP_FROM_HEADER'
content = b'REQUEST_BODY'
signature = 'SIGNATURE_FROM_HEADER'

verifySignature = 'hs256=' + hmac.new(secret, '{}.{}'.format(timestamp, content), hashlib.sha256).hexdigest()
if signature != verifySignature:
    raise ValueError("signature does not match!")