Gareth Wilson Gareth Wilson

Guide to Pylon Webhooks: Features and Best Practices

Published


Pylon webhooks notify your systems about B2B support activity: an issue is created or updated, an account changes. If you're building on Pylon, webhooks are how you react to support events without polling.

This guide covers how Pylon webhooks work, the events you'll handle, how to verify the Pylon-Webhook-Signature, the retry behavior, and the best practices for production.

What are Pylon webhooks?

Pylon webhooks are HTTP POSTs delivered to a webhook destination you configure, each signed with an HMAC-SHA256. The Pylon-Webhook-Signature header is hs256=<hex>, computed over timestamp.payload, with companion Pylon-Webhook-Timestamp and Pylon-Webhook-Version headers. The signing secret is shown only once when you create the destination.

Pylon webhook features

FeatureDetails
ConfigurationWebhook destinations (secret shown once at creation)
Signature headerPylon-Webhook-Signature, formatted hs256=<hex>
Signature schemeHMAC-SHA256 over {timestamp}.{payload}, keyed with the destination secret
Other headersPylon-Webhook-Timestamp (unix), Pylon-Webhook-Version
RetriesUp to 5 attempts with exponential backoff, final ~31h after the event
InactivationDestination flips to "inactive" after 7 days with no successful deliveries
SDKNone

Common events

Pylon events cover issues and accounts. The exact event-type token strings are gated behind Pylon's authenticated docs, so treat these as indicative and verify against a live Pylon account:

EventFires when
issue.createdAn issue is created
issue.updatedAn issue is updated

The precise format may be issue.created or issue_created (or trigger-based), so confirm the exact strings for your account before hardcoding them.

Setting up Pylon webhooks

Create a webhook destination in Pylon and copy the signing secret, it's shown only once. Store it securely for verification.

Securing Pylon webhooks

Each delivery carries a Pylon-Webhook-Signature header (hs256=<hex>) and a Pylon-Webhook-Timestamp. To verify, build {timestamp}.{payload} (the timestamp, a dot, then the raw body), compute an HMAC-SHA256 with the destination secret, hex-encode it, and compare against the hex after the hs256= prefix. Verify against the raw body, don't re-serialize.

const crypto = require("crypto");

const SECRET = process.env.PYLON_WEBHOOK_SECRET;

function verify(rawBody, timestamp, signatureHeader) {
  const message = `${timestamp}.${rawBody.toString()}`;
  const expected = "hs256=" +
    crypto.createHmac("sha256", SECRET).update(message).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const timestamp = req.headers["pylon-webhook-timestamp"];
  if (!verify(req.body, timestamp, req.headers["pylon-webhook-signature"])) {
    return res.sendStatus(401);
  }

  res.sendStatus(200); // acknowledge fast
  processQueue.add(JSON.parse(req.body)); // process asynchronously
});

The same check in Python:

import hashlib
import hmac
import os

SECRET = os.environ["PYLON_WEBHOOK_SECRET"].encode()


def verify(raw_body: bytes, timestamp: str, signature_header: str) -> bool:
    message = (timestamp + "." + raw_body.decode()).encode()
    expected = "hs256=" + hmac.new(SECRET, message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature_header or "")

The older X-Pylon-Signature scheme

An older Pylon support article documents a different header, X-Pylon-Signature (a hex HMAC-SHA256 of the raw body, with no timestamp). The Pylon-Webhook-Signature scheme above (from Pylon's developer guide) is the current one; if you encounter X-Pylon-Signature, it's the legacy variant.

Pylon webhook limitations and pain points

The signed message is timestamp.payload

The Problem: The HMAC is over {timestamp}.{payload}, not the body alone, and the header is hs256=-prefixed. Signing the body by itself, or dropping the prefix, fails.

Why It Happens: Pylon binds the timestamp into the signed message.

Workarounds:

  • Build timestamp + "." + body, HMAC-SHA256, hex, and compare against the hs256= value over the raw body.

How Hookdeck Can Help: Hookdeck verifies the Pylon-Webhook-Signature at the edge, so your app receives pre-verified events without reconstructing the signed message.

Two header schemes

The Problem: The current Pylon-Webhook-Signature and the legacy X-Pylon-Signature differ (the legacy one has no timestamp). Verifying with the wrong one fails.

Why It Happens: Pylon's documentation covers two generations.

Workarounds:

  • Use the Pylon-Webhook-Signature scheme (the one the developer guide and this source use).

How Hookdeck Can Help: Hookdeck verifies the current scheme at the edge, so your app isn't coupled to which header is present.

Secret shown once, and inactivation

The Problem: The signing secret appears only at creation, and the destination flips to "inactive" after 7 days with no successful deliveries. Lose the secret or let deliveries fail, and you're re-creating or reactivating.

Why It Happens: Pylon shows the secret once and prunes dead destinations.

Workarounds:

  • Capture the secret at creation, acknowledge fast so deliveries succeed, and monitor destination status.

How Hookdeck Can Help: Hookdeck always accepts deliveries and absorbs downstream failures, keeping the destination active while it retries to your service.

Unconfirmed event-type strings

The Problem: The exact event-type tokens are auth-gated, so a handler keyed to a guessed string may not match.

Why It Happens: Pylon's event catalog isn't publicly enumerable.

Workarounds:

  • Confirm the exact event strings against a live account and handle unknown ones defensively.

How Hookdeck Can Help: Hookdeck's filters route on the event fields you actually receive, so you can adapt without redeploying handlers.

Best practices

Verify hs256= over timestamp.body

Build {timestamp}.{body}, HMAC-SHA256 with the destination secret, hex, and compare against the hs256= value in constant time, over the raw body.

Store the secret and monitor status

Capture the once-shown secret, and watch for the 7-day inactivation.

Acknowledge fast, process asynchronously

Return 200 quickly and defer work to a queue. See why to process webhooks asynchronously.

Confirm event names and dedupe

Verify the exact event strings against a live account, and dedupe so retries don't double-process. See our guide to webhook idempotency.

Make Pylon webhooks production-ready

Hookdeck verifies Pylon-Webhook-Signature, deduplicates, and durably queues every support event

Conclusion

Pylon webhooks verify with a Pylon-Webhook-Signature (hs256=<hex>) HMAC over {timestamp}.{payload}, keyed with a once-shown destination secret, with an older X-Pylon-Signature legacy variant to be aware of. Verify against the raw body, store the secret, confirm the exact event strings, and acknowledge fast to avoid the 7-day inactivation.

Hookdeck verifies the signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified events.

Get started with Hookdeck for free and handle Pylon webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.