<!-- tempo-docs-context -->
> Source: [/docs/guide/machine-payments/streamed-payments](https://tempo.xyz/developers/docs/guide/machine-payments/streamed-payments.md)
> Section: [Machine Payments](https://tempo.xyz/developers/docs/agents.md). Pay for APIs, accept API payments, find services, and use Machine Payments Protocol (MPP).
> [Documentation index](https://tempo.xyz/developers/llms.txt) · [Docs skill](https://tempo.xyz/developers/SKILL.md)

> Tempo MCP: Use `search`, `find_pages`, `read_page`, and `code` at `https://mcp.tempo.xyz` for Tempo and related documentation.
> If an indexed page is missing or reflects an older site, read this site’s [documentation index](https://tempo.xyz/developers/llms.txt) and Markdown pages directly.

# Accept streamed payments

Build a payment-gated API that streams content word-by-word and charges $0.001 per word using `mppx` sessions with Server-Sent Events (SSE).

:::info
Streamed payments extend [pay-as-you-go sessions](https://tempo.xyz/developers/docs/guide/machine-payments/pay-as-you-go) with SSE. The server charges per word as content streams. When it needs authorization for more usage, the client sends a new voucher and the stream resumes. If the channel deposit itself is exhausted, more funds must be deposited before usage can continue.
:::

## How streamed payment sessions work

```mermaid
sequenceDiagram
  participant Client
  participant Server
  participant Tempo
  Client->>Tempo: (1) Deposit tokens
  Tempo-->>Client: Channel created
  Client->>Server: (2) Open credential
  Note over Server: Verify on-chain deposit
  Server-->>Client: 200 OK (SSE stream begins)
  loop Per word streamed
      Server-->>Client: (3) SSE data event + charge
      Note over Server: Verify authorized amount
  end
  alt More usage authorization needed
      Server-->>Client: (4) payment-need-voucher event
      Client->>Server: New voucher
      Note over Server: Resume streaming
  end
  Note over Server: (5) Periodic settlement
  Server->>Tempo: settle(channelId, voucher)
  Client->>Server: (6) Close
  Server->>Tempo: close(channelId, voucher)
  Tempo-->>Client: Refund remaining deposit
```

1. **Open** — Client deposits funds into an on-chain reserve contract, creating a payment channel
2. **Stream** — Server calls `stream.charge()` before sending each word to meter usage against the authorized voucher amount
3. **Authorize more usage** — The server emits `payment-need-voucher` when it needs a higher authorized amount; the client signs a new voucher within the funded channel
4. **Close** — Either party closes the channel, settling the final balance on-chain and refunding unused deposit

## Streamed payment server setup

::::steps
### Install streamed payment dependencies

:::code-group
```bash [npm]
npm install mppx viem
```

```bash [pnpm]
pnpm add mppx viem
```

```bash [bun]
bun add mppx viem
```
:::

### Set up an `Mppx` streaming instance

[Set `MPP_SECRET_KEY`](https://tempo.xyz/developers/docs/guide/machine-payments/server#set-the-server-secret) before starting the server.

Configure `tempo.session` directly with `sse: true` to enable SSE support for this session method.

```ts
import { Mppx, tempo } from 'mppx/server'

const mppx = Mppx.create({
  methods: [tempo.session({
    currency: '0x20c0000000000000000000006a37da5c996874be',
    recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
    sse: true,
  })],
})
```

### Add a streamed payment route

Use the standard `Request` / `Response` handler below in a Fetch-compatible server. For Next.js, export it as `GET`. The generator charges each word before sending it; the title is unmetered metadata.

```ts
import { Mppx, tempo } from 'mppx/server'

const mppx = Mppx.create({
  methods: [tempo.session({
    currency: '0x20c0000000000000000000006a37da5c996874be',
    recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
    sse: true,
  })],
})

export async function GET(request: Request) {
  const result = await mppx.session({
    amount: '0.001',
    unitType: 'word',
  })(request)

  if (result.status === 402) return result.challenge

  return result.withReceipt(async function* (stream) {
    yield JSON.stringify({ title: 'Payment confirmation' })
    for (const word of 'Your payment has been received.'.split(' ')) {
      await stream.charge()
      yield word
    }
  })
}
```

### Test the streamed payment endpoint

For Next.js App Router, save the handler as `app/api/sessions/poem/route.ts`, then use the client below. A successful request streams the title metadata followed by the words “Your payment has been received.” This example charges mainnet OUSD. Use a funded mainnet account; testnet faucet tokens cannot pay a mainnet challenge. To use test funds, [configure the server and client for Moderato](https://tempo.xyz/developers/docs/guide/machine-payments/server#test-your-mpp-server).
::::

## Streamed payment client setup

Use [`tempo.session.manager()`](https://mpp.dev/sdk/typescript/client/Method.tempo.session-manager) from `mppx/client` to create a session manager. The `.sse()` method connects to the SSE endpoint and handles voucher renewal automatically — if the server requests a new voucher mid-stream, the client signs and sends one without interrupting the stream.

```ts
import { tempo } from 'mppx/client'
import { Account } from 'viem/tempo'

const session = tempo.session.manager({
  account: Account.fromSecp256k1('0x...'),
  maxDeposit: '1', // Lock up to 1 OUSD per channel
})

try {
  const stream = await session.sse('http://localhost:3000/api/sessions/poem')
  for await (const word of stream) {
    process.stdout.write(word + ' ')
  }
} finally {
  await session.close()
}
```

* **`tempo.session.manager()`** — Creates a session manager that handles the full channel lifecycle: open, voucher signing, and close.
* **`.sse()`** — Connects to an SSE endpoint. Automatically sends new vouchers when the server emits `payment-need-voucher` events.
* **`maxDeposit: '1'`** — Locks up to 1 OUSD. At $0.001/word, this covers ~1,000 words before the channel needs a top-up.

## Next steps for streamed payments

* [Accept one-time payments](https://tempo.xyz/developers/docs/guide/machine-payments/one-time-payments) — Charge per request with on-chain settlement
* [Accept pay-as-you-go payments](https://tempo.xyz/developers/docs/guide/machine-payments/pay-as-you-go) — Session-based billing without streaming
* [Full session reference](https://mpp.dev/payment-methods/tempo/session) — Complete tempo.session API documentation
