Paddle Billing
Search

Verify webhook signatures

Check that that received events are genuinely sent from Paddle by verifying webhook signatures.

For security, verify webhook signatures to make sure received webhooks are genuinely sent from Paddle. This helps you be sure they haven't been tampered with in-transit.

How it works

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 Paddle-Signature header. Paddle generates this header using a secret key that only you and Paddle know.

To verify, you can use the secret key to generate your own signature for each webhook. Since only you and Paddle know the secret key, if both signatures match then you can be sure that a received event came from Paddle.

Before you begin

Create a notification destination

Create a notification destination where the type is url (webhook), if you haven't already.

Get your secret key

To verify webhooks, you'll need to get the secret key for your notification destination.

Paddle generates 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.

Send a GET request to the /notification-settings/{notification_setting_id} endpoint.

Response

If successful, Paddle returns the notification destination settings, including the endpoint_secret_key. For example:

Get started

There are two ways that you can verify webhook signatures:

Verify using Paddle SDKs

Use our official SDKs to verify webhook signatures. You'll need to provide the event payload, Paddle-Signature header, and the endpoint secret key.

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.

Learn more about the Paddle PHP SDK on GitHub: @PaddleHQ/paddle-php-sdk.

Verify manually

Build your own logic to verify webhook signatures from Paddle in five steps:

  1. Get Paddle-Signature header

    Get the Paddle-Signature header from an incoming webhook sent by Paddle.

  2. Extract timestamp and signature from the header

    Parse the header to extract its timestamp and signature values.

  3. Build the signed payload

    Concatenate the extracted timestamp with the raw body of the request to build a signed payload.

  4. Hash the signed payload

    Hash the signed payload you built to generate a signature that you can use for comparison.

  5. Compare your signatures

    Compare the Paddle-Signature header to the signature you just computed.

1. Get Paddle-Signature header

First, 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:

tsstring

Timestamp as a Unix timestamp.

h1string

Webhook event signature. Signatures contain at least one h1. We may add support for secret rotation in the future. During secret rotation, more than one h1 is returned while secrets are rotated out.

2. Extract timestamp and signature from header

Now you have the Paddle-Signature header, parse it to extract the timestamp (ts) and signature values (h1).

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.

To prevent replay attacks, you may like to check the timestamp (ts) against the current time and reject events that are too old. Our SDKs have a default tolerance of five seconds between the timestamp and the current time.

3. Build signed payload

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 (ts) +
  • 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.

4. Hash signed payload

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.

5. Compare signatures

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.

Related pages