> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://mpp.dev/api/mcp` to find what you need.

# EVM charge \[One-time EVM payments]

## Choose a signing account

### Direct

Create a server-only wallet.ts module, then import account wherever an example creates a local signing account.

```ts
import { privateKeyToAccount } from 'viem/accounts'

export const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
```

### Privy

Create an EVM wallet in Privy, fund it with the required currency on this page's network, and keep PRIVY\_APP\_SECRET server-side.

```bash
pnpm add @privy-io/node
```

Create a server-only privy.ts module, then import its account wherever an example configures account or feePayer.

```ts
import { PrivyClient } from '@privy-io/node'
import { createViemAccount } from '@privy-io/node/viem'

const privy = new PrivyClient({
  appId: process.env.PRIVY_APP_ID!,
  appSecret: process.env.PRIVY_APP_SECRET!,
})

export const account = createViemAccount(privy, {
  address: process.env.PRIVY_WALLET_ADDRESS as `0x${string}`,
  walletId: process.env.PRIVY_WALLET_ID!,
})
```

createViemAccount delegates signatures to the Privy wallet, so it replaces any local viem account in the examples on this page.

The EVM implementation of the [charge](/intents/charge) intent.

The server issues a Challenge describing the amount, currency, and recipient. The client signs an EIP-3009 authorization and returns it as a Credential. When x402 options are enabled, the same route also handles x402 exact flows.

This method is best for fixed-price API calls, paid content, and inline x402-compatible stablecoin payments.

## Server

Use `evm.charge` to gate an endpoint behind a one-time EVM stablecoin payment. Configure `x402.facilitator` when the same endpoint also accepts x402 exact Credentials.

```ts twoslash [server.ts]
import { Mppx, evm } from 'mppx/server'

const mppx = Mppx.create({
  methods: [
    // [!code hl:start]
    evm.charge({
      currency: evm.assets.baseSepolia.USDC,
      recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
      x402: {
        facilitator: 'https://x402.org/facilitator',
      },
    }),
    // [!code hl:end]
  ],
  secretKey: process.env.MPP_SECRET_KEY ?? 'local-dev-secret',
})

export async function handler(request: Request) {
  const result = await mppx.evm.charge({
    amount: '0.01',
    description: 'Premium API access',
  })(request)

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

  return result.withReceipt(Response.json({ data: '...' }))
}
```

## Client

Use `evm.charge` with `Fetch.from` to automatically handle `402` responses. The client signs native MPP EVM charge Challenges, route-bound x402 exact Challenges, and standard x402 v2 EIP-3009 Challenges without the optional `mppx` extension, including Challenges from official Coinbase x402 resource servers.

```ts twoslash [client.ts]
import { Fetch, evm } from 'mppx/client'
import { privateKeyToAccount } from 'viem/accounts'

const fetch = Fetch.from({
  methods: [
    evm.charge({
      account: privateKeyToAccount(
        '0x0123456789012345678901234567890123456789012345678901234567890123',
      ),
      currencies: [evm.assets.baseSepolia.USDC],
      maxAmount: '1.00',
    }),
  ],
})

const response = await fetch('https://api.example.com/paid')
console.log(response.status)
// @log: 200
```

## Known assets

`mppx` ships known assets for the following networks:

| Network      | Chain ID   | Known assets                                   |
| ------------ | ---------- | ---------------------------------------------- |
| Base         | `8453`     | `evm.assets.base.USDC`                         |
| Base Sepolia | `84532`    | `evm.assets.baseSepolia.USDC`                  |
| Celo         | `42220`    | `evm.assets.celo.USDC`, `evm.assets.celo.USDT` |
| Celo Sepolia | `11142220` | `evm.assets.celoSepolia.USDC`                  |

Use known assets when possible so `mppx` can infer the chain ID, token decimals, and authorization metadata:

```ts twoslash
import { evm } from 'mppx/server'

const method = evm.charge({
  currency: evm.assets.baseSepolia.USDC, // [!code hl]
  recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  x402: {
    facilitator: 'https://x402.org/facilitator',
  },
})
```

Use a custom asset when you provide the EIP-3009 authorization metadata:

```ts twoslash
import { evm } from 'mppx/server'

const method = evm.charge({
  authorization: {
    name: 'USD Coin',
    version: '2',
  },
  chainId: 84532,
  currency: '0x1234567890abcdef1234567890abcdef12345678',
  decimals: 6,
  recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  x402: {
    facilitator: 'https://x402.org/facilitator',
  },
})
```

## x402 compatibility

When `x402.facilitator` is configured, the server returns MPP and x402 Challenges and accepts both MPP and x402 Credentials inline for `GET`, body-bearing, and route-scoped endpoints. The default `routeBinding: 'resource'` accepts standard x402 Credentials by comparing the echoed resource URL and payment requirements. It also verifies any body digest against the request.

Set `routeBinding: 'required'` when every x402 Credential for a scoped route must include the `mppx` extension and route-bound nonce. This cryptographically binds MPP scope, opaque values, and metadata, but excludes standard clients that don't implement the extension from scoped routes.

On the client, `evm.charge` validates x402 offers before signing. Each offer must include resource information and EIP-3009 token name and version metadata, then pass the configured network, currency, and amount policies. The client skips unsupported or rejected offers and selects a later compatible offer when available.

See [running x402 inline with mppx](/guides/use-mpp-with-x402#run-x402-inline-with-mppx) for the full guide.

## Related resources

[EVM](/payment-methods/evm) — Stablecoin payments on EVM chains with inline x402 exact compatibility
