# Payment Statuses

Integrators can retrieve the current status of a payment at any time using the `trackingId` returned when the payment is created. Use this endpoint to verify completion, support customer issues, and keep internal records accurate.

Payment status checks complement webhooks, Reporting, and Settlement. Webhooks notify you when something changes, this endpoint lets you query on demand, and Reporting and Settlement provide historical and settlement views across many payments.

### Overview

Use the payment status endpoint when you want to:

* retrieve near real time payment status with a simple GET request
* confirm final outcomes such as `completed`, `expired`, `underpaid`, `overpaid`, or `invalid`
* identify the tender type actually used to pay, such as `bitcoin_Lightning`, `usdcSolana`, `paypal`, `venmo`, or `klarna`
* troubleshoot or support a single payment without pulling a full history

For ongoing monitoring and reconciliation, prefer webhooks plus Reporting and Settlement instead of frequent polling.

### Requesting payment status

Payment status is retrieved by `trackingId`.

#### Endpoint

`GET /Payments/tracking/{trackingId}`

#### Path parameters

<table><thead><tr><th width="154.77777099609375">Name</th><th width="89.22222900390625" align="right">Type</th><th width="123.111083984375" align="right">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>trackingId</code></td><td align="right">string</td><td align="right">Yes</td><td>Tracking identifier returned by the Create Payment response</td></tr></tbody></table>

#### Required headers

Payments endpoints use header based authentication with a terminal API key.

<table><thead><tr><th width="138.4444580078125">Header</th><th>Value</th></tr></thead><tbody><tr><td><code>X-Api-Key</code></td><td><code>{apiKey}</code></td></tr><tr><td><code>Accept</code></td><td><code>application/json</code></td></tr></tbody></table>

Notes:

* the API key is the secret credential
* the masked API key is not usable
* send the full API key value in the `X-Api-Key` header on every Payments request

### Authentication methods for Payment Statuses

#### Using `X-Api-Key`

Use `X-Api-Key` for new Payments integrations.

```http
GET /Payments/tracking/{trackingId}
X-Api-Key: {apiKey}
Accept: application/json
```

#### Using OAuth for legacy Payments integrations

If you are using an existing integration that authenticates Payments through OAuth password grant, send the access token as:

```http
GET /Payments/tracking/{trackingId}
Authorization: Bearer {access_token}
Accept: application/json
```

New integrations should use the `X-Api-Key` method.

### Example request

```bash
curl "https://api.test.devs.beadpay.io/Payments/tracking/{trackingId}" \
  -H "X-Api-Key: {apiKey}" \
  -H "Accept: application/json"
```

### Example response

The endpoint returns a Payment object. The full response in your environment may include additional fields such as payment instructions, conversion details, transactions, notifications, settlement status, and metadata.

The example below is abbreviated to highlight the fields most commonly used for status handling. For completed payments, `tenderType` identifies the tender actually used to pay. The response uses `created` and `updated`; it does not include a `completedAt` field.

```json
{
  "id": "65f0b274f9a4c9a3f8d4b2a1",
  "terminalId": "65f0b274f9a4c9a3f8d4b2a1",
  "paymentCode": "PAY-9X7K2M",
  "trackingId": "c10b29e3c8104e0f8dc139c20d9eeb6c",
  "statusCode": "completed",
  "tenderType": "bitcoin_Lightning",
  "reqCurrencyId": 1,
  "payCurrencyId": 3,
  "amounts": {
    "requested": {
      "inRequestedCurrency": {
        "amount": 100.00,
        "amountPrecision": 2,
        "currencyId": 1
      },
      "inPaymentCurrency": {
        "amount": 0.00154321,
        "amountPrecision": 8,
        "currencyId": 3
      }
    },
    "paid": {
      "inPaymentCurrency": {
        "amount": 0.00154321,
        "amountPrecision": 8,
        "currencyId": 3
      }
    },
    "settleableAmount": {
      "amount": 100.00,
      "amountPrecision": 2,
      "currencyId": 1
    },
    "partnerFees": []
  },
  "reference": "ORDER123",
  "created": "2025-03-04T10:15:30Z",
  "updated": "2025-03-04T10:20:30Z"
}
```

### Using `tenderType`

Use the returned `tenderType` to identify the tender actually used for the payment.

