Field notes
How Paddle behaves, and where it bites
A timestamped signature, a five minute tolerance, and two generations of the product that do not share a scheme.
How Paddle sends
Paddle Billing POSTs JSON with the event in event_type (subscription.updated, transaction.completed) and signs it with Paddle-Signature, a semicolon-separated ts=…;h1=… pair.
Where it bites
- Classic and Billing are different products. They sign differently and name events differently. A guide, or a preset, for one is wrong for the other.
- The signature is timestamped. There is a tolerance, so a badly skewed clock on either end turns valid deliveries into failures.
- Billing state is a sequence, not a snapshot. Reconstructing why a subscription is in its current state needs the events in order, which means having kept them.
The vault under it
Point a WebhookVault endpoint at Paddle and every delivery is stored in full: headers verbatim, bodies byte-for-byte, labelled with its event type and searchable. Forward it onward to your own handler if you want the relay pattern, replay any delivery once the bug is fixed, and let a Watchdog notice the day it stops arriving.
Create an endpoint
Name it paddle-billing. Turn on forwarding to your own handler if you want the vault in front of it rather than beside it.
Register the capture URL
Paddle → Developer tools → Notifications → New destination. Paste the capture URL and pick the events you want.
Keep everything
Every delivery from here on is on the shelf: searchable, replayable, and watched for the day it goes quiet.
Verify from the record, not just at the door
Paddle Billing signs ts:body with your notification secret and sends both halves in one header. The vault parses the pair, enforces the tolerance, and rules on every capture.
The vault stores the signature headers verbatim with every request, so a delivery from last month can still be checked today. Verdicts are part of Solo and up. How verification works →
# headers, stored verbatim "Paddle-Signature": "ts=1757030400;h1=8f3a2c41…" { "event_id": "evt_01j9x2m4k…", "event_type": "transaction.completed", "occurred_at": "2026-09-11T06:14:22.19Z", "data": { "id": "txn_01j9x2m4k…", "status": "completed", "currency_code": "USD" } }
Event catalogue
Paddle webhook events you'll see
A few of the events Paddle sends, not the full list: Paddle's own documentation has every one. Each arrives in the vault labelled with its event type.
| Event | What it tells you |
|---|---|
| transaction.completed | A transaction was paid and fully processed. |
| transaction.payment_failed | A payment attempt on a transaction failed. |
| subscription.created | A new subscription started. |
| subscription.updated | A subscription changed: items, billing date, status or a scheduled change. |
| subscription.past_due | A renewal payment failed and the subscription is past due. |
| subscription.canceled | A subscription was cancelled. The event name uses the American spelling. |
Questions
Paddle webhook questions, answered
The three that come up most when Paddle is wired to a new endpoint.
Does Paddle retry failed webhooks?
Yes. Paddle Billing retries a delivery that does not get a 2xx, with growing gaps, over a period of days in live and far more briefly in sandbox, and a notification can be replayed afterwards. Every retry carries the same event_id, so deduplicate on it. A WebhookVault capture URL stores the delivery the first time it arrives.
How do I verify Paddle-Signature?
Split the header into ts and h1. Compute HMAC-SHA256 over ts, a colon and the raw body, keyed with the notification destination's secret key, hex-encode it and compare it with h1 in constant time; refuse a ts that is too old. On Solo and up the vault does this at capture, with a five minute tolerance, and puts the verdict on every row.
Does this guide cover Paddle Classic?
No. Paddle Classic sends form-encoded alerts signed with a public key in p_signature, a different scheme from Billing's Paddle-Signature. This guide and the vault's Paddle preset are for Paddle Billing. Classic alerts are still captured and stored in full, but the Paddle preset cannot verify their signature.
Keep the events your revenue depends on.
Free tier keeps 3 days while you evaluate; Solo keeps a month from $5.
Sign up with GitHub, Google or email. Two-factor authentication is required on every account, Free included, for account security.