Docs

How webhooks work

Understand Paddle's event model, webhook payload structure, and delivery guarantees before you build your integration.

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:

FieldDescription
event_idUnique ID for this event, prefixed with evt_. Use this to deduplicate events you may receive more than once.
event_typeThe type of event, in the format entity.action (e.g. customer.created). Use this to route events in your handler.
occurred_atRFC 3339 timestamp of when the event occurred. Use this to handle events that arrive out of order.
notification_idUnique ID for this delivery attempt, prefixed with ntf_. Different from event_id because a single event can produce multiple notifications.
dataThe 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"]
StatusDescription
not_attemptedPaddle hasn't yet tried to deliver this notification.
needs_retryDelivery failed. The notification is scheduled for another attempt using an exponential backoff schedule.
deliveredYour server responded with 200. Paddle considers this notification successfully delivered.
failedAll 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.

Create a notification destination

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.

Handle webhook delivery

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.

Verify webhook signatures

Test your integration

Use the webhook simulator to send test events to your endpoint without triggering real transactions.

Simulate webhooks

Was this page helpful?