This is especially important when the payment flow presents multiple tender options. For example, an integrator may create one hosted payment session that allows several eligible tenders. When the customer completes the payment with Bitcoin Lightning, the status response returns:

```json
{
  "statusCode": "completed",
  "tenderType": "bitcoin_Lightning"
}
```

Recommended handling:

* store `tenderType` with your order, invoice, or payment record
* use `tenderType` for support, analytics, and tender-level reporting
* use the returned value as the actual tender paid, not only the tender options offered when the payment was created
* expect `tenderType` to be populated for completed payments
* for early or unresolved states, such as `created`, `tenderType` may not yet identify a completed tender

#### BTC Classic and `tenderType`

BTC Classic refers to Bitcoin on-chain payments. In API responses, use the returned `tenderType` value to identify the tender actually used for the payment.

For Bitcoin on-chain payments, the tender type is `bitcoin`. Do not treat `bitcoin_Lightning` as BTC Classic; Bitcoin Lightning is a separate, faster BTC payment rail.

If your payment flow allows multiple tenders, wait for the returned `tenderType` when available. If your integration already knows that the customer selected BTC Classic, you can use that local checkout context for customer messaging, but still use `statusCode` as the source of truth for fulfillment.

Recommended handling:

* use `tenderType: "bitcoin"` for BTC Classic / Bitcoin on-chain handling
* use `tenderType: "bitcoin_Lightning"` for Bitcoin Lightning handling
* do not assume all BTC payments have the same customer wait time
* use `completed`, not `processing`, as the fulfillment trigger

### Status values

Statuses are returned in the `statusCode` field and use the `PaymentStatus` enum.

Statuses marked as reserved are not currently returned by the API but are documented for future compatibility.

### How crypto amount mismatch happens

In most wallet based crypto payments, the customer scans the QR code to set the destination and then manually enters the amount to send in their wallet app. If the customer mistypes the amount, the payment can end as:

* `underpaid` when less than the requested amount is sent
* `overpaid` when more than the requested amount is sent

For both `underpaid` and `overpaid`, the payment is not treated as successful. The crypto that was paid remains unconverted and is returned to the payer through Bead’s reclaim process.

### Status codes

<table><thead><tr><th width="182.8887939453125">Status code</th><th>Description</th></tr></thead><tbody><tr><td><code>created</code></td><td>Payment record created, waiting for customer funds. The actual paid tender may not yet be known.</td></tr><tr><td><code>processing</code></td><td>Funds detected and conversion or settlement processing is in progress. The payment is underway, but it is not final. For most tenders, this state may be brief. For BTC Classic / Bitcoin on-chain payments, this state may last several minutes or longer while the Bitcoin network confirms the transaction. Do not fulfill based on <code>processing</code>.</td></tr><tr><td><code>completed</code></td><td>Customer sent the requested amount. <code>tenderType</code> identifies the tender actually used. Crypto, if any, has been converted and credited. Treat this as the successful final payment state and the fulfillment trigger.</td></tr><tr><td><code>underpaid</code></td><td>Customer sent less than requested. The payment should be treated as not completed. The crypto that was paid remains unconverted and will be returned to the payer through the reclaim process.</td></tr><tr><td><code>overpaid</code></td><td>Customer sent more than requested. The payment should be treated as not completed. The crypto that was paid remains unconverted and will be returned to the payer through the reclaim process.</td></tr><tr><td><code>expired</code></td><td>No funds received before the payment window expired. Any funds sent later remain unconverted and must be reclaimed.</td></tr><tr><td><code>invalid</code></td><td>Irregular event such as multiple transactions, unsupported asset, compliance block, or extreme market movement. Funds remain unconverted and must be reclaimed.</td></tr><tr><td><code>cancelled</code></td><td>Customer or merchant cancelled the payment. Any funds remain unconverted and may be reclaimed.</td></tr><tr><td><code>fullyRefunded</code></td><td>Reserved. Will indicate that the entire payment has been refunded.</td></tr><tr><td><code>partiallyRefunded</code></td><td>Reserved. Will indicate that a portion of the payment has been refunded.</td></tr></tbody></table>

### Integrator handling guidance

Use these rules when mapping payment statuses to your internal order or invoice state.

#### `processing`

Treat as payment detected, but not complete.

A `processing` status means Bead has detected funds and the payment is underway. It does not mean the payment has reached its successful final state.

