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.
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');
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>;
| Parameter | Type | Description |
|---|---|---|
wallet | X402Wallet | A wallet/signer accepted by x402-fetch (e.g. a viem WalletClient for EVM/Base). Typed permissively as any. |
opts.maxValue | bigint | Optional 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 tonew 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');
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 cached402or a cached paid response served to the wrong caller is incorrect. - Don't strip headers. x402 rides on the
X-PAYMENTrequest header and the402payment 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
- Installation — the
fetchconfiguration option. - Error handling — how a
402surfaces without x402. - TypeScript client reference — the typed resource methods.