> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paywire.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Build your own checkout

> Show the deposit address and amount in your own app instead of the hosted page.

The hosted checkout is built on three public endpoints. Use them yourself to keep the payer in your app: show the coins, create an order for the one they pick, display its address and amount, and follow its status.

> [!NOTE]
>
> These endpoints need no API key, but the API doesn't allow cross-origin browser requests. Call them **from your server** and pass the result to your page.

**1. Show the choices**

```bash theme={null}
curl https://api.staging.paywire.xyz/payments/links/{linkId}/checkout
```

```json theme={null}
{
  "id": "0193a0c4-5f2e-7c1d-9b8a-3e4f5a6b7c8d",
  "merchantName": "Example Shop",
  "amount": 49.90,
  "currency": "USD",
  "allowedAssets": [
    { "network": "solana_devnet", "token": "native", "decimals": 9 },
    { "network": "bitcoin_signet", "token": "native", "decimals": 8 }
  ],
  "orderTtlMinutes": 20,
  "returnUrl": "https://shop.example.com/orders/1042",
  "isActive": true
}
```

**2. Create an order for the payer's choice**

```bash theme={null}
curl -X POST https://api.staging.paywire.xyz/payments/links/{linkId}/orders \
  -H "Content-Type: application/json" \
  -d '{ "network": "solana_devnet", "token": "native", "refundAddress": "4Nd1m...payerAddress" }'
```

`refundAddress` is optional but recommended: it's where over- and underpayments go back. It must be a valid address on that network.

The `201` response is the order:

```json theme={null}
{
  "id": "0193a0c5-0a1b-7c2d-8e3f-4a5b6c7d8e9f",
  "paymentLinkId": "0193a0c4-5f2e-7c1d-9b8a-3e4f5a6b7c8d",
  "status": "AwaitingPayment",
  "network": "solana_devnet",
  "token": "native",
  "decimals": 9,
  "depositAddress": "8xKq3n...depositAddress",
  "refundAddress": "4Nd1m...payerAddress",
  "expectedAmount": "301204819",
  "expectedAmountDisplay": 0.301204819,
  "confirmedAmount": "0",
  "receivedAmount": "0",
  "remainingAmount": "301204819",
  "remainingAmountDisplay": 0.301204819,
  "fiatAmount": 49.90,
  "fiatCurrency": "USD",
  "rate": 165.67,
  "createdAt": "2026-10-24T09:13:05.118Z",
  "expiresAt": "2026-10-24T09:33:05.118Z",
  "resolvedAt": null,
  "deposits": []
}
```

Show `depositAddress`, `expectedAmountDisplay` and a countdown to `expiresAt`. A QR code of the address helps on mobile.

**3. Follow the payment**

Poll every few seconds while the payer is on the page:

```bash theme={null}
curl https://api.staging.paywire.xyz/payments/orders/{orderId}
```

* `receivedAmount` grows as transfers arrive; each one appears in `deposits` with its `txHash`.
* `remainingAmountDisplay` is what's still missing if they underpaid.
* `status` moves to `Confirming`, then a final status. See [Payment statuses](https://docs.paywire.xyz/concepts/payment-statuses.md).

Polling is for the payer's screen. Fulfil the purchase from the [webhook](https://docs.paywire.xyz/guides/webhooks.md), not from polling.

## Errors

| Status | `title` | Meaning |
| - | - | - |
| `404` | `PaymentLink.NotFound` / `Order.NotFound` | Wrong id |
| `409` | `PaymentLink.Inactive` | The link no longer takes payments |
| `400` | `PaymentLink.AssetNotAllowed` | The coin isn't in the link's `allowedAssets` |
| `400` | `Order.InvalidRefundAddress` | The refund address isn't valid on that network |
| `503` | `Order.PriceUnavailable` | No trustworthy price right now; retry shortly |
| `503` | `Order.DepositAddressUnavailable` | An address couldn't be issued right now; retry shortly |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.