# Streaming sessions

> MPP sessions — open one channel, stream many metered deliveries authorized by cumulative off-chain vouchers, and settle once when the session idle-closes.

An MPP **`session`** opens one payment channel and meters **many** deliveries against it. Each delivery is authorized by an off-chain **voucher** carrying a running cumulative total; nothing touches the chain per delivery. When the session goes idle the operator settles the final amount on-chain and refunds the rest.

## When to use it

Reach for a session when you're metering a **stream** rather than a single call:

- a token-by-token SSE response (the canonical case),
- a burst of many cheap calls a client makes in one sitting,
- anything where you want one channel reused across deliveries — and optionally **split** the proceeds across multiple recipients.

For a single call whose cost you only learn afterward, [usage charges (`upto`)](/docs/building-with-pay/payment-channels/upto) are simpler — one authorization, one settlement.

## How it flows

The buyer opens the channel with a deposit (the cap). For each delivery they sign a **cumulative** voucher — if the first authorizes $0.0001 and the next $0.0002, the operator may claim up to $0.0002 total, not the sum. The gateway verifies each voucher and serves off-chain. After the configured idle delay (`close_delay_ms`), the operator settles the final voucher and distributes — refunding the unused deposit. A buyer can `topUp` to extend a channel, and can always force-close (after a grace period) to recover funds if the server goes away.

<Mermaid
  chart={`sequenceDiagram
  participant C as Client
  participant G as pay gateway (operator)
  participant Ch as Channel program
  C->>G: request
  G-->>C: 402 WWW-Authenticate: Payment (session, cap)
  C->>G: Authorization: Payment (action: open, deposit = cap)
  G->>Ch: co-sign + broadcast open
  loop each metered delivery (off-chain)
    C->>G: Authorization: Payment (action: voucher, cumulative total ↑)
    G-->>C: deliver chunk
  end
  Note over G: idle close_delay elapses
  G->>Ch: settle_and_finalize (final voucher) + distribute
  Ch-->>C: refund unused deposit`}
/>

## With the pay CLI

A session needs two things in the spec: a top-level **`session:`** block configuring the channel, and one or more endpoints whose metering accepts `mpp-session`. The channel cap and idle-close delay live on the block; the per-delivery price is the endpoint's metering dimension.

```yaml
# Channel-wide config: deposit ceiling + idle-close delay.
session:
  cap_usdc: 1.0
  close_delay_ms: 2000 # settle + close after 2s of no deliveries
  modes: [pull] # or [push]
  pull_voucher_strategy: client_voucher
  # Optional: split the settled total across recipients (percentage-only).
  splits:
    - recipient: platform
      percent: 30

endpoints:
  - method: GET
    path: 'api/v1/stream'
    description: 'Metered token stream over an MPP session channel.'
    metering:
      schemes: [mpp-session]
      dimensions:
        - direction: usage
          unit: requests
          scale: 1
          tiers:
            - price_usd: 0.0001 # per-delivery price
```

```sh
pay --sandbox server start provider.yml
```

<Callout type="info">
  On-chain settle-at-close needs an operator signer + RPC. With the CLI the gateway owns the metering side channel and
  the settlement transaction for you; on `--sandbox` the operator is provisioned, and in production you set
  `operator.signer` + `operator.fee_payer: true`. Without a signer the close is a state-flip and no on-chain settlement
  signature is produced.
</Callout>

## On the wire

Sessions ride MPP's `402` handshake:

- **`WWW-Authenticate: Payment`** (402) — the session challenge: per-unit `amount`, `channelProgram`, `feePayer`, `minVoucherDelta`, `gracePeriodSeconds`, and optional `distributionSplits`.
- **`Authorization: Payment`** (retry) — a discriminated credential with `action: "open" | "voucher" | "topUp" | "close"`. A `voucher` carries the 48-byte on-chain structure `[channelId | cumulativeAmount | expiresAt]` plus the buyer's Ed25519 signature.
- **`Payment-Receipt`** — `acceptedCumulative` (highest voucher accepted), `spent`, and on close `refunded` + the settlement `txHash`.

Full details: the [MPP Solana session method spec](https://github.com/solana-foundation/mpp-specs/blob/main/specs/methods/solana/draft-solana-session-00.md).

## Next

- [Usage charges (x402 `upto`)](/docs/building-with-pay/payment-channels/upto) — a single metered call instead of a stream.
- [upto vs sessions](/docs/building-with-pay/payment-channels/choosing) — when to pick which.
- [YAML specification](/docs/building-with-pay/yaml-specification) — the `recipients` and split fields a session settlement routes to.
