Skip to main content

x402 Payments

x402 is an HTTP-native, pay-per-call settlement standard built on the 402 Payment Required status code. When a server responds with 402, an x402-capable client negotiates and submits a stablecoin payment, then retries the request — transparently. This makes it ideal for bots and autonomous agents that consume metered API endpoints without a human in the loop.

The MAGMA SDK ships an optional helper, withX402Payments, that wraps the global fetch with x402 payment handling and injects it into MagmaClient. The rest of the SDK is unchanged: gated calls that return 402 are paid for and retried automatically; everything else behaves exactly as before.

Optional dependency

x402 support is opt-in. The helper dynamically imports x402-fetch, so the SDK works without that package when you do not use x402. Install it only if you need payments:

npm install x402-fetch

How it works

withX402Payments(wallet, opts?) returns a FetchLike — a payment-wrapped fetch. You pass that fetch to the client via the fetch option. Because the SDK routes every request through the injected fetch, payment handling applies to all calls without any per-method changes.

import { MagmaClient, withX402Payments } from '@magma-protocol/sdk';

const fetchPaid = await withX402Payments(wallet);
const magma = new MagmaClient({ fetch: fetchPaid });

// A 402 from a gated route is paid and retried transparently
const data = await magma.get('/v1/agent/markets');
Without x402

If you do not inject a payment-wrapped fetch, a 402 response simply surfaces as a MagmaError with status: 402 — nothing is paid.

API

function withX402Payments(
wallet: X402Wallet,
opts?: { maxValue?: bigint },
): Promise<FetchLike>;
ParameterTypeDescription
walletX402WalletA wallet/signer accepted by x402-fetch (e.g. a viem WalletClient for EVM/Base). Typed permissively as any.
opts.maxValuebigintOptional per-request spend cap (in the payment token's base units). When set, it is forwarded to the underlying wrapper as the maximum payment amount.
  • Returns: Promise<FetchLike> — a fetch you pass to new MagmaClient({ fetch }).

The helper is async because it dynamically imports x402-fetch and resolves its wrapFetchWithPayment export. It throws if the package is not installed (x402-fetch not installed -- run: npm i x402-fetch) or if the expected export is missing.

The wallet interface

The X402Wallet type is intentionally permissive (any) so the SDK does not bind to a specific wallet library — the wallet is forwarded directly to x402-fetch. In practice this is the same signer x402-fetch expects, such as a viem WalletClient configured for an EVM chain (e.g. Base), which signs the payment authorization. Refer to the x402-fetch documentation for the exact signer requirements and supported chains.

End-to-end example

import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';
import { MagmaClient, withX402Payments } from '@magma-protocol/sdk';

// 1 — Build a signer that x402-fetch accepts (viem WalletClient on Base)
const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY as `0x${string}`);
const wallet = createWalletClient({ account, chain: base, transport: http() });

// 2 — Wrap fetch with x402 payment handling (cap each call at maxValue)
const fetchPaid = await withX402Payments(wallet, { maxValue: 1_000_000n });

// 3 — Inject it into the client
const magma = new MagmaClient({ fetch: fetchPaid });

// 4 — Call a pay-per-call endpoint. On a 402, the payment is made and the
// request is retried automatically; the resolved JSON is returned.
const markets = await magma.get('/v1/agent/markets');
Combine with auth

The fetch option is independent of authToken / walletAddress. You can inject a payment-wrapped fetch and still set a Privy JWT — the bearer token and X-Wallet-Address headers are added on top of the payment-aware transport.

Which endpoints are pay-per-call

x402 applies to agent/premium data endpoints gated behind 402 Payment Required — for example the /v1/agent family (such as /v1/agent/markets). The standard public read endpoints documented in the client reference (narrative feed, conviction, DeFi APYs, leaderboards, epoch state) are not metered and require no payment.

Because the SDK reacts to the server's 402 response rather than a hard-coded list, any endpoint the backend gates behind x402 is handled automatically once a payment-wrapped fetch is injected. See the API Reference for the authoritative, per-endpoint pricing and gating.

Infrastructure & deployment

x402 is handled entirely by the backend and this SDK — there is nothing to configure at the CDN/edge (no Cloudflare Workers, scripts, or snippets). The API returns 402 with payment requirements; withX402Payments pays and retries.

If your API is fronted by a proxy/CDN (e.g. Cloudflare in proxied mode), x402 keeps working as long as the proxy does not get in the way:

  • Don't block agents. x402 clients are bots/agents, not browsers — disable Bot Fight Mode (or exclude the gated /v1/agent/* paths) so they aren't challenged.
  • Don't cache the API. Bypass cache for /v1/*; a cached 402 or a cached paid response served to the wrong caller is incorrect.
  • Don't strip headers. x402 rides on the X-PAYMENT request header and the 402 payment metadata in the response — leave request/response headers intact.

If the API DNS record is DNS-only (not proxied), none of the above applies.

Settlement — the on-chain stablecoin transfer — happens via the x402 facilitator the backend talks to (EVM/Base side), not in the SDK and not at the edge.

See also