> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.crisscross.money/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.crisscross.money/_mcp/server.

# Per Session

> How Adaptive Currency Conversion prices a checkout with a per-session rate — no endpoint to call, the quote is minted at session creation and returned as fxCommit.

The per-session rate is the default way [Adaptive Currency Conversion](/adaptive-currency-conversion) prices a conversion — the alternative to a pre-fetched [rate lock](/rate-locks). There is **no endpoint to call and no field to set**: when a session needs a conversion and no `rateLockId` is supplied, an implicit FX quote is minted at session creation, valid for minutes, and refreshed automatically on the hosted page if it expires.

## When it applies

A per-session rate prices the session when, at [Create Checkout Session](/api-reference/collect/payments/payment-initiation/create-checkout-session):

1. The session `currency` (the currency you price in) differs from the payer's `collectionCurrency` — or from the primary currency of `payerDetails.location` when `collectionCurrency` is omitted, and
2. no `rateLockId` is supplied.

If a `rateLockId` is supplied, the session is priced by the [rate lock](/rate-locks) instead. If no conversion is needed, the payer is simply charged in the initiation currency and no FX commit is written.

## Reading the rate back

The committed conversion is returned inline on [Get Checkout Session](/api-reference/collect/payments/payment-initiation/get-checkout-session) as `fxCommit`. For a per-session rate, `pricingModel` is `SPOT_QUOTE` and `quoteId` is the upstream quote identifier, preserved for audit:

```json
{
  "session": {
    "id": "01951c8a-7c3d-7e1f-9d4a-2b3c4d5e6f70",
    "merchantId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "merchantReference": "ORDER-20260624-001",
    "amount": 10000,
    "currencyId": "USD",
    "expiresAt": "2026-06-24T11:00:00Z",
    "customerId": "9b2d7f3a-8c4e-4f1a-9d3e-1a2b3c4d5e6f",
    "payerLocation": "KEN",
    "redirectUrl": "https://merchant.example.com/order/confirmation",
    "paymentAttributes": {
      "paymentMethod": "card",
      "platform": "web"
    },
    "fxCommit": {
      "quoteId": "qut_01951c8a-9d5e-7f3b-bc4f-6e7d8c9b0a21",
      "pricingModel": "SPOT_QUOTE",
      "collectionCurrency": "KES",
      "collectionAmount": "13260.00",
      "midRate": "130.00",
      "markupBps": 200,
      "allInRate": "132.60",
      "fee": "260.00",
      "expiresAt": "2026-06-24T10:35:00Z"
    }
  }
}
```

Compare with a rate-locked session, where `pricingModel` is `RATE_LOCK` and `quoteId` is the `rlk_` rate lock id — see the response examples on [Get Checkout Session](/api-reference/collect/payments/payment-initiation/get-checkout-session).

## Expiry and refresh

A per-session quote is valid for **minutes, not hours** — note `fxCommit.expiresAt` above versus the session's own `expiresAt`:

* **On the hosted checkout page** — the rate refreshes automatically in place when the quote expires; the payer proceeds at the refreshed rate with no merchant action needed.
* **At payment initiation** — a payment submitted against an expired `fxCommit` is rejected with `422` (stale quote). Refresh the session and re-submit against the current rate. This is the safety net for direct-API integrations.

The expiry check runs when the payment is **initiated**, and this is the same for both flows. A payment initiated inside the validity window settles at the rate snapshotted onto the transaction, even if the quote expires while the payment is still being authorized — expiry never fails an in-flight payment, for a per-session rate or a rate lock alike.

Because of the refresh, `fxCommit` on the session reflects the *latest* committed conversion. The rate a payer actually transacted at is snapshotted per-attempt on the [transaction](/api-reference/collect/payments/manage-payments/get-transaction) (`collection`, `fxMidRate`, `fxAllInRate`, `fxMarkupBps`) — immutable once written, and authoritative for reconciliation.

## When to use a rate lock instead

Use the per-session rate when you just need the payer's currency converted at the moment of purchase. If you want one rate to hold across many checkouts — steady-state pricing, valid for hours and reusable until expiry — fetch a [rate lock](/rate-locks) and pass its `rateLockId` at session creation.