<!-- Source: https://docs.infraio.xyz/en/api-reference -->
<!-- Last updated: 2026-10-04 -->

# API Reference

Every endpoint below speaks JSON, lives under `https://api.infraio.xyz`
(prod) or `https://api-dev.infraio.xyz` (test), and authenticates via
HMAC-SHA256 — see [Authentication](https://docs.infraio.xyz/en/api-reference/authentication)
for request signing and [Errors](https://docs.infraio.xyz/en/api-reference/errors) for the
error envelope shape.

This page lists the endpoints for merchant integrations. Where an
endpoint has no page of its own, it's described in the related concept page.

> **Note:**
>
> Endpoints under **`/b2b/v1/*`** are HMAC-signed with your **secret**
> key (`sk_…`). This is the surface your backend calls. The merchant
> dashboard and the hosted checkout use their own endpoints, which aren't
> part of the integration API.

## Checkout

| Method | Path | Purpose | Notes |
| --- | --- | --- | --- |
| `POST` | `/b2b/v1/checkout-sessions/quick` | Create a session in one call — order + checkout-session minted together. | See [Quickstart](https://docs.infraio.xyz/en/get-started/quickstart#2-create-a-checkout-session-server) for the request body and sample. |
| `POST` | `/b2b/v1/checkout-sessions` | Create a session against an *existing* order. Use when your platform already has its own order model and you want one session per attempt. | The two-step flow. |
| `GET` | `/b2b/v1/checkout-sessions/by-order/{order_id}` | List all sessions ever minted for an order. | Useful when a buyer abandoned a session and you want to surface the previous attempts in your dashboard. |

## Orders

Orders are the timeless billable entity. A single order can back
multiple checkout sessions (e.g. buyer abandons, retries).

| Method | Path | Purpose | Notes |
| --- | --- | --- | --- |
| `POST` | `/b2b/v1/orders` | Create an order without a session. | Use when you want to send the buyer a payment link later instead of redirecting them immediately. |
| `GET` | `/b2b/v1/orders/{id}` | Read a single order with line items + status. | Status: `PENDING` → `PAID` \| `PARTIAL_PAID` \| `CANCELED`. After refund: `PARTIALLY_REFUNDED` \| `REFUNDED`. |
| `GET` | `/b2b/v1/orders/by-merchant/{merchant_id}` | List your orders, cursor-paginated. | See [Cursor pagination](#cursor-pagination) for the cursor protocol. |
| `PATCH` | `/b2b/v1/orders/{id}/cancel` | Mark an unpaid order canceled. Emits `order.canceled`. | Fails if the order is already paid. |
| `PATCH` | `/b2b/v1/orders/{id}/reopen` | Reverse an auto-cancel (`canceled_reason=payment_timeout`). | Useful if the buyer comes back after the TTL expired. |

## Refunds

See [Refunds concept page](https://docs.infraio.xyz/en/concepts/refunds) for the saga flow
and token lifecycle.

### Merchant-initiated

| Method | Path | Purpose | Notes |
| --- | --- | --- | --- |
| `POST` | `/b2b/v1/merchants/{merchant_id}/refunds` | Merchant-initiated refund. Auto-approved (skips `PENDING`). | Emits `payment.refund.approved` immediately. |

### Customer-initiated — refund-request tokens

The buyer fills the refund form on our hosted page; you only mint
the token and deliver the URL. You can mint tokens from your backend
(below) or from the merchant dashboard. Renewals and cancellations are
handled in the dashboard.

| Method | Path | Auth | Purpose |
| --- | --- | --- | --- |
| `POST` | `/b2b/v1/merchants/{merchant_id}/refund-requests` | HMAC (`sk_…`) | Mint a token from your backend. Body: `{ref_type, ref_value, amount, ttl_seconds?, metadata?, hide_summary?, hide_header?}`. `ref_type` is one of `order_id` / `order_number` / `session_id` / `session_key`; `ref_value` is the matching identifier. `amount` is **required** and locks the maximum the buyer can submit. Default TTL **30 min**. Emits `refund_request.created` (`source: b2b`). |

### Refund lifecycle (post-create)

Applies to both flows. The endpoints below operate on the refund
itself (id starts `rfn_…`), not the request token.

| Method | Path | Purpose | Notes |
| --- | --- | --- | --- |
| `GET` | `/b2b/v1/refunds/{id}` | Read one refund. | Status: `PENDING` → `APPROVED` → `EXECUTED` \| `REJECTED`. |
| `GET` | `/b2b/v1/refunds/by-merchant/{merchant_id}` | List your refunds, cursor-paginated. | — |
| `POST` | `/b2b/v1/refunds/{id}/approve` | Approve a `PENDING` refund (customer-initiated only — merchant-initiated lands `APPROVED` already). | Crypto: lands `APPROVED`, you call `/submit-tx` next. |
| `POST` | `/b2b/v1/refunds/{id}/reject` | Deny a `PENDING` refund. | Emits `payment.refund.rejected`. |
| `POST` | `/b2b/v1/refunds/{id}/submit-tx` | Crypto only — stamp the on-chain tx hash you broadcast. | Body: `{tx_hash, network, token_address}` — all three required. |

## Catalog (read-only)

| Method | Path | Purpose |
| --- | --- | --- |
| `GET` | `/v1/supported/networks` | All chains InfraIO Pay can settle on (mainnet + testnet, filtered by env). |
| `GET` | `/v1/supported/tokens` | All stablecoins on those chains. |
| `GET` | `/v1/supported/currencies` | Currencies accepted for `order.currency`. |

## Health

| Method | Path | Auth | Purpose |
| --- | --- | --- | --- |
| `GET` | `/health` | None (public) | Liveness check. Returns `{"status":"ok"}`. Point your uptime monitors here. |

## Cursor pagination

Every list endpoint accepts the same query params, returns the same
envelope. Cursors are opaque and are used instead of offsets, so a page never
shifts when a new row arrives while you're paging.

| Query param | Type | Default | Notes |
| --- | --- | --- | --- |
| `cursor` | `string` | — | Opaque — copy the previous response's `next_cursor` verbatim. |
| `limit` | `int` | `20` | `1..100`. |
| `sort_dir` | `'asc' \| 'desc'` | `desc` | Sort by `(created_at, id)`. |
| `from` / `to` | `RFC3339` | — | Optional time-window filter. |
| `search` | `string` | — | Free-text filter where supported. |

Response envelope:

```json
{
  "orders": [ /* page rows */ ],
  "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wNS0...",
  "has_next": true
}
```

`has_next` is always present. `next_cursor` is omitted when `has_next`
is `false`. Treat the cursor as an opaque string.

## What's missing from this page

This page covers the endpoints intended for merchant integrations. If
you need an endpoint that isn't listed, or an OpenAPI spec, contact
support.
