Loading...
Loading...
Pay for x402-protected API endpoints with USDC. Use when calling APIs that return HTTP 402 Payment Required, integrating payments into agents, handling x402 payment requirements, building autonomous agents that pay for API access, or discovering paid services via Bazaar. Supports EVM (Base, Ethereum, Avalanche) and Solana networks.
npx skill4agent add must-be-ash/x402-skills buycurl -i "https://example.com/api/paid-endpoint"| Check This | v1 (Legacy) | v2 (Current) |
|---|---|---|
| | |
| Network format | | |
| Requirements location | Body only | |
| Payment header to send | | |
| Response header | | |
{"x402Version":1,"accepts":[{"network":"base","maxAmountRequired":"2000",...}]}PAYMENT-REQUIRED: <base64-encoded>
{"x402Version":2,"accepts":[{"network":"eip155:8453","maxAmountRequired":"2000",...}]}# EVM wallet (Base, Ethereum, Avalanche) - pipes "1" to select EOA
echo "1" | npx add-wallet evm
# Solana wallet
npx add-wallet sol
# Top up with testnet USDC
npx add-wallet topup testnet.envWALLET_ADDRESSWALLET_PRIVATE_KEYnpm install x402-fetch viemnpm install @x402/fetch @x402/evm viem
# Optional for Solana: npm install @x402/svm @solana/kit @scure/baseimport { wrapFetchWithPayment, createSigner, decodeXPaymentResponse } from "x402-fetch";
const privateKey = process.env.WALLET_PRIVATE_KEY as `0x${string}`;
// Use network string from 402 response: "base", "base-sepolia", "solana", etc.
const signer = await createSigner("base", privateKey);
const fetchWithPayment = wrapFetchWithPayment(fetch, signer);
const response = await fetchWithPayment("https://api.example.com/paid", { method: "GET" });
const data = await response.json();
// Check payment receipt
const paymentResponse = response.headers.get("x-payment-response");
if (paymentResponse) {
const receipt = decodeXPaymentResponse(paymentResponse);
console.log("Payment settled:", receipt);
}import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
const signer = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
const client = new x402Client();
registerExactEvmScheme(client, { signer });
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
const response = await fetchWithPayment("https://api.example.com/paid", { method: "GET" });
// Check payment receipt
const paymentResponse = response.headers.get("PAYMENT-RESPONSE");| Purpose | v1 (Legacy) | v2 (Current) |
|---|---|---|
| Fetch wrapper | | |
| Axios wrapper | | |
| Core types | | |
| EVM support | Built into x402-fetch | |
| Solana support | Built into x402-fetch | |
| Network | v1 ID | v2 CAIP-2 ID | Environment |
|---|---|---|---|
| Base Mainnet | | | Production |
| Base Sepolia | | | Testnet |
| Avalanche C-Chain | | | Production |
| Avalanche Fuji | | | Testnet |
| Solana Mainnet | | | Production |
| Solana Devnet | | | Testnet |
| Network | USDC Address |
|---|---|
| Base Mainnet | |
| Base Sepolia | |
| Avalanche | |
| Solana Mainnet | |
// call-v1-endpoint.ts
import { wrapFetchWithPayment, createSigner, decodeXPaymentResponse } from "x402-fetch";
const privateKey = "0x..." as `0x${string}`; // Your private key
const walletAddress = "0x..."; // Your wallet address
async function main() {
// Step 1: Check what version the endpoint uses
const checkResponse = await fetch("https://example.com/api/data");
if (checkResponse.status === 402) {
const body = await checkResponse.json();
console.log("x402 Version:", body.x402Version);
console.log("Network:", body.accepts[0].network);
console.log("Price:", body.accepts[0].maxAmountRequired, "atomic units");
}
// Step 2: Create signer with v1 network string
const signer = await createSigner("base", privateKey); // Use network from response
// Step 3: Wrap fetch and make paid request
const fetchWithPayment = wrapFetchWithPayment(fetch, signer);
const response = await fetchWithPayment("https://example.com/api/data");
const data = await response.json();
console.log("Response:", data);
// Step 4: Check payment receipt
const receipt = response.headers.get("x-payment-response");
if (receipt) {
console.log("Payment settled:", decodeXPaymentResponse(receipt));
}
}
main().catch(console.error);// call-v2-endpoint.ts
import { wrapFetchWithPayment, x402Client, x402HTTPClient } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
const privateKey = "0x..." as `0x${string}`;
async function main() {
// Step 1: Check what version the endpoint uses
const checkResponse = await fetch("https://example.com/api/data");
if (checkResponse.status === 402) {
const hasV2Header = checkResponse.headers.get("PAYMENT-REQUIRED");
console.log("Is v2:", !!hasV2Header);
}
// Step 2: Setup v2 client
const signer = privateKeyToAccount(privateKey);
const client = new x402Client();
registerExactEvmScheme(client, { signer });
// Step 3: Make paid request
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
const response = await fetchWithPayment("https://example.com/api/data");
const data = await response.json();
console.log("Response:", data);
// Step 4: Check payment receipt
const receipt = response.headers.get("PAYMENT-RESPONSE");
if (receipt) {
console.log("Payment settled");
}
}
main().catch(console.error);# Quick discovery via curl
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?type=http&limit=50" | jq '.items[] | {url: .resource, price: .accepts[0].maxAmountRequired, version: .x402Version}'import { HTTPFacilitatorClient } from "@x402/core/http";
import { withBazaar } from "@x402/extensions";
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://api.cdp.coinbase.com/platform/v2/x402"
});
const client = withBazaar(facilitatorClient);
const response = await client.extensions.discovery.listResources({ type: "http" });
// Filter by price (under $0.01 = 10000 atomic units)
const affordable = response.items.filter(item =>
Number(item.accepts[0].maxAmountRequired) < 10000
);| Amount (atomic) | USDC Value |
|---|---|
| $0.001 (0.1 cents) |
| $0.002 |
| $0.01 (1 cent) |
| $0.10 (10 cents) |
| $1.00 |
# Try GET first
curl -i "https://example.com/api/endpoint"
# If you get 405 Method Not Allowed, try POST
curl -i -X POST "https://example.com/api/endpoint" -H "Content-Type: application/json"PAYMENT-REQUIRED# Extract and decode the header (save full header value to a file or variable)
echo "<base64-payment-required-value>" | base64 -d | jq '.'extensions.bazaar.schema.properties.input{
"x402Version": 2,
"accepts": [...],
"extensions": {
"bazaar": {
"info": {
"input": {
"type": "http",
"method": "POST", // <-- HTTP method
"bodyType": "json", // <-- Body format
"body": {}
}
},
"schema": {
"properties": {
"input": {
"properties": {
"body": {
"properties": {
"urls": { "type": "array", "items": { "type": "string" } }, // Required field
"text": { "type": "boolean" } // Optional field
},
"required": ["urls"] // <-- Required fields listed here
}
}
}
}
}
}
}
}const response = await fetchWithPayment("https://example.com/api/endpoint", {
method: "POST", // From info.input.method
headers: { "Content-Type": "application/json" }, // From info.input.bodyType
body: JSON.stringify({
urls: ["https://example.com"], // Required field
text: true // Optional field
})
});curl -s -X POST "https://example.com/api/endpoint" -H "Content-Type: application/json" | \
jq -r 'if .accepts then . else empty end' 2>/dev/null || \
echo "Check PAYMENT-REQUIRED header for v2"curl -si -X POST "https://example.com/api/endpoint" -H "Content-Type: application/json" | \
grep -i "payment-required:" | cut -d' ' -f2 | base64 -d | \
jq '{method: .extensions.bazaar.info.input.method, bodyType: .extensions.bazaar.info.input.bodyType, required: .extensions.bazaar.schema.properties.input.properties.body.required}'| If you see... | Then use... |
|---|---|
| |
| |
| |
No | Try GET first, then POST if 405 |
echo "1" | npx add-wallet evm.envWALLET_ADDRESSnpx add-wallet topup testnetcurl -i <url>curl -i -X POST <url>PAYMENT-REQUIREDx402-fetch@x402/fetch @x402/evmcreateSigner()registerExactEvmScheme()curl -i -X POST "https://example.com/api/endpoint" -H "Content-Type: application/json"@x402/fetchx402Version: 1x402-fetchregisterExactEvmScheme(client, { signer })PAYMENT-REQUIREDextensions.bazaar.schemanetwork