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.
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.
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 number | Incremental delay | Cumulative delay |
---|---|---|
1 | 0 | 0 |
2 | 100s | 1m40s |
3 | 1,000s | 18m20s |
4 | 10,000s | 3h5m |
5 | 100,000s | 30h51m40s |
Note that the final attempt will occur about 31 hours after the event was initially created.
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.
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:
Pylon-Webhook-Timestamp
header (in the example above, this would be 1624235417
){"data": {...}}
)concat(timestamp, '.', payload)
using the SHA256 algorithm and the secret of your webhook destination. See below for examples in different languages.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.
$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!");
}
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!")