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

# Payments

> Create and read sessions from your server.

<Warning>
  Server-side only. These functions send your secret key and throw if `window`
  exists. Create the session on your server and hand the browser the returned
  `id` or `url`.
</Warning>

## Create a session

```typescript theme={"system"}
import { createCheckout } from "@hypermid/sdk";

const session = await createCheckout(
  {
    orderId: "order-8842",
    chain: 8453,
    token: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    amount: "10000000",           // 10 USDC, 6 decimals
    recipient: "0xYourTreasury…",
    successUrl: "https://shop.example/thanks",
    cancelUrl: "https://shop.example/cart",
  },
  { secretKey: process.env.HYPERMID_SECRET_KEY! },
);

// Hand this to the browser.
return { url: session.url, id: session.id };
```

`createDeposit` and `createWithdrawal` take the same request shape.

| Function           | Product                                        |
| ------------------ | ---------------------------------------------- |
| `createCheckout`   | [Checkout](/guides/checkout) — fixed amount    |
| `createDeposit`    | [Deposit](/guides/deposit) — often open-amount |
| `createWithdrawal` | [Withdrawal](/guides/withdrawal) — funds out   |
| `getPayment`       | Read a session you created                     |

## Request fields

Beyond `chain` / `token` / `recipient`, the create call accepts:

| Field                      | Type     | Notes                                                                                                                                                                |
| -------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `amount`                   | `string` | Base units (`"10000000"` = 10 USDC at 6 decimals). **Omit for an open amount** — the payer names it. Fixed for a checkout, usually open for a deposit.               |
| `minAmount` / `maxAmount`  | `string` | Bounds on an **open-amount** session. **Ignored when `amount` is fixed.**                                                                                            |
| `orderId`                  | `string` | Your id, and the idempotency key (see below).                                                                                                                        |
| `metadata`                 | `object` | Arbitrary JSON. Echoed back on session reads and on every [webhook](/guides/webhooks); **never shown to the payer**. Keep it small — an oversized object is a `413`. |
| `expiresIn`                | `number` | Session lifetime in **seconds**. Defaults to the server's configured TTL. After it elapses the session is `expired`.                                                 |
| `successUrl` / `cancelUrl` | `string` | Where the hosted page sends the payer afterwards.                                                                                                                    |

For a session that offers the payer more than one destination, see
[multi-destination deposits](/guides/deposit) (`destinations` /
`destinationRecipients`) — those replace the top-level `chain` / `token` /
`recipient`.

<Warning>
  For a **checkout**, `recipient` must be on your payout allowlist. An
  un-allowlisted recipient is refused with `403 RECIPIENT_NOT_ALLOWLISTED` — add
  it in the partner portal first. Deposits and withdrawals are not allowlist-checked
  this way (a deposit lands in the payer's own wallet).
</Warning>

## Idempotency

Creation is idempotent on `orderId`. Replaying the same `orderId` while a
session is still open returns the **existing** session rather than opening a
second one:

```typescript theme={"system"}
const again = await createCheckout({ orderId: "order-8842", /* … */ }, opts);
// again.id === session.id
```

So a retry after a network timeout is safe — it cannot double-charge. Use your
own order identifier and this property comes for free.

## Reading a session

```typescript theme={"system"}
import { getPayment } from "@hypermid/sdk";

const session = await getPayment(id, { secretKey: process.env.HYPERMID_SECRET_KEY! });
if (session.status === "completed") { /* fulfil */ }
```

<Note>
  Prefer a [webhook](/guides/webhooks) over polling. The webhook fires as soon as
  funds land; polling adds latency and load for the same answer. Read the session
  to *confirm* what a webhook told you, not to discover it.
</Note>

## Sandbox

Pass an `sk_test_…` key. Nothing else changes — same functions, same host, same
payloads, testnets only. See [Environments](/environments).

```typescript theme={"system"}
const opts = {
  secretKey: process.env.NODE_ENV === "production"
    ? process.env.HYPERMID_SECRET_KEY_LIVE!
    : process.env.HYPERMID_SECRET_KEY_TEST!,
};
```

## Options

```typescript theme={"system"}
interface PaymentsClientOptions {
  secretKey: string;      // sk_live_… or sk_test_…
  apiBase?: string;       // defaults to https://server.hypermid.io
  signal?: AbortSignal;   // for timeouts and cancellation
}
```
