> ## 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.

# Recovery

> The payloads sent to your webhook endpoint when abandoned cart recovery or subscription dunning events occur.

## Abandoned Cart Recovery Events

The following webhook events track the abandoned cart recovery lifecycle:

| Event                          | Description                                                                                                                                      |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `abandoned_checkout.detected`  | An abandoned checkout has been detected. Sent when a payment is identified as abandoned (failed or incomplete) and the recovery workflow begins. |
| `abandoned_checkout.recovered` | The customer completed payment through the recovery link. The `recovered_payment_id` field contains the successful payment ID.                   |

### Abandoned Checkout Payload Fields

<ParamField body="payment_id" type="string" required>
  The original payment that was abandoned. Use this to look up product, amount, and currency details.
</ParamField>

<ParamField body="customer_id" type="string" required>
  The customer who abandoned the checkout.
</ParamField>

<ParamField body="abandonment_reason" type="string" required>
  Why the checkout was abandoned. One of:

  * `payment_failed` — Customer attempted payment but it failed
  * `checkout_incomplete` — Customer visited checkout but never attempted payment
</ParamField>

<ParamField body="status" type="string" required>
  Current lifecycle state of this recovery attempt. One of:

  * `abandoned` — Detected, no emails sent yet
  * `recovering` — At least one recovery email sent
  * `recovered` — Customer completed payment
  * `exhausted` — All emails sent or newer checkout found
  * `opted_out` — Customer unsubscribed
</ParamField>

<ParamField body="abandoned_at" type="string" required>
  ISO 8601 timestamp of when the checkout was detected as abandoned.
</ParamField>

<ParamField body="recovered_payment_id" type="string | null">
  The payment ID of the successful recovery payment. `null` until the checkout is recovered.
</ParamField>

### Example: Handling ACR Webhooks

```javascript theme={null}
app.post('/webhooks/dodo', async (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'abandoned_checkout.detected':
      console.log(`Checkout abandoned: ${event.data.payment_id}`);
      console.log(`Reason: ${event.data.abandonment_reason}`);
      // Track abandonment in your analytics
      await trackAbandonment(event.data);
      break;

    case 'abandoned_checkout.recovered':
      console.log(`Checkout recovered: ${event.data.payment_id}`);
      console.log(`Recovery payment: ${event.data.recovered_payment_id}`);
      // Grant access, update records
      await handleRecovery(event.data);
      break;
  }

  res.json({ received: true });
});
```

***

## Dunning Events

The following webhook events track the subscription dunning lifecycle:

| Event               | Description                                                                                                                               |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `dunning.started`   | A dunning attempt has been created for a subscription that entered `on_hold` or was cancelled by the customer.                            |
| `dunning.recovered` | The customer updated their payment method and the resulting payment succeeded. The `payment_id` field contains the successful payment ID. |

### Dunning Attempt Payload Fields

<ParamField body="subscription_id" type="string" required>
  The subscription that triggered the dunning attempt.
</ParamField>

<ParamField body="customer_id" type="string" required>
  The customer who owns the subscription.
</ParamField>

<ParamField body="trigger_state" type="string" required>
  The subscription state that triggered dunning. One of:

  * `on_hold` — Subscription paused due to payment failure
  * `cancelled` — Customer cancelled from the customer portal
</ParamField>

<ParamField body="status" type="string" required>
  Current lifecycle state of this dunning attempt. One of:

  * `recovering` — Dunning emails are being sent
  * `recovered` — Customer updated payment method and payment succeeded
  * `exhausted` — All emails sent or subscription state changed
</ParamField>

<ParamField body="created_at" type="string" required>
  ISO 8601 timestamp of when the dunning attempt was created.
</ParamField>

<ParamField body="payment_id" type="string | null">
  The payment ID of the successful recovery payment. `null` while recovering.
</ParamField>

### Example: Handling Dunning Webhooks

```javascript theme={null}
app.post('/webhooks/dodo', async (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'dunning.started':
      console.log(`Dunning started for subscription: ${event.data.subscription_id}`);
      console.log(`Trigger: ${event.data.trigger_state}`);
      // Track dunning in your system
      await trackDunning(event.data);
      break;

    case 'dunning.recovered':
      console.log(`Subscription recovered: ${event.data.subscription_id}`);
      console.log(`Recovery payment: ${event.data.payment_id}`);
      // Reactivate access, update records
      await handleDunningRecovery(event.data);
      break;
  }

  res.json({ received: true });
});
```

<Tip>
  Subscribe to both `dunning.started` and `dunning.recovered` to track the full dunning lifecycle. Use `dunning.started` to pause grace periods or flag at-risk subscriptions in your system.
</Tip>

<CardGroup cols={2}>
  <Card title="Abandoned Cart Recovery" icon="cart-shopping" href="/features/recovery/abandoned-cart-recovery">
    Configure ACR email sequences and discount incentives.
  </Card>

  <Card title="Subscription Dunning" icon="rotate" href="/features/recovery/subscription-dunning">
    Configure dunning email sequences for lapsed subscriptions.
  </Card>

  <Card title="Subscription Webhooks" icon="repeat" href="/developer-resources/webhooks/intents/subscription">
    Related subscription lifecycle events like `subscription.on_hold` and `subscription.cancelled`.
  </Card>
</CardGroup>

## Webhook Payload Schema
