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

# Payment links & hosted checkout

> Charge anyone with a URL. Chipper hosts the checkout; the payer picks mobile money, bank transfer, or stablecoin.

Most merchants don't want a payments integration — they want to get paid. A payment link is one API call (or one dashboard form) that produces a URL. Your customer opens it and pays on a page Chipper hosts, in your branding, over whichever rail they have.

## Links and pages

Two objects, one checkout:

|               | Payment **link** `pl_`                   | Payment **page** `pp_`                        |
| ------------- | ---------------------------------------- | --------------------------------------------- |
| For           | one specific customer — an invoice       | anyone — a storefront, a donation, a bio link |
| Amount        | fixed                                    | fixed, or **open** (payer chooses)            |
| Payer's email | known at creation                        | entered on the page                           |
| Lifetime      | single use — `paid` when settled         | reusable — every payer creates a child link   |
| Stats         | `totalReceived`, `remaining`, `sessions` | `paymentCount`, `totalCollected`              |

## Create a link

```bash theme={null}
POST /v1/payment-links
{
  "email": "ama@example.com",
  "amount": 250,
  "currency": "GHS",
  "title": "Invoice #1042",
  "description": "Event photography — deposit",
  "allowedMethods": ["mobile_money", "bank_transfer", "crypto"],
  "branding": { "businessName": "Zouk Inc.", "accentColor": "#6642D1" }
}
→ { "paymentLink": { "id": "pl_…", "url": "https://…/pl_…", "status": "active", … } }
```

Send `url` to the customer. That's the integration.

## Create a page

```bash theme={null}
POST /v1/payment-pages
{
  "currency": "GHS",
  "title": "Support our work",
  "allowedMethods": ["mobile_money", "crypto"],
  "branding": { "businessName": "Zouk Inc.", "accentColor": "#2f8f6f" }
}
```

Omit `amount` and the page asks the payer what to pay.

## What the payer sees

Your name, logo, and accent colour; the amount; and one of three flows:

* **Mobile money** — picks their operator, enters their number, taps *Pay*. An approval prompt hits their phone. This is the only rail that charges on click.
* **Bank transfer** — taps *Get account details*. A dedicated virtual account is set aside for **this payment**; they transfer the exact amount from their own banking app; we detect it. Partial amounts count and accumulate.
* **Stablecoin** — picks USDC or USDT and a network, gets an address with a QR code and the exact crypto amount at a **locked rate** (90 minutes for stablecoins), plus a "send only USDC on Solana" warning.

Every attempt is a **checkout session** (`cs_…`) with its own countdown (5 min mobile money · 30 min bank · 15–90 min crypto). A failed or expired session never affects the link — the payer just picks another method. On success they get a receipt they can download.

## Branding rules

`accentColor` can be any hex. The checkout paints it in exactly two places — the identity mark and the pay button — with the text colour computed for contrast, so no colour can break the page. `logoUrl` (square) and `businessName` complete the identity.

## Knowing you've been paid

* **Webhooks**: the link's payment settles through the normal rails, so you receive `collection.completed` and `account.credited`; for bank and crypto sessions the checkout deposit fires them too.
* **Polling**: `GET /v1/payment-links/{id}` → `status: "paid"`, with `sessions` showing every attempt and which one succeeded.
* **Dashboard**: Payment links → the link → *Checkout sessions*.

`redirectUrl` on the link sends the payer back to you after success (with a 5-second countdown they can skip).

## Closing and expiry

`PATCH /v1/payment-links/{id} { "status": "closed" }` stops further attempts. `expiresAt` on creation does it on a schedule. Pages close the same way; they never "expire" — an expired page simply refuses new checkouts.

## Sandbox

Everything above works on sandbox with `pl_test_` ids and simulated money. The checkout page carries **dev tools** in local development to complete, partial-pay, fail, or expire a session on demand; via the API, `POST /v1/simulations/checkout-deposit` pays a bank-transfer session.
