Standalone TypeScript client for paying x402 v2 APIs from a smart contract vault. No API key. No account. EIP-3009 signed USDC on Base.
npm install @gitbank/x402import { payX402 } from "@gitbank/x402";
const result = await payX402("https://api.example.com/data", process.env.PRIVATE_KEY, {
method: "POST",
body: { query: "hello" },
});
console.log(result.status, result.body);import {
fetchX402Requirements,
signEip3009Authorization,
sendX402Request,
atomicToHuman,
} from "@gitbank/x402";
// 1. Probe the endpoint
const req = await fetchX402Requirements("https://api.example.com/data");
if (!req) throw new Error("No payment required");
console.log("Cost:", atomicToHuman(req.maxAmountRequired), "USDC");
// 2. Sign EIP-3009 authorization
const payload = await signEip3009Authorization(
process.env.PRIVATE_KEY,
req,
BigInt(req.maxAmountRequired),
8453, // Base Mainnet
);
// 3. Send paid request
const result = await sendX402Request("https://api.example.com/data", payload, "POST", {
query: "hello",
});
console.log(result.status); // 200| v1 | v2 | |
|---|---|---|
| 402 response header | X-PAYMENT-REQUIRED | PAYMENT-REQUIRED |
| Payment request header | X-PAYMENT | PAYMENT-SIGNATURE |
resource field location |
inside each accepts[] item |
top-level of the 402 body |
accepted field |
not present | required at payload top level |
Key v2 gotcha: resource is at the top level of the decoded PAYMENT-REQUIRED body,
not inside each item in accepts[]. Parsing it from inside accepts[] silently gives undefined.
- Node.js 20+
- Payer address must hold sufficient USDC on Base Mainnet (chainId 8453)
- USDC:
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
- USDC:
- Or Base Sepolia for testing (chainId 84532)
- USDC:
0x036CbD53842c5426634e7929541eC2318f3dCF7e
- USDC:
See examples/ for a working POST request example.
See CONTRIBUTING.md.
Apache-2.0. See LICENSE.