> For the complete documentation index, see [llms.txt](https://developers.doku.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.doku.com/accept-payments/doku-checkout/order-and-notification-handling/recover-abandoned-cart.md).

# Recover Abandoned Cart

Recover Abandoned Cart is a feature on the DOKU Checkout Page that lets customers reopen and complete an **expired** order without the merchant having to recreate it. When an order expires, DOKU can automatically send the customer an "Expired Order" email containing a link back to the original Checkout Page, where they can resume and finish the payment.

{% hint style="info" %}
**Availability:** 🇮🇩 Indonesian Business Account only.
{% endhint %}

***

### How It Works

1. A customer initiates checkout and the order is generated (`ORDER_GENERATED`).
2. The customer does not complete payment within the `payment_due_date`, so the order expires (`ORDER_EXPIRED`).
3. If **Recover Abandoned Cart** is active, DOKU sends the customer an **Expired Order** email containing a direct link back to the same Checkout Page.
4. The customer opens the link and resumes payment on the original order — no **new order/invoice is created.**
5. If the customer completes the payment within the recovery period you configured, the order is marked as recovered (`ORDER_RECOVERED`).

The customer can reopen the same expired order **up to 3 times** via the recovery email, within the recovery period you set (for example, 7 days after expiration).

***

### 1. Enable via DOKU Dashboard

The simplest way to turn on Recover Abandoned Cart is from the **DOKU Dashboard**, which sets the merchant-level default applied to all Checkout orders. (If you need to control this per order, or override the default for specific transactions, see [API Reference](https://claude.ai/chat/ae248e82-62ab-4c91-b595-874cd328f7df#2.-api-reference) below.)

**Step 1 — Enable the Expired Order email notification (prerequisite)**

The Expired Order email is the entry point for customers to return to their cart, so it must be turned on first.

1. Log in to your **DOKU Dashboard**
2. Go to **Settings > Checkout Page Notification** (Checkout Email Notifications)
3. Activate the **Expired Order** status notification

**Step 2 — Activate Recover Abandoned Cart**

1. Log in to your **DOKU Dashboard**
2. Go to **Settings > Checkout Appearance > Expired Settings**
3. Switch on **Activate Recover Abandoned Cart**
4. Set your preferred **recovery period** — the number of days after expiration during which the order can still be recovered (for example, 7 days)
5. Click **Save**

{% hint style="warning" %}
If the **Expired Order** email notification is not active, customers will have no way to reach the recovery link, even if **Recover Abandoned Cart** is switched on.
{% endhint %}

***

### 2. API Reference

In addition to the Dashboard toggle, Recover Abandoned Cart can be controlled **per transaction** via the `Initiate Order` request (`POST /checkout/v1/payment`). This lets you turn recovery on/off, or set a different recovery window, for specific orders instead of relying on the merchant-level Dashboard default.

{% hint style="warning" %}
**Channel restriction:** `order.recover_abandoned_cart` and `order.expired_recovered_cart` are only applicable for **Virtual Account (VA)**, **Convenience Store / Online-to-Offline (O2O)**, and **Credit Card** payment methods.
{% endhint %}

#### Request parameters

```json
{
  "order": {
    "amount": 80000,
    "invoice_number": "INV-{{$timestamp}}",
    "currency": "IDR",
    "recover_abandoned_cart": true,
    "expired_recovered_cart": 2,
    "line_items": [
      {
        "id": "001",
        "name": "Fresh flowers",
        "quantity": 1,
        "price": 40000,
        "sku": "FF01",
        "category": "gift-and-flowers"
      }
    ]
  },
  "payment": {
    "payment_due_date": 60
  }
}
```

| Body parameter                 | Type    | Mandatory                                   | Description                                                                                                                                                                               |
| ------------------------------ | ------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `order.recover_abandoned_cart` | boolean | Conditional — VA, O2O, and Credit Card only | If sent as `true`, the customer can recover this order after it expires, as long as `expired_recovered_cart` has not lapsed.                                                              |
| `order.expired_recovered_cart` | number  | Conditional — VA, O2O, and Credit Card only | The expiry window (in **minutes**) for the *recovered* order — i.e. how long the customer has to complete payment after clicking the recovery link. Max value: `44640` minutes (31 days). |

{% hint style="info" %}
&#x20;`expired_recovered_cart` is separate from `payment.payment_due_date`. `payment_due_date` controls how long the **original** order stays open before it expires; `expired_recovered_cart` controls how long the **recovered** order stays open after the customer reopens it.&#x20;
{% endhint %}

#### Response parameters

DOKU echoes both fields back in the `Initiate Order` response so you can confirm what was applied to the order:

```json
{
  "message": ["SUCCESS"],
  "response": {
    "order": {
      "amount": "80000",
      "invoice_number": "INV-1720752332",
      "currency": "IDR",
      "session_id": "5f6304ca900144c7a4fcf802ad6c0898",
      "recover_abandoned_cart": true,
      "expired_recovered_cart": 2,
      "line_items": [ ... ]
    },
    "payment": {
      "payment_due_date": 60,
      "token_id": "5f6304ca900144c7a4fcf802ad6c089820244512094533497",
      "url": "https://sandbox.doku.com/checkout-link-v2/5f6304ca900144c7a4fcf802ad6c089820244512094533497",
      "expired_date": "20240712104531"
    }
  }
}
```

| Body parameter                          | Type    | Mandatory   | Description          |
| --------------------------------------- | ------- | ----------- | -------------------- |
| `response.order.recover_abandoned_cart` | boolean | Conditional | Same as the request. |
| `response.order.expired_recovered_cart` | number  | Conditional | Same as the request. |

#### Dashboard vs API

This follows the same override pattern used elsewhere in Checkout Settings (e.g. `payment_method_types`, `payment_due_date`): the **Dashboard** setting defines the merchant-level default, while the **API request** parameters let you override that default on a **per-order basis.**

| Configuration source                                                         | Scope                  | Behavior                                                                                                                                      |
| ---------------------------------------------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Dashboard (**Settings > Checkout Appearance > Expired Settings**)            | Merchant-level default | Applies to all Checkout orders unless overridden by the API request. Recovery period is set in **days**.                                      |
| API request (`order.recover_abandoned_cart`, `order.expired_recovered_cart`) | Per-order              | Overrides the Dashboard default for that specific order. Recovery period is set in **minutes**, and only applies to VA, O2O, and Credit Card. |

{% hint style="info" %}
If you don't send `recover_abandoned_cart` in the request, the order falls back to whatever is configured in the Dashboard.
{% endhint %}

#### Order status: `ORDER_RECOVERED`

To let merchants track recovery programmatically, the **Check Status API** returns a new `order.status` value once a previously expired order is successfully recovered and paid.

| Value             | Description                                                                                        |
| ----------------- | -------------------------------------------------------------------------------------------------- |
| `ORDER_GENERATED` | Order has been created and is awaiting payment.                                                    |
| `ORDER_EXPIRED`   | Order was not paid within `payment_due_date` and has expired.                                      |
| `ORDER_RECOVERED` | An expired order was reopened by the customer via the recovery link and the payment was completed. |

**Sample Check Status API response**

```json
{
    "order": {
        "invoice_number": "INV-5489910000093492",
        "amount": 120000,
        "status": "ORDER_RECOVERED",
        "date": "2025-07-09T02:58:30Z"
    },
    "transaction": {
        "status": "SUCCESS",
        "date": "2025-07-09T03:14:02Z",
        "original_request_id": "3719"
    },
    "service": {
        "id": "VIRTUAL_ACCOUNT"
    },
    "acquirer": {
        "id": "BCA"
    },
    "channel": {
        "id": "VIRTUAL_ACCOUNT_BCA"
    }
}
```

| Body parameter | Type   | Mandatory | Description                                                            |
| -------------- | ------ | --------- | ---------------------------------------------------------------------- |
| `order.status` | string | optional  | Possible values: `ORDER_GENERATED`, `ORDER_EXPIRED`, `ORDER_RECOVERED` |

{% hint style="warning" %}
Use `order.status = ORDER_RECOVERED` to distinguish orders completed through the recovery flow from regular first-attempt payments in your reconciliation or analytics logic.&#x20;
{% endhint %}

#### Notification behavior

* The **Expired Order** notification (configured under **Settings > Checkout Page Notification**) is sent when an order transitions to `ORDER_EXPIRED`.
* No separate "recovered" webhook event is sent — once the customer completes payment through the recovery link, your **standard payment/paid notification callback** fires as usual, and the corresponding order will report `order.status: ORDER_RECOVERED` on subsequent `Check Status API` calls.

***

### Monitoring Recovered Orders

* **Dashboard:** Go to **Report > Checkout Orders**, open an order's **Details**, then check the **Transaction History** tab to see the full status trail — including expiry and recovery events.
* **API:** Call the **Check Status API** with the order's `invoice_number` and read `order.status`.

***

### Use Cases

* **Campaign / promo periods** — recover carts abandoned due to urgency-driven traffic spikes.
* **B2B transactions** — give business buyers more time to finalize payment without restarting the order.
* **Subscription renewals** — automatically follow up on incomplete renewal payments.

***

### Notes & Limitations

* Available for **Indonesian Business Accounts** only.
* Customers can reopen an expired order via the recovery email up to **3 times**.
* **Per-order** API control (`order.recover_abandoned_cart` / `order.expired_recovered_cart`)
* Only applies to **Virtual Account, Convenience Store/O2O, and Credit Card** payment methods. Other channels rely solely on the Dashboard-level default.
* Requires the **Expired Order** email notification to be active; without it, customers have no recovery entry point regardless of how the feature was enabled.
