# Quick Start

This guide walks you through creating a crypto payment, launching the hosted payment page, and confirming the final outcome. It also includes the required behavior for underpayments and overpayments.

### What you will build

* Create a hosted crypto payment session
* Present the hosted payment page to a customer
* Confirm payment completion using webhooks or status polling
* Handle `underpaid` and `overpaid` outcomes correctly
* Understand the reclaim flow for any unconverted crypto

### Prerequisites

You will need:

* A sandbox terminal API key (the secret `apiKey`, not a masked value)
* A sandbox `merchantId` and `terminalId`
* A server or tool capable of making HTTPS requests (curl, Postman, your backend)

Optional but recommended:

* A webhook endpoint for payment status updates

### Environment and base URLs

Common sandbox base URL:

* `https://api.test.devs.beadpay.io`

Payments endpoints used in this quick start:

* `POST /payments/crypto`
* `GET /payments/tracking/{trackingId}`

Authentication used in this quick start:

* `X-Api-Key: {apiKey}`

### Step 1: Create a payment

Create a hosted payment session and receive a `trackingId` plus one or more hosted `paymentUrls`.

#### Request

`POST https://api.test.devs.beadpay.io/payments/crypto`

Headers:

* `X-Api-Key: {apiKey}`
* `Content-Type: application/json`
* `Accept: application/json`

Minimal body:

```json
{
  "terminalId": "TERM-123",
  "merchantId": "MERCH-456",
  "requestedAmount": 100.00,
}
```

Recommended additions:

* `refundEmail`: If you have an email address for the payer, include it. This is the email Bead uses to send reclaim instructions when reclaim is required.
* `redirectUrl`: If you want the hosted experience to return the shopper to your confirmation page.
* `webhookUrls`: If you want webhooks for this payment in addition to any terminal level webhook configuration.

Example expanded body:

```json
{
  "terminalId": "TERM-123",
  "merchantId": "MERCH-456",
  "requestedAmount": 100.00,
  "reference": "ORDER-0001",
  "description": "Sample order",
  "refundEmail": "customer@example.com",
  "redirectUrl": "https://merchant.example.com/payment-return",
  "webhookUrls": [
    "https://merchant.example.com/webhooks/payments"
  ]
}
```

#### Example curl

```bash
curl -s -X POST "https://api.test.devs.beadpay.io/payments/crypto" \
  -H "X-Api-Key: {apiKey}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "terminalId": "TERM-123",
    "merchantId": "MERCH-456",
    "requestedAmount": 100.00,
    "reference": "ORDER-0001",
    "refundEmail": "customer@example.com"
  }'
```

#### Response

You will receive a response similar to:

```json
{
  "trackingId": "c10b29e3c8104e0f8dc139c20d9eeb6c",
  "paymentPageId": "a12b34c56d789e01",
  "paymentUrls": [
    "https://pay.qa.beadpay.io/crypto?paymentPageId=a12b34c56d789e01"
  ]
}
```

Save:

* `trackingId`: your lookup key for status, webhooks, reporting, and support
* `paymentUrls[0]`: the hosted payment page URL to present to the customer

### Step 2: Present the hosted payment page

Open the hosted page URL from `paymentUrls`.

Common options:

* Web: open in a new tab or window, or embed (if allowed in your flow)
* Mobile: open in an in app browser or webview
* POS or terminal assisted: display the hosted page on a customer facing device

What the customer will do (typical crypto wallet flow):

1. Select an asset (example: BTC, USDC)
2. View a QR code or payment details
3. Open their wallet app and scan the QR code
4. Manually enter the crypto amount in their wallet app
5. Submit the transfer

Important: because the wallet requires the payer to enter an amount manually, miskeyed amounts can result in `underpaid` or `overpaid`.

### Step 3: Confirm the final result

You should always confirm the final status before fulfilling an order. Use either webhooks or status polling.

#### Option A: Webhooks (recommended)

If you configured webhooks (terminal level and or per payment `webhookUrls`), your server will receive events when the payment status changes.

Recommended handling:

