Payments

x402 Flow

Accept payments from AI agents using the x402 protocol

The x402 protocol enables AI agents to autonomously pay for API access. When an agent hits a paid endpoint, payment is negotiated and settled within a single HTTP request cycle.

How x402 Works

  1. Agent requests a resource - Makes a standard HTTP request
  2. Server responds with 402 - Returns payment requirements
  3. Agent creates payment - Signs a transaction meeting requirements
  4. Agent retries with payment - Includes X-Payment header
  5. Server verifies and settles - Validates payment and returns resource
Agent                                Server
  |                                    |
  |--- GET /api/data ----------------->|
  |                                    |
  |<-- 402 Payment Required -----------|
  |    { accepts: [payment_req] }      |
  |                                    |
  |--- GET /api/data ----------------->|
  |    X-Payment: <signed_payload>     |
  |                                    |
  |<-- 200 OK -------------------------|
  |    { data: ... }                   |

Agent Implementation

Interactive
import { MoneyMQ } from '@moneymq/sdk';import { wrapFetchWithPayment } from 'x402-fetch';const moneymq = new MoneyMQ({	endpoint: 'http://localhost:8488',});// Fetch catalogconst catalog = await moneymq.catalog.list();const product = catalog.data[0];// Get signer for sandbox account by labelconst payer = await moneymq.x402.getSigner({ tag: 'alice' });// Get x402 config from serverconst config = await moneymq.x402.getConfig();// Create payment-enabled fetch (max 10 USDC)const fetchWithPayment = wrapFetchWithPayment(	fetch,	payer,	BigInt(10_000_000), // 10 USDC	undefined,	config,);// Access a paid API - payment is handled automaticallyconst response = await fetchWithPayment(	product.accessUrl,	{ method: 'GET' },);const data = await response.json();console.log(data);

Payment-Enabled Fetch

The wrapFetchWithPayment function wraps the standard fetch API to automatically handle 402 responses:

import { wrapFetchWithPayment } from 'x402-fetch';

const fetchWithPayment = wrapFetchWithPayment(
  fetch,
  signer,
  maxAmount,    // Maximum amount willing to pay
  undefined,    // Optional: preferred network
  config,       // x402 configuration
);

// Use like regular fetch
const response = await fetchWithPayment('https://api.example.com/data');

Creating a Signer

From Sandbox Account

// Get signer for a sandbox test account
const payer = await moneymq.x402.getSigner({ tag: 'alice' });

From Private Key

import { createSigner } from 'x402-fetch';

const signer = await createSigner('solana', privateKeyHex, {
  svmConfig: rpcUrl,
});

Configuration

Get the x402 configuration from your MoneyMQ server:

const config = await moneymq.x402.getConfig();

// Config includes:
// - Facilitator URL
// - Supported networks
// - Token addresses

Payment Requirements

When a server responds with 402, it includes payment requirements:

{
  "accepts": [
    {
      "network": "solana",
      "currency": "USDC",
      "maxAmountRequired": "1000000",
      "payTo": "recipient_address",
      "extra": {
        "product": "prod_xxxxx"
      }
    }
  ]
}

Setting Maximum Payment

Control how much your agent is willing to pay:

// Pay up to 1 USDC
const fetchWithPayment = wrapFetchWithPayment(
  fetch,
  signer,
  BigInt(1_000_000), // 1 USDC (6 decimals)
);

// Pay up to 0.10 USDC
const fetchWithPayment = wrapFetchWithPayment(
  fetch,
  signer,
  BigInt(100_000), // 0.10 USDC
);

Error Handling

try {
  const response = await fetchWithPayment(url);
  const data = await response.json();
} catch (error) {
  if (error.code === 'INSUFFICIENT_FUNDS') {
    console.error('Agent wallet needs more funds');
  } else if (error.code === 'PAYMENT_REJECTED') {
    console.error('Server rejected the payment');
  } else if (error.code === 'MAX_AMOUNT_EXCEEDED') {
    console.error('Price exceeds maximum willing to pay');
  }
}

Next Steps

On this page