Skip to content
Integration

Consuming Paddle Webhooks: A Practical Integration Guide

Receive and process Paddle webhooks reliably — Paddle-Signature (ts/h1) verification, fast acknowledgement, retries, dedupe on the event id, and a debugging checklist.

Published 6 min read
On this page

Paddle acts as merchant of record, which means it — not your application — owns the checkout, the tax, and the subscription state. Your system finds out what happened through webhooks: a transaction completed, a subscription was cancelled, a payment method updated. If those events do not land, your entitlements drift from what Paddle believes the customer has paid for, and the gap surfaces as a support ticket. This guide covers receiving Paddle events reliably — verifying them, acknowledging fast, and recovering the ones that fail.

What Paddle webhooks are

A Paddle webhook (Paddle calls the destination a notification destination) is an HTTP POST carrying an event about a billing entity. Each event has a type such as transaction.completed or subscription.canceled, a unique event id, an occurred_at timestamp, and a data object holding the entity — a transaction, a subscription, a customer. Because Paddle is authoritative for billing state and your app is downstream, these events are how your app learns the truth about what a customer is owed.

Common use cases

  • Provisioning and entitlements — grant or extend access on transaction.completed and subscription activation events.
  • Cancellation and downgrades — revoke access or schedule it on subscription.canceled and subscription.updated.
  • Dunning — react to failed-payment and past-due events to prompt the customer.
  • Reconciliation — record transactions and adjustments against your own ledger for finance.

Configuring the webhook in Paddle

You configure a notification destination in the Paddle dashboard: a URL, the set of event types it should receive, and — on creation — a secret key Paddle uses to sign deliveries to that destination. Paddle has separate sandbox and production environments with separate destinations and secrets, so a sandbox secret will not verify a production event. Subscribe each destination only to the events it needs.

Exact dashboard labels and the available event types change, so confirm current specifics against Paddle’s webhook documentation rather than memorising a layout. Note that Paddle Billing and the older Paddle Classic differ in their signing schemes; the scheme below is Paddle Billing’s.

Paddle expects a prompt 2xx and retries otherwise, so acknowledge first and process later:

  1. Capture the raw request body for signature verification before parsing.
  2. Verify the Paddle-Signature header.
  3. Persist or enqueue the raw event, keyed by its event id.
  4. Return 2xx immediately.
  5. Apply entitlements, dunning, or ledger writes asynchronously.

Filtering by event type at the edge keeps unrelated events out of your handler. A HookWatch endpoint’s event-type allowlist can drop types a destination does not act on before they reach your service.

Verifying authenticity

Paddle Billing signs each delivery with the Paddle-Signature header, which carries a timestamp and a hash under a ts/h1 scheme:

Paddle-Signature: ts=1753228800;h1=eec5c3d1a0f8b6...c94

The h1 value is an HMAC-SHA256 computed with your destination’s secret key over a payload built from the ts value and the raw request body. To verify, rebuild that signed payload using the header’s ts and the raw body, recompute the HMAC with your secret, and compare in constant time against h1. Keep the detail modest here and follow Paddle’s docs for the exact payload construction and any recommended timestamp tolerance, since those specifics are where implementations drift.

As with every HMAC scheme, verify the raw bytes — a parsed-and-re-serialised body breaks the hash. The general mechanics are in how to verify webhook signatures. Note that Paddle’s ts/h1 scheme signs a timestamped payload, not the body alone — so verify it in your own handler per Paddle’s docs; a generic HMAC-over-body check (including HookWatch’s configurable inbound verification) does not reconstruct that signed payload for you.

Common failure scenarios

  • Signature failures from a parsed body — a JSON middleware ahead of the verifier changes the bytes; the h1 no longer matches.
  • Wrong-environment secret — verifying a production event with a sandbox secret, or vice versa, right after go-live.
  • Classic vs Billing mismatch — applying the older Paddle Classic verification to a Paddle Billing delivery (or the reverse) fails every time.
  • Delivered but not processed — Paddle records a 2xx, but a downstream enqueue silently dropped the event, so entitlements never update. This class of failure is invisible in Paddle’s dashboard; see webhook delivered but not processed.
  • Timeouts under load — synchronous provisioning pushes the response past Paddle’s window and the event is retried.

Testing workflow

Paddle provides ways to send a simulated or test event to a destination from the dashboard, and its sandbox environment lets you drive real flows without real money. Because the exact test tooling moves, check Paddle’s current docs for what is available to your account.

For local development, expose your handler with a tunnel and register a sandbox destination against it so real Paddle deliveries reach your machine over public HTTPS. See testing webhooks locally; hookwatch tunnel forwards captured deliveries to a local process so Paddle can reach your laptop through a HookWatch endpoint.

Retry behaviour

Paddle retries failed deliveries with backoff over a limited window rather than forever, and the exact schedule changes, so rely on the behaviour and confirm current numbers in the docs. For your handler:

  • A 2xx is the only success signal; a 5xx, a timeout, or a connection error is a failed attempt Paddle will retry.
  • After the window closes, an unrecovered event is gone unless you can re-request or reconcile it, so persistent failures need attention.
  • Retries mean the same event arrives more than once — design for at-least-once.

How this shapes your own handler is covered in webhook retry best practices.

Idempotency

Dedupe on the Paddle event id, which is stable across every retry of the same event. Record processed ids and make provisioning idempotent — extending one subscription twice, or granting access twice for one transaction.completed, is precisely what dedupe prevents. A duplicate you have already handled should still return 2xx so Paddle stops retrying. Full patterns are in webhook idempotency.

Debugging checklist

  1. Confirm the destination is active and subscribed to the event type in the right environment (sandbox vs production).
  2. Check the recorded response for the failed attempt — a status or a timeout.
  3. Confirm the handler reads the raw body before any parser runs.
  4. Verify the Paddle-Signature h1 recomputes with the correct destination secret.
  5. Confirm you are applying the Paddle Billing scheme, not Paddle Classic (or vice versa) to match the destination.
  6. Ensure the handler returns 2xx inside Paddle’s timeout, with work deferred.
  7. Match application logs to the delivery by event id.
  8. Confirm duplicate events are deduped and still answered 2xx.
  9. If a 2xx was returned but nothing happened, trace the asynchronous path — the event was delivered but not processed.

How HookWatch helps

Route Paddle through a HookWatch endpoint and every delivery is captured in full — the Paddle-Signature header, the body, your response, and each attempt — so a failed subscription.canceled still shows exactly what Paddle sent and what your handler returned when you investigate later. Once a fix is deployed, replay the exact captured event (individually or in bulk) without waiting for Paddle’s retry window, pause an endpoint during maintenance and resume it, and filter to the event types a destination actually acts on. Repeated failures group into an incident, so a broken billing hook pages you once with the payload attached rather than leaving entitlements quietly out of sync.

Get started

See what happened to every webhook.

HookWatch keeps the request, the response, and every attempt for each delivery — so the debugging, retry, and replay steps in this article are a matter of reading, not reconstructing.