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

# How it works

> Sessions and orders, fiat gates, assets and networks, quote locking, and the money-moment lifecycle.

## Sessions and orders

Your backend mints a single-order collection session with `pulse.collectionSessions.create()`.
The session is the bridge to the browser: it returns a `session_token` (`cs_…`), and the
order it minted carries everything the payment surface needs — `deposit_address`,
`qr_payload` (Solana Pay / EIP-681), `quote` (`rate`, `asset_amount`, `locked_until`),
`status`, `amount_status`, `deposit`, and `disbursement`. Whether you render with a
drop-in component or build your own UI against the API, this order is what you're
driving to completion.

## Fiat gates

Every session picks one of two fiat gates:

* **`naira`** — carries per-user identity. Add `user_ref` plus an `account` block:
  `{ provision: true, bvn, nin }` for a first-time customer, so Pulse provisions their
  named virtual account, or `{ provision: false, virtual_account_ref }` for a returning
  one. BVN/NIN are sensitive — they travel server-to-server only and never reach the
  browser.
* **`usd`** — no `user_ref`, no `account` block. Funds land in your omnibus rather
  than a per-user account.

Each order also has a **direction**: `offramp` (the default — your user pays crypto and
you collect fiat) or `onramp` (your user pays fiat and receives crypto). The
engine-direct onramp flow is live today — see [Onramp](/backend/onramp).

## Assets and networks

Sessions accept stablecoin assets (`USDC`, `USDT`) on a network. Two network surfaces
exist, and the casing tells you which one you're on:

* **`Network`** (product surface — collection sessions) is **lowercase**: `base`,
  `polygon`, `arbitrum`, and others. Solana and TON are recognised but
  **coming soon** (see [Supported stablecoins](/supported-stablecoins)).
* **`EngineNetwork`** (engine surface — quotes, rates, offramp, onramp) is
  **UPPERCASE**: `BASE`, `POLYGON`, `ARBITRUM`, `OPTIMISM`, `ETHEREUM`, `BSC`.

Pass the casing that matches the call you're making. The full asset and network lists
live in the [SDK reference](/reference/node).

## Quotes and locking

A quote is a locked price; creating one moves no money and creates no order. The
order's `quote` carries the locked `rate`, the `asset_amount` to send, and a
`locked_until` expiry. A separate `rates.preview()` call reshapes a quote for
display with no order created, returning `{ rate, youSend, youReceive, expiresAt,
quoteId }`. When an order's quote expires, re-lock it with
`collectionOrders.refreshQuote(orderId)` rather than creating a new order.

## The money-moment lifecycle

A payment moves through the states reflected in the webhook event names:
`collection.order.created` → `collection.deposit.detected` →
`collection.deposit.confirmed` → `disbursement.completed`. Alongside the happy path,
edge states can occur at any point: `collection.amount.underpaid` / `.overpaid`,
`collection.deposit.wrong_chain` (funds arrived on the wrong network; the order is
still payable on the right one), `collection.order.expired`, and
`collection.order.failed`. The sandbox can simulate every one of these directly
against a real order.

## Webhooks are the source of truth

Client-side callbacks like `onSuccess` are UX signals only — they can be spoofed.

<Warning>
  **Credit a customer only after a verified `disbursement.completed` webhook.**
  Client-side callbacks such as `onSuccess` are UX signals — they can be spoofed.
  The signed webhook is the only source of truth for crediting a user.
</Warning>
