> ## 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.

# Create a session

> Mint a single-order collection session with pulse.collectionSessions.create — the naira and USD gates, idempotency keys, and the returned shape.

Every session picks one of two fiat gates. Construct the client once (see
[Install & initialize](/backend/install)), then mint a session with
`pulse.collectionSessions.create(payload, { idempotencyKey })`.

<Tabs>
  <Tab title="Naira gate">
    The `naira` gate carries per-user identity: add `user_ref` and 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.

    ```ts theme={null}
    import Pulse, { useApiKey } from '@pulsebyshiga/node';

    const pulse = new Pulse(useApiKey(process.env.PULSE_API_KEY!), {
      webhookSecret: process.env.PULSE_WEBHOOK_SECRET,
    });

    // Naira gate — first-time customer (Pulse provisions the virtual account)
    const session = await pulse.collectionSessions.create(
      {
        gate: 'naira',
        target: { currency: 'NGN', amount: '1000000.00' },
        asset: 'USDT',
        network: 'base',
        user_ref: 'your_user_123',
        account: { provision: true, bvn: '...', nin: '...' },
      },
      { idempotencyKey: `fund-${depositId}` },
    );

    // Returning customer:
    // account: { provision: false, virtual_account_ref: "va_..." }
    ```

    <Note>
      BVN/NIN are sensitive — they travel server-to-server only in this call
      and never reach the browser.
    </Note>
  </Tab>

  <Tab title="USD gate">
    The `usd` gate is the simplest path — no `user_ref`, no `account` block;
    funds land in your omnibus rather than a per-user account.

    ```ts theme={null}
    import Pulse, { useApiKey } from '@pulsebyshiga/node';

    const pulse = new Pulse(useApiKey(process.env.PULSE_API_KEY!), {
      webhookSecret: process.env.PULSE_WEBHOOK_SECRET,
    });

    // USD gate — no user_ref, no account block; funds land in your omnibus.
    const session = await pulse.collectionSessions.create(
      {
        gate: 'usd',
        target: { currency: 'USD', amount: '100.00' },
        asset: 'USDT',
        network: 'base',
      },
      { idempotencyKey: `fund-${depositId}` },
    );
    ```
  </Tab>
</Tabs>

## Idempotency

Pass an `idempotencyKey` (e.g. keyed off your own deposit/order id) so a retried
request — a network blip, a duplicate click — mints the same session instead of
a second one.

## The returned shape

```ts theme={null}
// {
//   session_token,   // 'cs_…' — hand this to the frontend, never the sk_ key
//   order_id,
//   deposit_address,
//   qr_payload,      // Solana Pay / EIP-681
//   quote,           // rate, asset_amount, locked_until
//   status,
// }
```

Return only `session.session_token` to your frontend — it is the only Pulse
credential the browser ever holds. See
[Render the payment moment](/render/choose-a-model) for how the client
consumes it, and [Webhooks](/backend/webhooks) for how you confirm settlement.
