buy

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.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "buy" with this command: npx skills add must-be-ash/x402-skills/must-be-ash-x402-skills-buy

x402 Buy Skill

Enable AI agents to autonomously pay for HTTP resources using the x402 payment protocol.

Overview

x402 is an open payment standard that enables programmatic payments over HTTP. When an agent requests a paid resource, the server responds with HTTP 402 (Payment Required) containing payment details. The agent signs a payment authorization and retries the request.

CRITICAL: Pre-Flight Check (Do This First!)

ALWAYS check the endpoint's x402 version BEFORE writing any payment code.

curl -i "https://example.com/api/paid-endpoint"

Look at the 402 response to determine which version and packages to use:

How to Identify Version

Check Thisv1 (Legacy)v2 (Current)
x402Version field12
Network format"base", "base-sepolia""eip155:8453", "eip155:84532" (CAIP-2)
Requirements locationBody onlyPAYMENT-REQUIRED header
Payment header to sendX-PAYMENTPAYMENT-SIGNATURE
Response headerX-PAYMENT-RESPONSEPAYMENT-RESPONSE

Example v1 response:

{"x402Version":1,"accepts":[{"network":"base","maxAmountRequired":"2000",...}]}

Example v2 response:

PAYMENT-REQUIRED: <base64-encoded>
{"x402Version":2,"accepts":[{"network":"eip155:8453","maxAmountRequired":"2000",...}]}

Quick Start

1. Setup Wallet

Non-interactive CLI commands (for AI agents):

# 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

This creates a .env file with WALLET_ADDRESS and WALLET_PRIVATE_KEY.

2. Install Packages (Based on Version)

For v1 endpoints:

npm install x402-fetch viem

For v2 endpoints:

npm install @x402/fetch @x402/evm viem
# Optional for Solana: npm install @x402/svm @solana/kit @scure/base

3. Make Paid Requests

For v1 Endpoints (Legacy)

import { 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);
}

For v2 Endpoints (Current)

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");

Package Reference

Purposev1 (Legacy)v2 (Current)
Fetch wrapperx402-fetch@x402/fetch
Axios wrapperx402-axios@x402/axios
Core typesx402@x402/core
EVM supportBuilt into x402-fetch@x402/evm
Solana supportBuilt into x402-fetch@x402/svm

Network Identifiers

Networkv1 IDv2 CAIP-2 IDEnvironment
Base Mainnetbaseeip155:8453Production
Base Sepoliabase-sepoliaeip155:84532Testnet
Avalanche C-Chainavalancheeip155:43114Production
Avalanche Fujiavalanche-fujieip155:43113Testnet
Solana Mainnetsolanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpProduction
Solana Devnetsolana-devnetsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1Testnet

USDC Token Addresses

NetworkUSDC Address
Base Mainnet0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Base Sepolia0x036CbD53842c5426634e7929541eC2318f3dCF7e
Avalanche0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E
Solana MainnetEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

Complete Working Examples

Example 1: Calling a v1 Endpoint

// 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);

Example 2: Calling a v2 Endpoint

// 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);

Service Discovery (Bazaar)

Find x402-enabled services without knowing URLs in advance.

# 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}'

Programmatic Discovery

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
);

Payment Amounts

Amount (atomic)USDC Value
1000$0.001 (0.1 cents)
2000$0.002
10000$0.01 (1 cent)
100000$0.10 (10 cents)
1000000$1.00

Extracting Endpoint Requirements (Method, Body, Schema)

Many x402 endpoints include detailed input/output schemas in their 402 response. This tells you:

  • What HTTP method to use (GET, POST, etc.)
  • What body format (JSON, form-data)
  • Required and optional fields

Step 1: Get the 402 Response

# 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"

Step 2: Decode and Inspect the Payment Header

For v2 endpoints, decode the PAYMENT-REQUIRED header:

# Extract and decode the header (save full header value to a file or variable)
echo "<base64-payment-required-value>" | base64 -d | jq '.'

Step 3: Find the Input Schema

Look for extensions.bazaar.schema.properties.input in the decoded response:

{
  "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
              }
            }
          }
        }
      }
    }
  }
}

Step 4: Build Your Request

Based on the schema above:

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
  })
});

Quick Schema Extraction (One-liner)

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"

For v2 with header:

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}'

Common Patterns

If you see...Then use...
"method": "GET"fetch(url)
"method": "POST" + "bodyType": "json"fetch(url, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({...}) })
"method": "POST" + "bodyType": "form-data"fetch(url, { method: "POST", body: formData })
No extensions.bazaarTry GET first, then POST if 405

Setup Checklist

  1. Create wallet - Run echo "1" | npx add-wallet evm (non-interactive)
  2. Note the address - Check .env for WALLET_ADDRESS
  3. Fund wallet - Send USDC on Base mainnet (or npx add-wallet topup testnet)
  4. Check endpoint - curl -i <url> to see:
    • x402 version (v1 or v2)
    • Price (amount field)
    • Network (mainnet or testnet)
    • If 405, try curl -i -X POST <url>
  5. Extract schema - Decode PAYMENT-REQUIRED header to find method, body format, required fields
  6. Install correct packages - v1: x402-fetch, v2: @x402/fetch @x402/evm
  7. Use correct code pattern - v1: createSigner(), v2: registerExactEvmScheme()
  8. Build request - Use method/body from schema, SDK handles 402 → payment → retry

Troubleshooting

HTTP 405 Method Not Allowed

The endpoint requires a different HTTP method. Try POST instead of GET:

curl -i -X POST "https://example.com/api/endpoint" -H "Content-Type: application/json"

"EIP-712 domain parameters required" Error

You're using v2 packages (@x402/fetch) on a v1 endpoint. Check the 402 response - if x402Version: 1, use x402-fetch instead.

"No scheme registered" Error

The network in the 402 response isn't registered. For v2, make sure you called registerExactEvmScheme(client, { signer }).

Payment succeeds but response is empty or error

You might be missing required body fields. Decode the PAYMENT-REQUIRED header and check extensions.bazaar.schema for required fields.

Payment not going through

  1. Check wallet has sufficient USDC balance on the correct network
  2. Verify you're using the right network (mainnet vs testnet)
  3. Check the network field in the 402 response matches your setup

Protocol References

For detailed protocol schemas, see:

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

sell

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

clinic-visit-prep

帮助患者整理就诊前问题、既往记录、检查清单与时间线,不提供诊断。;use for healthcare, intake, prep workflows;do not use for 给诊断结论, 替代医生意见.

Archived SourceRecently Updated
Automation

changelog-curator

从变更记录、提交摘要或发布说明中整理对外 changelog,并区分用户价值与内部改动。;use for changelog, release-notes, docs workflows;do not use for 捏造未发布功能, 替代正式合规审批.

Archived SourceRecently Updated
Automation

klaviyo

Klaviyo API integration with managed OAuth. Access profiles, lists, segments, campaigns, flows, events, metrics, templates, catalogs, and webhooks. Use this skill when users want to manage email marketing, customer data, or integrate with Klaviyo workflows. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).

Archived SourceRecently Updated