> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Subscription Webhooks

> The payload sent to your webhook endpoint when a subscription is created, updated, or changes state. Handle each event to keep your records in sync.

## Subscription Webhook Events

A subscription emits an event at each stage of its lifecycle:

| Event | Fires when |
| - | - |
| `subscription.active` | A subscription is successfully activated and recurring charges are scheduled. |
| `subscription.updated` | Any subscription field changes (real-time sync without polling). |
| `subscription.past_due` | A renewal fails and the grace period opens; the customer keeps access until the deadline. The payload includes `past_due_ends_at`. |
| `subscription.on_hold` | A subscription is put on hold due to failed renewal. |
| `subscription.paused` | A subscription is paused. |
| `subscription.unpaused` | A paused subscription is resumed. |
| `subscription.renewed` | A subscription is renewed for the next billing period. |
| `subscription.plan_changed` | A subscription is upgraded, downgraded, or modified with different add-ons. |
| `subscription.update_payment_method` | A subscription's payment method is updated. |
| `subscription.cancelled` | A subscription is cancelled by the merchant or customer. |
| `subscription.failed` | Subscription creation fails during mandate creation. |
| `subscription.expired` | A subscription reaches the end of its term and expires. |

### Using `subscription.updated` for Real-Time Sync

The `subscription.updated` webhook fires whenever any subscription field changes, allowing you to keep your application state in sync without polling:

```javascript theme={null}
app.post('/webhooks/dodo', async (req, res) => {
  // Verify the signature first. See /developer-resources/webhooks#verifying-signatures.
  // With express.raw(), req.body is a Buffer, so parse it after verification.
  const event = JSON.parse(req.body);
  
  if (event.type === 'subscription.updated') {
    const subscription = event.data;
    
    // Sync subscription changes to your database
    await syncSubscription(subscription.subscription_id, {
      status: subscription.status,
      next_billing_date: subscription.next_billing_date,
      metadata: subscription.metadata,
      // ... other fields you want to track
    });
    
    console.log(`Subscription ${subscription.subscription_id} updated`);
  }
  
  res.json({ received: true });
});
```

<Tip>
  Subscribe to `subscription.updated` to get real-time notifications about any subscription changes, eliminating the need to poll the API for updates.
</Tip>

## Webhook Payload Schema


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.