Paddle uses webhooks to push real-time notifications to your server when things happen in your account. Rather than polling the API for changes, your server receives an HTTP POST request the moment an event occurs.
Use webhooks to:
- Manage access to features in your app depending on a customer's subscription status.
- Sync information with other systems that your business uses, like a CRM or ERP solution.
- Set up notifications or automations.
The event model
When something notable happens in Paddle, it creates an event entity. An event records:
- What happened (
event_type) - When it happened (
occurred_at) - A snapshot of the entity at that moment (
data)
You can poll the /events endpoint in the Paddle API to get a list of events. However, subscribing to events via webhooks is recommended. Paddle pushes events to you as they happen, rather than you having to pull them.
When you create a notification destination, you tell Paddle which events you want to receive and where to send them. From that point on, every time a matching event occurs, Paddle sends a notification to your endpoint with the event payload as JSON.
sequenceDiagram
participant Paddle
participant YourServer as Your server
Paddle->>Paddle: Something happens (e.g. subscription created)
Paddle->>Paddle: Creates an event entity
Paddle->>YourServer: POST /your-webhook-endpoint
note over YourServer: Receives JSON payload
YourServer-->>Paddle: HTTP 200 OK
note over Paddle: Marks notification as delivered
Webhook payloads
Every webhook Paddle sends has the same top-level structure, regardless of the event type:
| Field | Description |
|---|---|
event_id | Unique ID for this event, prefixed with evt_. Use this to deduplicate events you may receive more than once. |
event_type | The type of event, in the format entity.action (e.g. customer.created). Use this to route events in your handler. |
occurred_at | RFC 3339 timestamp of when the event occurred. Use this to handle events that arrive out of order. |
notification_id | Unique ID for this delivery attempt, prefixed with ntf_. Different from event_id because a single event can produce multiple notifications. |
data | The new or changed entity at the time of the event. This is a snapshot that reflects the entity's state when the event occurred. |
Events vs. notifications
An event is a record of something that happened. A notification is a delivery attempt for that event to a specific destination. Notifications can be delivered via webhook or email.
The distinction matters when you have multiple notification destinations. If you have two webhook endpoints both subscribed to subscription.created, Paddle creates one event but two notifications — one for each destination. Each notification has its own notification_id but they share the same event_id.
Delivery guarantees
Paddle guarantees at-least-once delivery. If your server doesn't respond with 200 within five seconds, Paddle retries the notification automatically. This means your handler may occasionally receive the same event more than once.
To handle this safely, make your webhook processing idempotent. This means processing the same event twice should produce the same result as processing it once. Using event_id as a deduplication key is the simplest approach: store it when you first process an event, and skip any event with an ID you've already seen.
Because events can arrive out of order, use occurred_at rather than arrival time when you need to reason about the sequence of events. For example, if you receive both subscription.updated and subscription.canceled for the same subscription, compare their occurred_at values to determine which represents the latest state.
Notification status
Each notification moves through a lifecycle as Paddle attempts to deliver it:
flowchart LR
A["not_attempted"] --> B["needs_retry"]
A --> C["delivered"]
B --> C
B --> D["failed"]
| Status | Description |
|---|---|
not_attempted | Paddle hasn't yet tried to deliver this notification. |
needs_retry | Delivery failed. The notification is scheduled for another attempt using an exponential backoff schedule. |
delivered | Your server responded with 200. Paddle considers this notification successfully delivered. |
failed | All delivery attempts were exhausted. The notification won't be retried automatically, but you can replay it using the API. |
You can inspect notification status and delivery logs in the Paddle dashboard under Developer Tools > Notifications, or by using the list notification logs operation.
What happens at checkout
When a customer completes Paddle Checkout, a sequence of events fires automatically as Paddle creates and updates entities in your account. Understanding this sequence helps you know which events to handle for provisioning.
Paddle Checkout supports prefilling data and a variety of configuration options, and customer journeys can vary, but a typical sequence of events might look like this:
sequenceDiagram
participant Customer
participant Paddle
participant YourServer as Your server
Customer->>Paddle: Opens checkout
Paddle->>YourServer: transaction.created
Customer->>Paddle: Enters email
Paddle->>YourServer: customer.created
Customer->>Paddle: Enters country / ZIP
Paddle->>YourServer: address.created
Customer->>Paddle: Enters tax/VAT number (optional)
Paddle->>YourServer: business.created
Customer->>Paddle: Completes payment
Paddle->>YourServer: transaction.paid
Paddle->>YourServer: subscription.created (if recurring)
Paddle->>YourServer: transaction.completed
For a subscription, transaction.paid is the earliest point at which you can be sure payment has been captured. Use subscription.created to record the subscription in your system, and transaction.completed to confirm that Paddle has finished all internal processing.
You can use the subscription created scenario in the webhook simulator to test your checkout integration end-to-end. You can inspect each event in order, replay individual notifications, and validate your handler logic without making a real purchase.
Next steps
Create a notification destination
Tell Paddle where to send webhooks and which events you want to receive. Go to Developer Tools > Notifications in your Paddle dashboard, or use the create notification destination operation.
Handle webhook delivery
Configure your server to accept POST requests over HTTPS, respond with 200 within five seconds, and handle retries. Learn about IP allowlisting and processing recommendations.
Verify webhook signatures
Every Paddle webhook includes a Paddle-Signature header. Verify it to confirm that the request genuinely came from Paddle and hasn't been tampered with.
Test your integration
Use the webhook simulator to send test events to your endpoint without triggering real transactions.