> For the complete documentation index, see [llms.txt](https://developers.bead.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.bead.xyz/reference-guide/payment-scenarios/expired-payment-handling.md).

# Expired Payment Handling

#### Purpose

This page explains what happens when a payment reaches the `expired` status, how to handle it in your integration, and what the customer experiences.

Use this page when a payment status check or webhook returns `expired` and you need to know what to do next.

> **Scope note:** the mechanism described below, a crypto quote window, governs crypto tenders. Klarna (and other non crypto hosted checkout tenders) expire differently. See "Expiry for Klarna and other non crypto tenders" near the end of this page.

#### What causes an expired payment?

Each Bead payment is backed by a crypto quote: a fixed conversion rate valid for a limited window. If the customer does not complete the wallet transfer before the quote window closes, the payment moves to `expired`.

The hosted payment page gives the customer a short window to request a new quote before the session ends. If the customer does not act within that window, the payment is automatically marked `expired`.

Expiry is not caused by merchant or integrator action. It is driven entirely by the quote window timing out.

#### Abandoned versus expired

A payment that is created but never started is not `expired`. It is `abandoned`.

* `abandoned`: the payment was created, but the customer never began a payment attempt. No quote, deposit address, or checkout was ever issued for it. Bead closes these payments automatically once the hosted payment session lifetime has passed. There is nothing to reclaim, and the status never changes.
* `expired`: a payment attempt was started (for example a crypto quote was issued) but it was not completed before the window closed. Funds sent after expiry are handled through reclaim, as described below. `expired` is a final status: a reclaim does not change it.

Neither is a paid outcome. Do not fulfill the order for either, and create a new payment if the customer wants to try again.

> **Webhook behavior:** when Bead closes a payment automatically after the hosted payment session lifetime, neither `abandoned` nor `expired` is currently delivered as a payment webhook event. Both are available from `GET /Payments/{paymentId}/tracking`. If a payment stays in `created` or `processing` in your system, reconcile it with the tracking endpoint rather than waiting for a notification. See [Payment Webhooks](/payments/payment-webhooks.md) and [Why is my payment still Created or In Progress?](/faqs-and-troubleshooting/payments-faqs/why-is-my-payment-still-created-or-in-progress.md).

#### What happens to funds sent after expiry?

If a customer sends funds after the payment has expired:

* the funds are not converted
* they remain unconverted and are returned to the payer through Bead's reclaim process
* Bead emails reclaim instructions to the payer if an email address is available
* Bead sends a payment webhook each time `refundLifecycleStatus` changes, and `statusCode` stays `expired`

The integrator does not need to implement the crypto return flow. See [Reclaiming Unconverted Crypto](/reference-guide/payment-scenarios/reclaiming-unconverted-crypto.md) for full details on reclaim timing, windows, and the customer experience.

#### Integrator handling

**Order and fulfillment**

* Treat `expired` as not paid.
* Do not fulfill the order.
* Do not reuse the expired payment URL. It cannot be resumed or extended.
* If the customer still wants to pay, create a new payment and direct them to the new hosted payment URL.

**Internal state mapping**

Map `expired` to a not paid internal state such as:

* Payment expired
* Session timed out
* Awaiting new payment

Do not map `expired` to paid, approved, or any fulfillable state.

**Webhook handling**

When your webhook consumer receives a payload with `statusCode: "expired"`:

1. Verify the webhook signature.
2. Persist the event.
3. Update your internal order or invoice to a not paid state.
4. Surface appropriate messaging to the customer.
5. Return `2xx` promptly.

Use `paymentId` + `statusCode` + `refundLifecycleStatus` as your idempotency key, so that reclaim progress events on an expired payment are not treated as duplicates. `trackingId` is a legacy identifier and should not be used for de-duplication. See [Payment Webhooks](/payments/payment-webhooks.md) for signature verification and processing guidance.

Do not rely on this webhook alone. Payments that Bead closes automatically after the session lifetime are not currently sent as webhook events, so also reconcile any payment still open after your own timeout with `GET /Payments/{paymentId}/tracking`.

#### Customer experience

**In the hosted UI**

When the quote is about to expire, the hosted payment page gives the customer a short window to request a new quote. If no action is taken, the session ends and the payment moves to `expired`.

The customer cannot resume the expired session. They must start a new payment.

**If funds were sent after expiry**

Bead initiates reclaim after the payment expires if funds are received. If a `refundEmail` was included in the original payment request, Bead emails the customer reclaim instructions automatically. If no email was provided, the hosted page prompts the customer for an email when reclaim is required.

The reclaim window is 30 days from the payment's last-updated timestamp. Customers who miss that window should contact support. See [Reclaiming Unconverted Crypto](/reference-guide/payment-scenarios/reclaiming-unconverted-crypto.md).

#### Suggested UI messaging

Use clear, direct messaging so the customer knows what happened and what to do next.

**When the payment expires before the customer pays:**

```
Your payment session expired before a payment was detected. To complete your
purchase, please start a new payment.
```

**When the customer may have sent funds after expiry:**

```
Your payment session expired before a payment was detected. If you sent funds
after the session ended, they will be returned to you through the reclaim
process. To try again, please start a new payment.
```

#### Scenario routing

| Situation                                                                | What to do                                                                                   |
| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
| Payment reached `expired`, no funds sent                                 | Create a new payment if the customer wants to try again                                      |
| Payment reached `expired`, customer may have sent funds late             | Direct customer to check for a reclaim email; create a new payment if they want to try again |
| Payment reached `abandoned`                                              | No funds were requested; create a new payment if the customer wants to pay                   |
| Customer sent funds just before expiry but payment still shows `expired` | Funds are handled through reclaim; create a new payment for the purchase                     |
| Customer wants to resume the expired session                             | Not possible. Create a new payment                                                           |

#### Expiry for Klarna and other non crypto tenders

Klarna checkouts are not backed by a crypto quote, so the quote window mechanism described above does not apply to them. A Klarna payment expires instead when the hosted payment page session ends. That session currently lasts 24 hours. This is an operational setting, so it can change over time. If your integration depends on the exact value, confirm the current setting with your Bead partner contact.

A further difference from crypto tenders: for a Klarna checkout, Bead does not always receive a distinct signal when the customer declines or abandons the checkout. In that case, the payment surfaces as `expired` once the session lifetime elapses, the same as a plain timeout. There is currently no separate status or reason code to distinguish a customer decline or abandonment from a simple timeout for these tenders. Because expiry is detected on a periodic check rather than immediately, the status can lag slightly behind the moment the session actually ended.

Integrator handling is otherwise the same as above: treat `expired` as not paid, do not fulfill, and create a new payment if the customer wants to retry. There is no crypto reclaim flow for these tenders, since no crypto was received.

#### Related pages

* [Payment Statuses](/payments/payment-statuses.md)
* [Reclaiming Unconverted Crypto](/reference-guide/payment-scenarios/reclaiming-unconverted-crypto.md)
* [Under and Over Payment Handling](/reference-guide/payment-scenarios/under-and-over-payment-handling.md)
* [Payment Webhooks](/payments/payment-webhooks.md)
* [Why Did My Payment Expire, and What Happens Next?](/faqs-and-troubleshooting/payments-faqs/why-did-my-payment-expire-and-what-happens-next.md)
* [Why is my payment still Created or In Progress?](/faqs-and-troubleshooting/payments-faqs/why-is-my-payment-still-created-or-in-progress.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://developers.bead.xyz/reference-guide/payment-scenarios/expired-payment-handling.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