Do not fulfill the order, release goods, grant digital access, ship an item, or mark an invoice as paid based only on `processing`.

For most tender types, `processing` may be short enough that the customer can remain in the payment flow until the final status is returned.

For BTC Classic / Bitcoin on-chain payments, `processing` can last several minutes or longer. In those flows, the recommended customer experience is to acknowledge that the payment has been detected, let the customer move on, and use webhooks or this endpoint to confirm when the payment reaches `completed`.

Recommended BTC Classic handling:

* show the customer that the BTC payment has been detected
* explain that Bitcoin on-chain confirmation can take several minutes
* move the customer to an order, invoice, receipt, or status screen
* keep the internal order or invoice in a pending payment state
* use Payment Webhooks or this endpoint to detect the final status
* fulfill only after the payment reaches `completed`

Example customer message:

```
Your BTC payment has been detected and is now processing.

Bitcoin on-chain payments can take several minutes to confirm. You do not need to keep this page open. The merchant will confirm when the payment is complete.
```

#### `completed`

* Treat as successful payment.
* Store the returned `tenderType` as the tender actually paid.
* Proceed with fulfillment after you have confirmed the final state via webhooks or this endpoint.
* Use `trackingId`, `statusCode`, `tenderType`, `reference`, `created`, and `updated` to support order lookup and customer support workflows.

#### `underpaid`

* Treat as not successful payment.
* The transaction is not going through. Do not fulfill the order based on an `underpaid` status.
* The crypto that was paid remains unconverted and will be returned to the payer through Bead’s reclaim process.
* Prompt the customer to attempt payment again with a new hosted payment session, based on your normal retry or tender selection flow.

#### `overpaid`

* Treat as not successful payment.
* The transaction is not going through. Do not fulfill the order based on an `overpaid` status.
* The requested amount is not processed as a successful payment, and the overage is not split out separately. The crypto that was paid remains unconverted and will be returned to the payer through Bead’s reclaim process.
* Prompt the customer to attempt payment again with a new hosted payment session, based on your normal retry or tender selection flow.

#### `expired`, `invalid`, `cancelled`

* Treat as not successful payment.
* Do not fulfill the order.
* If funds were sent, they remain unconverted and are handled through reclaim.

For how these states behave in full flows, see the Payment Scenarios pages, which walk through underpaid, overpaid, and reclaim flows in more detail.

### Reclaiming unconverted crypto

When a payment ends in one of the following states:

* `underpaid`
* `overpaid`
* `expired`
* `invalid`
* `cancelled`

any unconverted crypto associated with that payment is handled through Bead’s reclaim process.

For `underpaid` and `overpaid`, the full crypto amount paid by the customer is returned through reclaim. The payment should not be treated as successful, and the integrator should not fulfill the order based on either status.

### Email capture behavior

Bead uses an email based reclaim flow to return unconverted crypto.

* if an email address is included in the original payment request, common in digital and `virtual` terminal flows, Bead will email instructions to the payer when reclaim is required
* if an email address is not included in the request, common in `physical` or terminal based flows, the hosted payment page will prompt the customer to enter an email address when one of these outcomes occurs, then Bead emails the reclaim instructions

Your integration does not need to implement the reclaim process directly, but you should:

* display clear messaging in your UI when these statuses occur
* add internal flags or notes so support and finance teams can recognize reclaim scenarios
* avoid automatically retrying or recreating payments without clear customer intention
* create a new payment session when the customer is ready to attempt payment again

### Error responses

#### Common error responses

<table><thead><tr><th width="82.88885498046875" align="right">Code</th><th>Condition</th></tr></thead><tbody><tr><td align="right"><code>401</code></td><td>Missing or invalid API key. Confirm the <code>X-Api-Key</code> header is present and the key is valid for this environment.</td></tr><tr><td align="right"><code>403</code></td><td>Authenticated, but not permitted to view this payment in the current context. Confirm you are using the correct API key for the terminal and merchant relationship tied to this payment.</td></tr><tr><td align="right"><code>404</code></td><td>No payment exists for this <code>trackingId</code>, or it is not visible in the current context.</td></tr></tbody></table>

Log the response body and headers for debugging, but avoid exposing raw error text directly to end users.

### Best practices

Recommended patterns when using the payment status endpoint:

