@three-ws/x402-fetch

@three-ws/x402-fetch

Drop-in fetch wrapper that automatically pays x402 payment challenges with USDC on Base

npm install @three-ws/x402-fetch
View on GitHubStar the repo

@three-ws/x402-fetch

A drop-in fetch that silently answers x402 payment challenges. Wrap a wallet once, then call any paid three.ws (or CDP-x402 / agentic.market) endpoint as if it were free.

npm install @three-ws/x402-fetch

#Quick start

import { withX402 } from '@three-ws/x402-fetch';

// Browser: pass the injected wallet provider.
const pay = withX402(window.ethereum, { maxPaymentUsd: 0.1 });

const res = await pay('https://three.ws/api/mcp', {
	method: 'POST',
	headers: { 'content-type': 'application/json' },
	body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list' }),
});

const data = await res.json(); // paid + unlocked, transparently

On a 402 Payment Required, the wrapper parses the challenge, selects the USDC-on-Base requirement, signs the authorization, and retries with the X-PAYMENT header — all before your await resolves. Non-402 responses pass through untouched.

#Wallet forms

Browser (MetaMask / any EIP-1193 provider):

withX402(window.ethereum);

Node.js (private key):

import { withX402 } from '@three-ws/x402-fetch';
import { privateKeyToWallet } from '@three-ws/x402-fetch/wallet';

const pay = withX402(privateKeyToWallet(process.env.WALLET_PRIVATE_KEY));

Pre-built signer (three.ws agent SDK / viem account):

withX402({ address, signTypedData });

#Options

withX402(wallet, {
	maxPaymentUsd: 1.0, // refuse to auto-pay more than this per request (default 0.10)
	onPayment: ({ amount, to, requestUrl }) => console.log(`paying $${amount} to ${to}`),
	timeout: 30000, // ms to wait for payment authorization (default 15000)
	network: 'eip155:8453', // prefer a specific CAIP-2 network from accepts[]
});

maxPaymentUsd is a hard guard: a challenge above the limit throws rather than paying, so a misconfigured or hostile server can never silently overcharge you.

#Compatibility alias

For parity with the upstream x402-fetch package, wrapFetchWithPayment is exported with the fetch-first signature:

import { wrapFetchWithPayment } from '@three-ws/x402-fetch';
const pay = wrapFetchWithPayment(fetch, wallet);

#Errors

Message Meaning
no supported network/asset was found in accepts[] The server only offered networks/assets this wrapper can't sign (it signs USDC on Base / EVM EIP-3009).
payment of $X exceeds maxPaymentUsd limit The challenge asked for more than your authorized ceiling.
user rejected payment The wallet user cancelled the signature.
payment submitted but server still returned 402 The retry was still gated — usually an amount/recipient mismatch.

#Examples

Runnable scripts live in examples/: a zero-spend 402 discovery probe and a real env-gated paid call against the live three.ws Market Data API.

#License

Apache-2.0. See LICENSE.