<!-- tempo-docs-context -->
> Source: [/docs/guide/machine-payments/server](https://tempo.xyz/developers/docs/guide/machine-payments/server.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.

<span id="server-quickstart-add-mpp-payments-to-your-server" />

# Accept payments for an API

Add payment verification to an API endpoint. Use the `mppx` middleware for your framework, or call `mppx/server` with the Fetch API.

## Set the server secret

`Mppx.create()` requires a server secret to authenticate payment challenges. Generate one before starting the server:

```bash
export MPP_SECRET_KEY="$(openssl rand -base64 32)"
```

Store this value in your deployment's secret manager and reuse it across server instances. It is separate from the account's signing key.

## MPP server framework middleware

Use the framework-specific middleware from `mppx` to integrate payment into your server. Each middleware handles the `402` challenge/credential flow and attaches receipts automatically.

:::code-group
```ts [Next.js]
import { Mppx, tempo } from 'mppx/nextjs'

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

export const GET =
  mppx.charge({ amount: '0.1' })
  (() => Response.json({ data: '...' }))
```

```ts [Hono]
import { Hono } from 'hono'
import { Mppx, tempo } from 'mppx/hono'

const app = new Hono()

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

app.get(
  '/resource',
  mppx.charge({ amount: '0.1' }),
  (c) => c.json({ data: '...' }),
)
```

```ts [Express]
import express from 'express'
import { Mppx, tempo } from 'mppx/express'

const app = express()

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

app.get(
  '/resource',
  mppx.charge({ amount: '0.1' }),
  (req, res) => res.json({ data: '...' }))
```
:::

:::tip
You can override `currency` and `recipient` per call if different routes need different payment configurations.

```ts
mppx.charge({
  amount: '0.1',
  currency: '0x...',
  recipient: '0x...',
})
```
:::

## Manual MPP server mode

If you prefer full control over the payment flow, use `mppx/server` directly with the Fetch API.

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

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

export async function handler(request: Request) {
  const response = await mppx.charge({ amount: '0.1' })(request)

  // Payment required: send 402 response with challenge
  if (response.status === 402) return response.challenge

  // Payment verified: attach receipt and return resource
  return response.withReceipt(Response.json({ data: '...' }))
}
```

:::info[Currency and recipient values]
`currency` is the TIP-20 token contract address — [`0x20c0000000000000000000006a37da5c996874be`](https://explore.tempo.xyz/address/0x20c0000000000000000000006a37da5c996874be?live=false) is OUSD on Tempo. `recipient` is the address that receives payment. See the [Tempo payment method](https://mpp.dev/payment-methods/tempo) for supported tokens.
:::

## MPP payment realm

The `realm` identifies your server in payment challenges and onchain attribution. `mppx` resolves it from `MPP_REALM` or supported hosting variables such as `VERCEL_URL`, then falls back to the request URL's hostname. Configure it explicitly when a proxy or deployment exposes an internal hostname.

Set `realm` explicitly to your public domain:

```ts
const mppx = Mppx.create({
  realm: 'api.example.com', // [!code hl]
  methods: [tempo({
    currency: '0x20c0000000000000000000006a37da5c996874be',
    recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
  })],
})
```

You can also set the `MPP_REALM` environment variable instead of passing it in code.

## MPP push and pull modes

Tempo charges support two transaction submission modes, determined by the client:

* **`pull` mode (default)**: the client signs the transaction and sends the serialized transaction to the server. The server broadcasts it and verifies on-chain. This enables the server to sponsor gas fees via a `feePayer`.
* **`push` mode**: the client builds, signs, and broadcasts the transaction itself (for example, via a browser wallet). It sends the transaction hash to the server, which verifies the payment by fetching the receipt.

Your server handles both modes automatically — no configuration required. The server inspects the credential payload type (`transaction` for pull, `hash` for push) and verifies accordingly.

### MPP fee sponsorship

To sponsor gas fees for pull-mode clients, pass a `feePayer` account to `tempo()`:

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

const mppx = Mppx.create({
  methods: [tempo({
    currency: '0x20c0000000000000000000006a37da5c996874be',
    feePayer: Account.fromSecp256k1('0x...'),
    recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
  })],
})
```

When a pull-mode client submits a signed transaction, the server co-signs with the fee payer account before broadcasting. Push-mode clients pay their own gas, so `feePayer` is ignored for those requests.

## Test your MPP server

These examples charge mainnet OUSD. Configure the `mppx` CLI with a funded mainnet account before calling the endpoint; testnet faucet tokens cannot pay a mainnet challenge.

```bash
npx mppx https://your-server.example/resource
```

:::tip
Use `npx mppx --inspect https://your-server.example/resource` to debug your server's Challenge response without making any payments.
:::

To test on Moderato, add `testnet: true` to the server's `tempo({ ... })` configuration. The OUSD address above exists on both networks; `testnet: true` selects chain `42431`. Fund the payer with [testnet OUSD](https://tempo.xyz/developers/docs/quickstart/faucet), and connect the client to the same network. For a browser client, use the [Moderato Wagmi configuration](https://tempo.xyz/developers/docs/guide/machine-payments/client#use-mpp-with-wagmi).

## Next steps for MPP servers

* [Pay for services](https://tempo.xyz/developers/docs/guide/machine-payments/client) — Handle payment-gated resources automatically
* [Accept one-time payments](https://tempo.xyz/developers/docs/guide/machine-payments/one-time-payments) — End-to-end guide with the charge intent
* [Full SDK reference](https://mpp.dev/sdk/typescript/server/Mppx.create) — Complete mppx server API documentation