#### Prefer webhooks for real time changes

Configure Payment Webhooks so your system receives status updates automatically. Use this endpoint for ad hoc checks and support workflows, not as your primary real time mechanism.

Webhooks are especially important for longer-running payment flows such as BTC Classic / Bitcoin on-chain. In those flows, the customer may leave the payment page after the payment reaches `processing`, while the merchant still needs to know when the payment reaches `completed`.

Recommended pattern:

* use the hosted payment page or status endpoint to show the customer the current payment state
* use webhooks to update the merchant order, invoice, or fulfillment workflow
* use this endpoint for customer support, reconciliation checks, or manual refresh actions
* avoid relying on the customer keeping a browser tab open until final completion

#### Store and use `trackingId` as the lookup key

Save the `trackingId` from the Create Payment response alongside your order or invoice. Use it to correlate status checks, webhooks, and Reporting records.

#### Store the actual paid `tenderType`

Save the returned `tenderType` after the payment reaches a final state. This lets your system distinguish between the tenders offered during checkout and the tender actually used to pay.

For example, if a hosted payment flow allowed multiple tenders but the customer paid with Bitcoin Lightning, the completed payment status returns `tenderType: "bitcoin_Lightning"`.

#### Map status codes to internal order states

Translate `completed`, `underpaid`, `overpaid`, `expired`, `invalid`, and `cancelled` into internal states that your business and support team understand.

Only `completed` should be treated as a successful payment. Statuses such as `underpaid` and `overpaid` should be treated as not successful and routed through the appropriate retry and reclaim messaging.

**Use a pending state for BTC Classic processing**

For BTC Classic / Bitcoin on-chain payments, map `processing` to an internal pending state such as:

* payment detected
* pending confirmation
* awaiting BTC confirmation
* payment processing

Do not map BTC Classic `processing` to paid, approved, fulfilled, or complete.

Recommended mapping:

| Bead status  | Internal state                          | Fulfillment behavior    |
| ------------ | --------------------------------------- | ----------------------- |
| `created`    | Awaiting payment                        | Do not fulfill          |
| `processing` | Payment detected / pending confirmation | Do not fulfill          |
| `completed`  | Paid                                    | Fulfillment may proceed |
| `underpaid`  | Payment failed / reclaim required       | Do not fulfill          |
| `overpaid`   | Payment failed / reclaim required       | Do not fulfill          |
| `expired`    | Payment expired                         | Do not fulfill          |
| `invalid`    | Payment invalid / review required       | Do not fulfill          |
| `cancelled`  | Payment cancelled                       | Do not fulfill          |

#### Avoid tight polling loops

If you must poll, use reasonable intervals and a backoff strategy. For anything beyond small scale, move to webhooks together with Reporting and Settlement.

#### Combine with Reporting and Settlement for reconciliation

Use this endpoint for single payment checks. For daily reconciliation and accounting, rely on the Reporting payment history endpoints and the Settlement APIs to see payments, batches, and payment settlement lines together.

### Next steps

* Configure [Payment Webhooks](/payments/payment-webhooks.md) for real time payment events.
* Review [Tender Types](/reference-guide/enumerations-and-schemas/tender-types.md) for the list of valid `tenderType` values.
* Review [Why do BTC Classic payments take longer?](/faqs-and-troubleshooting/payments-faqs/why-do-btc-classic-payments-take-longer.md) for more detail on Bitcoin on-chain confirmation timing and customer messaging.
* Review [Choosing Tender Types by Payment Environment](/reference-guide/payment-flows/choosing-tender-types-by-payment-environment.md) for guidance on when BTC Classic is appropriate for physical, digital, invoice, and delayed-fulfillment flows.
* Review [Payment Scenarios](/reference-guide/payment-scenarios.md) for practical examples of handling non-happy-path statuses such as underpaid and overpaid.
* Use [Reporting](/reporting.md) and [Settlement](/settlement.md) to build dashboards and reconciliation jobs that operate over many payments at once.

### Legacy authentication

Some existing Payments integrations authenticate using OAuth password grant and send an access token as:

```http
Authorization: Bearer {access_token}
```

New Payments integrations should use the terminal API key method described above. If you are on the legacy model, see [Authentication](/authentication.md).


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.bead.xyz/payments/payment-statuses.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