* Verify the webhook signature if your configuration supports it
* Persist the event quickly
* Return `200 OK` promptly
* Treat the webhook as the primary status signal

#### Option B: Polling

Use the tracking endpoint with the `trackingId` until the payment reaches a terminal status.

Request:

`GET https://api.test.devs.beadpay.io/payments/tracking/{trackingId}`

Example curl:

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

Recommended polling behavior:

* Use a reasonable interval (example: 2 seconds) during an active checkout
* Stop polling once a terminal status is returned
* Prefer webhooks for production scale

### Step 4: Handle status outcomes

The payment status is returned in `statusCode`.

#### Non terminal statuses

| statusCode   | Meaning                                      |
| ------------ | -------------------------------------------- |
| `created`    | Payment created, waiting for customer action |
| `processing` | Funds detected and processing is in progress |

#### Terminal statuses

| statusCode  | Meaning                                                | What you should do                                   |
| ----------- | ------------------------------------------------------ | ---------------------------------------------------- |
| `completed` | Customer paid the requested amount                     | Fulfill and mark as paid                             |
| `underpaid` | Customer sent less than requested                      | Treat as not successful payment, do not fulfill      |
| `overpaid`  | Customer sent more than requested                      | Treat as successful payment for the requested amount |
| `expired`   | Payment window ended without a valid completion        | Treat as not successful payment, do not fulfill      |
| `invalid`   | Irregular condition, funds not eligible for conversion | Treat as not successful payment, do not fulfill      |
| `cancelled` | Payment cancelled                                      | Treat as not successful payment, do not fulfill      |

### Underpayments and overpayments

Underpayments and overpayments occur because the payer manually enters the crypto amount in their wallet app.

#### Underpaid

Definition: the payer sent less than the requested amount.

Integrator behavior:

* Treat as not successful payment
* Do not fulfill the order
* If the customer still wants to pay, create a new payment and start a new hosted checkout session

What Bead does:

* The crypto received remains unconverted
* The full amount received is returned to the payer through the reclaim process

#### Overpaid

Definition: the payer sent more than the requested amount.

Integrator behavior:

* Treat as successful payment for the requested amount
* Fulfill once you confirm the terminal status
* Do not attempt to refund the overage yourself

What Bead does:

* The requested portion is processed and settled
* The overage remains unconverted and is returned to the payer through the reclaim process

### Reclaiming unconverted crypto

Reclaim is how Bead returns any unconverted crypto to the payer.

Reclaim can occur when the payment is:

* `underpaid`
* `overpaid` (overage only)
* `expired`
* `invalid`
* `cancelled`

#### Email behavior for reclaim

* If you provided `refundEmail` in the Create Payment request, Bead emails reclaim instructions to that address when reclaim is required.
* If `refundEmail` was not provided, the hosted payment page prompts the payer to enter an email address in underpaid and overpaid outcomes so Bead can send reclaim instructions.

Recommended best practice:

* Provide `refundEmail` whenever you have it, especially for digital and virtual checkout flows.

### Troubleshooting

#### 401 Unauthorized

Common causes:

* Missing `X-Api-Key` header
* Using a masked value instead of the real `apiKey`
* Using a key from the wrong environment

#### Hosted payment page does not load

Common causes:

* Using an old or incorrect `paymentUrls` value
* Terminal is not configured for the tender types you are testing
* Environment mismatch between API base URL and hosted page environment

#### Status never reaches a terminal state

Common causes:

* Customer did not complete the wallet transfer
* Customer sent funds after the payment expired
* Webhook endpoint is failing and you are relying only on webhooks without polling

### Next steps

After you complete this quick start in sandbox:

* Review [Payment Statuses ](https://developers.bead.xyz/payments/payment-statuses)for full status definitions and guidance
* Review [Under and Over Payment Handling](https://developers.bead.xyz/reference-guide/payment-scenarios/under-and-over-payment-handling) for detailed integrator workflows
* Review [Reclaiming Unconverted Crypto](#reclaiming-unconverted-crypto) to understand reclaim timing and payer experience
* Implement production grade webhooks and internal state mapping before going live
