Check that webhooks are genuinely sent by Paddle by verifying webhook signatures.
For security, we recommend that you verify webhook signatures to make sure that webhook events are genuinely sent by Paddle. This helps you to be sure that they haven't been tampered with in-transit.
Webhooks let you subscribe to events in Paddle. When a subscribed event occurs, Paddle sends a notification to a webhook endpoint that you specify.
All webhooks sent by Paddle include a signature that you can use to verify that they were genuinely sent by Paddle.
To verify, you can compare the signature included with each webhook with a signature that you generate. Both signatures are generated using a secret key that only you and Paddle know, so if they match it means you can be sure events came from Paddle.
Verify webhook signatures from Paddle in six steps:
Get the secret key for your notification destination using the API or Paddle web app.
Paddle-Signatureheader from an incoming webhook sent by Paddle.
Parse the header to extract its timestamp and signature values.
Concatenate the extracted timestamp with the raw body of the request to build a signed payload.
Hash the signed payload you built to generate a signature that you can use for comparison.
Paddle-Signatureheader to the signature you just computed.
First, get the secret key for your notification destination.
Paddle creates a secret key for each notification destination that you create. If you've created more than one notification destination, get keys for each notification destination that you'd like to verify signatures for.
Treat your endpoint secret key like a password. Keep it safe and never share it with apps or people you don't trust.
Go to Paddle > Developer Tools > Notifications.
Click the … next to a notification destination in the list, then choose Edit destination from the menu.
Copy secret key
Click the copy icon in the secret key field to copy it.
Next, get the
Paddle-Signature header from an incoming webhook sent by Paddle.
All webhook events sent by Paddle include a
Paddle-Signature header. For example:
Signatures include two parts, separated by a semicolon:
Timestamp as a Unix timestamp.
Webhook event signature. Signatures contain at least one
Now you have the
Paddle-Signature header, parse it to extract the timestamp (
ts) and signature values (
You can do this by splitting using a semicolon character (
;) to get elements, then splitting again using an equals sign character (
=) to get key-value pairs.
Paddle creates a signature by first concatenating the timestamp (
ts) with the body of the request, joined with a colon (
Build your own signed payload by concatenating:
- The extracted timestamp (
- A colon (
- The raw body of the request
Don't transform or process the raw body of the request, including adding whitespace or applying other formatting. This results in a different signed payload, meaning signatures won't match when you compare.
Next, hash your signed payload to generate a signature.
Paddle generates signatures using a keyed-hash message authentication code (HMAC) with SHA256 and a secret key.
Compute the HMAC of your signed payload using the SHA256 algorithm, using the secret key for this notification destination as the key.
This should give you the expected signature of the webhook event.
Finally, compare the
Paddle-Signature header to the signature you just computed.
If they don't match, you should reject the webhook event. Someone may be sending malicious requests to your webhook endpoint.