x402 Facilitator

Octo x402 Protocol Documentation

Overview

Octo x402 is a decentralized payment protocol that enables instant micropayments for digital content and API access. It supports both EVM (Ethereum Virtual Machine) and SVM (Solana Virtual Machine) networks, allowing merchants to accept USDC payments seamlessly across multiple blockchains.

Protocol Version: x402 v1 Facilitator URL: https://facilitator.octox402.xyz Status: Production Ready (12 networks) | Testing Phase (BSC, Ethereum, and more)

Architecture

The x402 protocol consists of three main components:

1. Facilitator

  • URL: https://facilitator.octox402.xyz

  • Verifies payment signatures and requirements

  • Submits transactions to blockchain

  • EVM Networks: Facilitator pays gas fees (~$0.001-0.01)

  • SVM Networks: Facilitator only verifies; consumer pays transaction fees (~$0.000005)

2. Merchant

  • Exposes content behind payment requirements

  • Returns HTTP 402 with payment requirements when payment is needed

  • Verifies payments via facilitator

  • Serves content after successful payment settlement

3. Consumer

  • Signs payment authorizations using wallet

  • Sends payments via X-PAYMENT header

  • Receives content after payment verification


Supported Networks

⚡ Production Ready (12 Networks)

EVM Networks (10 networks)

Network
Network ID
Chain ID
Type
Status

Base

base

8453

Mainnet

✅ Live

Base Sepolia

base-sepolia

84532

Testnet

✅ Live

Abstract

abstract

-

Mainnet

✅ Live

Abstract Testnet

abstract-testnet

-

Testnet

✅ Live

Polygon

polygon

137

Mainnet

✅ Live

Polygon Amoy

polygon-amoy

80002

Testnet

✅ Live

Avalanche C-Chain

avalanche

43114

Mainnet

✅ Live

Avalanche Fuji

avalanche-fuji

43113

Testnet

✅ Live

SEI

sei

-

Mainnet

✅ Live

SEI Testnet

sei-testnet

-

Testnet

✅ Live

IoTeX

iotex

4689

Mainnet

✅ Live

Peaq

peaq

-

Mainnet

✅ Live

SVM Networks (2 networks)

Network
Network ID
Type
Status

Solana

solana

Mainnet

✅ Live

Solana Devnet

solana-devnet

Testnet

✅ Live

🚧 Coming Soon (Testing Phase)

  • BSC (Binance Smart Chain) - Chain ID: 56

  • Ethereum Mainnet - Chain ID: 1

  • Optimism - Layer 2

  • Arbitrum - Layer 2

  • Additional EVM-compatible chains


Network Details

USDC Contract Addresses

EVM Networks

  • Base: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913

  • Polygon: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359

  • Avalanche: 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E

SVM Networks

  • Solana: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

Transaction Fees

Network
Average Fee
Who Pays
Settlement Time

Base

~$0.001

Facilitator

~2 seconds

Polygon

~$0.001

Facilitator

~2 seconds

Avalanche

~$0.01

Facilitator

~2 seconds

Solana

~$0.000005

Consumer

~400ms


Getting Started

Prerequisites

npm install axios ethers @solana/web3.js @solana/spl-token bs58 dotenv express

Environment Variables

Create a .env file:

# Consumer Configuration
CONSUMER_PRIVATE_KEY=your_evm_private_key_here      # For EVM networks
CONSUMER_PRIVATE_KEY_BS58=your_solana_key_here     # For Solana networks
MERCHANT_URL=https://your-merchant-url.com

# Merchant Configuration
MERCHANT_WALLET_ADDRESS=your_wallet_address         # Your receiving wallet
FACILITATOR_URL=https://facilitator.octox402.xyz

# Network Selection (choose one)
NETWORK=base                    # Options: base, polygon, avalanche, solana, etc.
CHAIN_ID=8453                  # For EVM networks only

# Optional: Custom RPC URLs
SOLANA_RPC=https://api.mainnet-beta.solana.com
BASE_RPC=https://mainnet.base.org
POLYGON_RPC=https://polygon-rpc.com

Quick Start

1. Check Supported Networks

curl https://facilitator.octox402.xyz/supported

2. Test Health

curl https://facilitator.octox402.xyz/health

3. Implement Consumer (See examples below)


EVM Implementation

Consumer (Base Mainnet)

import axios from 'axios';
import { ethers } from 'ethers';

const CONSUMER_PRIVATE_KEY = process.env.CONSUMER_PRIVATE_KEY;
const MERCHANT_URL = process.env.MERCHANT_URL;
const NETWORK = 'base';
const CHAIN_ID = 8453;

const wallet = new ethers.Wallet(CONSUMER_PRIVATE_KEY);

async function createPayment(requirements: any): Promise<string> {
  // EIP-712 domain for USDC
  const domain = {
    name: 'USD Coin',
    version: '2',
    chainId: CHAIN_ID,
    verifyingContract: requirements.asset,
  };

  // EIP-712 types for USDC transferWithAuthorization
  const types = {
    TransferWithAuthorization: [
      { name: 'from', type: 'address' },
      { name: 'to', type: 'address' },
      { name: 'value', type: 'uint256' },
      { name: 'validAfter', type: 'uint256' },
      { name: 'validBefore', type: 'uint256' },
      { name: 'nonce', type: 'bytes32' },
    ],
  };

  const validAfter = 0;
  const validBefore = Math.floor(Date.now() / 1000) + 3600;
  const nonce = ethers.hexlify(ethers.randomBytes(32));

  const value = {
    from: wallet.address,
    to: requirements.payTo,
    value: requirements.maxAmountRequired,
    validAfter,
    validBefore,
    nonce,
  };

  const signature = await wallet.signTypedData(domain, types, value);

  const paymentPayload = {
    x402Version: 1,
    scheme: 'exact',
    network: NETWORK,
    payload: {
      authorization: {
        from: wallet.address,
        to: requirements.payTo,
        value: requirements.maxAmountRequired,
        validAfter: validAfter.toString(),
        validBefore: validBefore.toString(),
        nonce: nonce,
      },
      signature: signature  // String, not {v, r, s} object
    }
  };

  return Buffer.from(JSON.stringify(paymentPayload)).toString('base64');
}

async function fetchWithPayment(url: string) {
  let response = await axios.get(url, {
    validateStatus: () => true
  });

  if (response.status === 402) {
    const requirements = response.data;
    const paymentHeader = await createPayment(requirements);
    
    response = await axios.get(url, {
      headers: { 'X-PAYMENT': paymentHeader },
      validateStatus: () => true
    });
  }

  return response.data;
}

Merchant (Base Mainnet)

import express from 'express';
import axios from 'axios';

const app = express();
app.use(express.json());

const MERCHANT_WALLET = process.env.MERCHANT_WALLET_ADDRESS;
const MERCHANT_URL = process.env.MERCHANT_URL;
const FACILITATOR_URL = 'https://facilitator.octox402.xyz';
const NETWORK = 'base';
const USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';

async function checkPayment(req: any, res: any, next: any) {
  const paymentHeader = req.headers['x-payment'];
  
  const paymentRequirements = {
    scheme: 'exact',
    network: NETWORK,
    maxAmountRequired: '10000', // $0.01 USDC (6 decimals)
    payTo: MERCHANT_WALLET,
    asset: USDC_ADDRESS,
    resource: `${MERCHANT_URL}${req.path}`,
    description: 'Premium content access',
    mimeType: 'application/json',
    maxTimeoutSeconds: 300
  };
  
  if (!paymentHeader) {
    return res.status(402).json(paymentRequirements);
  }
  
  try {
    const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');
    const paymentPayload = JSON.parse(decoded);
    
    // Step 1: Verify
    const verifyResponse = await axios.post(
      `${FACILITATOR_URL}/verify`,
      { paymentPayload, paymentRequirements },
      { headers: { 'Content-Type': 'application/json' } }
    );
    
    const verifyData = verifyResponse.data.success 
      ? verifyResponse.data.data 
      : verifyResponse.data;
    
    if (!verifyData.isValid) {
      return res.status(402).json({
        error: 'Payment verification failed',
        reason: verifyData.invalidReason
      });
    }
    
    // Step 2: Settle
    const settleResponse = await axios.post(
      `${FACILITATOR_URL}/settle`,
      { paymentPayload, paymentRequirements },
      { headers: { 'Content-Type': 'application/json' } }
    );
    
    const settleData = settleResponse.data.success
      ? settleResponse.data.data
      : settleResponse.data;
    
    if (!settleData.success) {
      return res.status(402).json({
        error: 'Payment settlement failed'
      });
    }
    
    next();
    
  } catch (error: any) {
    return res.status(500).json({
      error: 'Payment processing failed',
      message: error.message
    });
  }
}

// Protected endpoint
app.get('/premium-content', checkPayment, (req, res) => {
  res.json({ data: 'Your premium content here' });
});

app.listen(3000);

SVM Implementation

Consumer (Solana Mainnet)

Important: On Solana, the consumer pays their own transaction fees (~$0.000005). The facilitator only verifies the payment.

import axios from 'axios';
import { 
  Keypair, 
  PublicKey,
  Connection,
  TransactionMessage,
  VersionedTransaction
} from '@solana/web3.js';
import { 
  getAssociatedTokenAddress,
  createTransferInstruction
} from '@solana/spl-token';
import bs58 from 'bs58';

const CONSUMER_PRIVATE_KEY_BS58 = process.env.CONSUMER_PRIVATE_KEY_BS58;
const MERCHANT_URL = process.env.MERCHANT_URL;
const NETWORK = 'solana';
const RPC_URL = process.env.SOLANA_RPC || 'https://api.mainnet-beta.solana.com';

const keypair = Keypair.fromSecretKey(bs58.decode(CONSUMER_PRIVATE_KEY_BS58));
const connection = new Connection(RPC_URL, 'confirmed');

async function createPayment(requirements: any): Promise<string> {
  const fromPubkey = keypair.publicKey;
  const toPubkey = new PublicKey(requirements.payTo);
  const mintPubkey = new PublicKey(requirements.asset);
  const amount = BigInt(requirements.maxAmountRequired);
  
  // Get associated token accounts
  const fromTokenAccount = await getAssociatedTokenAddress(mintPubkey, fromPubkey);
  const toTokenAccount = await getAssociatedTokenAddress(mintPubkey, toPubkey);
  
  // Create transfer instruction
  const transferInstruction = createTransferInstruction(
    fromTokenAccount,
    toTokenAccount,
    fromPubkey,
    amount
  );
  
  // Get recent blockhash
  const { blockhash } = await connection.getLatestBlockhash('finalized');
  
  // Create v0 versioned transaction
  const messageV0 = new TransactionMessage({
    payerKey: fromPubkey,  // Consumer pays fees
    recentBlockhash: blockhash,
    instructions: [transferInstruction],
  }).compileToV0Message();
  
  const transaction = new VersionedTransaction(messageV0);
  transaction.sign([keypair]);
  
  // Serialize transaction
  const serializedTx = transaction.serialize();
  const base64Tx = Buffer.from(serializedTx).toString('base64');
  
  const paymentPayload = {
    x402Version: 1,
    scheme: 'exact',
    network: NETWORK,
    payload: {
      transaction: base64Tx
    }
  };
  
  return Buffer.from(JSON.stringify(paymentPayload)).toString('base64');
}

async function fetchWithPayment(url: string) {
  let response = await axios.get(url, {
    validateStatus: () => true
  });
  
  if (response.status === 402) {
    const requirements = response.data;
    const paymentHeader = await createPayment(requirements);
    
    response = await axios.get(url, {
      headers: { 'X-PAYMENT': paymentHeader },
      validateStatus: () => true
    });
  }
  
  return response.data;
}

Merchant (Solana Mainnet)

import express from 'express';
import axios from 'axios';

const app = express();
app.use(express.json());

const MERCHANT_WALLET = process.env.MERCHANT_WALLET_ADDRESS;
const MERCHANT_URL = process.env.MERCHANT_URL;
const FACILITATOR_URL = 'https://facilitator.octox402.xyz';
const NETWORK = 'solana';
const USDC_ADDRESS = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';

async function checkPayment(req: any, res: any, next: any) {
  const paymentHeader = req.headers['x-payment'];
  
  const paymentRequirements = {
    scheme: 'exact',
    network: NETWORK,
    maxAmountRequired: '10000', // $0.01 USDC (6 decimals)
    payTo: MERCHANT_WALLET,
    asset: USDC_ADDRESS,
    resource: `${MERCHANT_URL}${req.path}`,
    description: 'Premium content access',
    mimeType: 'application/json',
    maxTimeoutSeconds: 300
  };
  
  if (!paymentHeader) {
    return res.status(402).json(paymentRequirements);
  }
  
  try {
    const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');
    const paymentPayload = JSON.parse(decoded);
    
    // Step 1: Verify
    const verifyResponse = await axios.post(
      `${FACILITATOR_URL}/verify`,
      { paymentPayload, paymentRequirements },
      { headers: { 'Content-Type': 'application/json' } }
    );
    
    const verifyData = verifyResponse.data.success 
      ? verifyResponse.data.data 
      : verifyResponse.data;
    
    if (!verifyData.isValid) {
      return res.status(402).json({
        error: 'Payment verification failed',
        reason: verifyData.invalidReason
      });
    }
    
    // Step 2: Settle (Facilitator only verifies, does not pay fees)
    const settleResponse = await axios.post(
      `${FACILITATOR_URL}/settle`,
      { paymentPayload, paymentRequirements },
      { headers: { 'Content-Type': 'application/json' } }
    );
    
    const settleData = settleResponse.data.success
      ? settleResponse.data.data
      : settleResponse.data;
    
    if (!settleData.success) {
      return res.status(402).json({
        error: 'Payment settlement failed'
      });
    }
    
    next();
    
  } catch (error: any) {
    return res.status(500).json({
      error: 'Payment processing failed',
      message: error.message
    });
  }
}

// Protected endpoint
app.get('/premium-content', checkPayment, (req, res) => {
  res.json({ data: 'Your premium content here' });
});

app.listen(3000);

Payment Flow

1. Initial Request

Consumer → Merchant: GET /premium-content

2. Payment Required

Merchant → Consumer: HTTP 402 Payment Required
{
  "scheme": "exact",
  "network": "base",
  "maxAmountRequired": "10000",
  "payTo": "MERCHANT_WALLET",
  "asset": "USDC_ADDRESS",
  "resource": "https://merchant.com/premium-content",
  "description": "Premium content access",
  "mimeType": "application/json",
  "maxTimeoutSeconds": 300
}

3. Payment Creation

Consumer creates signed payment:
- EVM: EIP-712 signature for USDC transferWithAuthorization
- SVM: Signed versioned transaction (v0)

4. Payment Submission

Consumer → Merchant: GET /premium-content
Headers: { "X-PAYMENT": "base64EncodedPayment" }

5. Payment Verification

Merchant → Facilitator: POST /verify
{
  "paymentPayload": {...},
  "paymentRequirements": {...}
}

6. Payment Settlement

Merchant → Facilitator: POST /settle
{
  "paymentPayload": {...},
  "paymentRequirements": {...}
}

Facilitator → Blockchain: Submit transaction

7. Content Delivery

Merchant → Consumer: HTTP 200 OK
{ "data": "Your premium content" }

Facilitator API Reference

Base URL: https://facilitator.octox402.xyz

Endpoints Overview

Endpoint
Method
Description
Auth Required

/

GET

Service information

No

/health

GET

Health check

No

/supported

GET

List supported networks

No

/stats

GET

Facilitator statistics

No

/verify

GET

Verify endpoint info

No

/verify

POST

Verify payment signature

Optional

/settle

GET

Settle endpoint info

No

/settle

POST

Settle payment on blockchain

Optional


GET /supported

Returns all supported payment networks and schemes.

Response:

{
  "kinds": [
    {
      "x402Version": 1,
      "scheme": "exact",
      "network": "base",
      "extra": {
        "feePayer": "0x..."
      }
    },
    {
      "x402Version": 1,
      "scheme": "exact",
      "network": "solana",
      "extra": {
        "feePayer": "..."
      }
    }
  ],
  "facilitator": "Octo x402 Facilitator",
  "version": 1,
  "supportedChains": {
    "evm": [
      "Base",
      "Abstract",
      "Polygon",
      "Avalanche",
      "SEI",
      "IoTeX",
      "Peaq"
    ],
    "svm": [
      "Solana"
    ]
  },
  "requestId": "unique-request-id",
  "timestamp": "2025-11-04T12:00:00.000Z"
}

GET /stats

Returns facilitator statistics and performance metrics.

Response:

{
  "facilitator": "Octo x402 Facilitator",
  "version": "1.0.0",
  "x402Version": 1,
  "uptime": 86400,
  "uptimeFormatted": "1d 0h 0m 0s",
  "capabilities": {
    "evmEnabled": true,
    "svmEnabled": true,
    "apiKeyRequired": false
  },
  "memoryUsage": {
    "rss": "150MB",
    "heapUsed": "85MB",
    "heapTotal": "120MB",
    "external": "10MB"
  },
  "requestId": "unique-request-id",
  "timestamp": "2025-11-04T12:00:00.000Z"
}

POST /verify

Verifies payment signature and requirements without settling on blockchain.

Request Headers:

Content-Type: application/json
X-API-Key: your-api-key (optional)

Request Body:

{
  "x402Version": 1,
  "paymentPayload": {
    "x402Version": 1,
    "scheme": "exact",
    "network": "base",
    "payload": {
      "authorization": {
        "from": "consumer_wallet_address",
        "to": "merchant_wallet_address",
        "value": "10000",
        "validAfter": "0",
        "validBefore": "1730736000",
        "nonce": "0x..."
      },
      "signature": "0x..."
    }
  },
  "paymentRequirements": {
    "scheme": "exact",
    "network": "base",
    "maxAmountRequired": "10000",
    "payTo": "merchant_wallet_address",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "resource": "https://merchant.com/premium-content",
    "description": "Premium content access",
    "mimeType": "application/json",
    "maxTimeoutSeconds": 300
  }
}

Success Response (200):

{
  "success": true,
  "data": {
    "isValid": true
  },
  "requestId": "unique-request-id",
  "timestamp": "2025-11-04T12:00:00.000Z"
}

Failure Response (200):

{
  "success": true,
  "data": {
    "isValid": false,
    "invalidReason": "Insufficient amount: 5000, expected: 10000"
  },
  "requestId": "unique-request-id",
  "timestamp": "2025-11-04T12:00:00.000Z"
}

Error Response (400/500):

{
  "success": false,
  "error": "Error message",
  "requestId": "unique-request-id",
  "timestamp": "2025-11-04T12:00:00.000Z"
}

POST /settle

Verifies and settles payment on blockchain. For EVM networks, facilitator pays gas fees. For SVM networks, facilitator only submits the pre-signed transaction.

Request Headers:

Content-Type: application/json
X-API-Key: your-api-key (optional)

Request Body: Same as /verify

Success Response (200):

{
  "success": true,
  "data": {
    "success": true,
    "transaction": "0x1f00f9d92d433c29472354853f77c3a97398b01f4e0820c13a068e29daebdd2c",
    "networkId": "base"
  },
  "requestId": "unique-request-id",
  "timestamp": "2025-11-04T12:00:00.000Z"
}

For Solana (SVM):

{
  "success": true,
  "data": {
    "success": true,
    "signature": "4haFW9Zp7cB8tgqPgASvyEJhPYfZaNKcLVHdhCKPhiKuCWudtSHEQWQhMDuWzhBEeg9F9LVED4ZC6E8hYU4CPWMi",
    "networkId": "solana"
  },
  "requestId": "unique-request-id",
  "timestamp": "2025-11-04T12:00:00.000Z"
}

Failure Response (200):

{
  "success": true,
  "data": {
    "success": false,
    "error": "Transaction simulation failed",
    "txHash": null,
    "networkId": "base"
  },
  "requestId": "unique-request-id",
  "timestamp": "2025-11-04T12:00:00.000Z"
}

Sample Transactions

EVM Transaction Example (Base Mainnet)

Transaction Hash: 0x1f00f9d92d433c29472354853f77c3a97398b01f4e0820c13a068e29daebdd2c

Explorer Link: View on Basescan

Transaction Details:

  • Network: Base Mainnet

  • From: Consumer Wallet

  • To: USDC Contract (transferWithAuthorization)

  • Amount: $0.01 USDC

  • Gas Fee: ~$0.001 (paid by facilitator)

  • Confirmation Time: ~2 seconds

  • Total Cost to Consumer: $0.01 USDC


SVM Transaction Example (Solana Mainnet)

Transaction Signature: 4haFW9Zp7cB8tgqPgASvyEJhPYfZaNKcLVHdhCKPhiKuCWudtSHEQWQhMDuWzhBEeg9F9LVED4ZC6E8hYU4CPWMi

Explorer Link: View on Solana Explorer

Transaction Details:

  • Network: Solana Mainnet

  • Transaction Type: SPL Token Transfer (v0 versioned transaction)

  • From: Consumer Token Account

  • To: Merchant Token Account

  • Amount: $0.01 USDC

  • Transaction Fee: ~$0.000005 (paid by consumer)

  • Confirmation Time: ~400ms

  • Total Cost to Consumer: $0.010005 USDC

Important Note: Solana transactions use versioned transactions (v0) which are more efficient and support lookup tables for reduced transaction size.


Advanced Examples

Multi-Network Consumer (Universal)

This example shows how to create a universal consumer that works across all supported networks:

import axios from 'axios';
import { ethers } from 'ethers';
import { Keypair, Connection, TransactionMessage, VersionedTransaction, PublicKey } from '@solana/web3.js';
import { getAssociatedTokenAddress, createTransferInstruction } from '@solana/spl-token';
import bs58 from 'bs58';

interface NetworkConfig {
  type: 'evm' | 'svm';
  chainId?: number;
  rpcUrl?: string;
  usdcAddress: string;
}

const NETWORKS: Record<string, NetworkConfig> = {
  'base': {
    type: 'evm',
    chainId: 8453,
    usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
  },
  'polygon': {
    type: 'evm',
    chainId: 137,
    usdcAddress: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359'
  },
  'avalanche': {
    type: 'evm',
    chainId: 43114,
    usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E'
  },
  'solana': {
    type: 'svm',
    rpcUrl: 'https://api.mainnet-beta.solana.com',
    usdcAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
  }
};

class UniversalX402Consumer {
  private evmWallet?: ethers.Wallet;
  private svmKeypair?: Keypair;
  private svmConnection?: Connection;

  constructor(
    evmPrivateKey?: string,
    svmPrivateKey?: string
  ) {
    if (evmPrivateKey) {
      this.evmWallet = new ethers.Wallet(evmPrivateKey);
    }
    if (svmPrivateKey) {
      this.svmKeypair = Keypair.fromSecretKey(bs58.decode(svmPrivateKey));
      this.svmConnection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');
    }
  }

  async createEVMPayment(requirements: any, network: string): Promise<string> {
    if (!this.evmWallet) throw new Error('EVM wallet not configured');

    const config = NETWORKS[network];
    const domain = {
      name: 'USD Coin',
      version: '2',
      chainId: config.chainId,
      verifyingContract: requirements.asset,
    };

    const types = {
      TransferWithAuthorization: [
        { name: 'from', type: 'address' },
        { name: 'to', type: 'address' },
        { name: 'value', type: 'uint256' },
        { name: 'validAfter', type: 'uint256' },
        { name: 'validBefore', type: 'uint256' },
        { name: 'nonce', type: 'bytes32' },
      ],
    };

    const value = {
      from: this.evmWallet.address,
      to: requirements.payTo,
      value: requirements.maxAmountRequired,
      validAfter: 0,
      validBefore: Math.floor(Date.now() / 1000) + 3600,
      nonce: ethers.hexlify(ethers.randomBytes(32)),
    };

    const signature = await this.evmWallet.signTypedData(domain, types, value);

    const paymentPayload = {
      x402Version: 1,
      scheme: 'exact',
      network: network,
      payload: {
        authorization: {
          from: this.evmWallet.address,
          to: requirements.payTo,
          value: requirements.maxAmountRequired,
          validAfter: value.validAfter.toString(),
          validBefore: value.validBefore.toString(),
          nonce: value.nonce,
        },
        signature: signature
      }
    };

    return Buffer.from(JSON.stringify(paymentPayload)).toString('base64');
  }

  async createSVMPayment(requirements: any): Promise<string> {
    if (!this.svmKeypair || !this.svmConnection) {
      throw new Error('SVM wallet not configured');
    }

    const fromPubkey = this.svmKeypair.publicKey;
    const toPubkey = new PublicKey(requirements.payTo);
    const mintPubkey = new PublicKey(requirements.asset);
    const amount = BigInt(requirements.maxAmountRequired);

    const fromTokenAccount = await getAssociatedTokenAddress(mintPubkey, fromPubkey);
    const toTokenAccount = await getAssociatedTokenAddress(mintPubkey, toPubkey);

    const transferInstruction = createTransferInstruction(
      fromTokenAccount,
      toTokenAccount,
      fromPubkey,
      amount
    );

    const { blockhash } = await this.svmConnection.getLatestBlockhash('finalized');

    const messageV0 = new TransactionMessage({
      payerKey: fromPubkey,
      recentBlockhash: blockhash,
      instructions: [transferInstruction],
    }).compileToV0Message();

    const transaction = new VersionedTransaction(messageV0);
    transaction.sign([this.svmKeypair]);

    const serializedTx = transaction.serialize();
    const base64Tx = Buffer.from(serializedTx).toString('base64');

    const paymentPayload = {
      x402Version: 1,
      scheme: 'exact',
      network: 'solana',
      payload: {
        transaction: base64Tx
      }
    };

    return Buffer.from(JSON.stringify(paymentPayload)).toString('base64');
  }

  async fetchWithPayment(url: string, preferredNetwork?: string): Promise<any> {
    let response = await axios.get(url, { validateStatus: () => true });

    if (response.status === 402) {
      const requirements = response.data;
      const network = preferredNetwork || requirements.network;
      const config = NETWORKS[network];

      if (!config) {
        throw new Error(`Unsupported network: ${network}`);
      }

      console.log(`💳 Payment required: ${requirements.maxAmountRequired} on ${network}`);

      let paymentHeader: string;
      if (config.type === 'evm') {
        paymentHeader = await this.createEVMPayment(requirements, network);
      } else {
        paymentHeader = await this.createSVMPayment(requirements);
      }

      response = await axios.get(url, {
        headers: { 'X-PAYMENT': paymentHeader },
        validateStatus: () => true
      });

      if (response.status === 200) {
        console.log('✅ Payment successful!');
      } else {
        throw new Error(`Payment failed: ${JSON.stringify(response.data)}`);
      }
    }

    return response.data;
  }
}

// Usage
const consumer = new UniversalX402Consumer(
  process.env.EVM_PRIVATE_KEY,
  process.env.SVM_PRIVATE_KEY
);

// Use with Base
await consumer.fetchWithPayment('https://merchant.com/premium', 'base');

// Use with Polygon
await consumer.fetchWithPayment('https://merchant.com/premium', 'polygon');

// Use with Solana
await consumer.fetchWithPayment('https://merchant.com/premium', 'solana');

Polygon Payment Example

import axios from 'axios';
import { ethers } from 'ethers';

const POLYGON_CONFIG = {
  network: 'polygon',
  chainId: 137,
  usdcAddress: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
  rpcUrl: 'https://polygon-rpc.com'
};

const wallet = new ethers.Wallet(process.env.CONSUMER_PRIVATE_KEY);
const MERCHANT_URL = process.env.MERCHANT_URL;

async function createPolygonPayment(requirements: any): Promise<string> {
  const domain = {
    name: 'USD Coin',
    version: '2',
    chainId: POLYGON_CONFIG.chainId,
    verifyingContract: requirements.asset,
  };

  const types = {
    TransferWithAuthorization: [
      { name: 'from', type: 'address' },
      { name: 'to', type: 'address' },
      { name: 'value', type: 'uint256' },
      { name: 'validAfter', type: 'uint256' },
      { name: 'validBefore', type: 'uint256' },
      { name: 'nonce', type: 'bytes32' },
    ],
  };

  const value = {
    from: wallet.address,
    to: requirements.payTo,
    value: requirements.maxAmountRequired,
    validAfter: 0,
    validBefore: Math.floor(Date.now() / 1000) + 3600,
    nonce: ethers.hexlify(ethers.randomBytes(32)),
  };

  const signature = await wallet.signTypedData(domain, types, value);

  const paymentPayload = {
    x402Version: 1,
    scheme: 'exact',
    network: 'polygon',
    payload: {
      authorization: {
        from: wallet.address,
        to: requirements.payTo,
        value: requirements.maxAmountRequired,
        validAfter: value.validAfter.toString(),
        validBefore: value.validBefore.toString(),
        nonce: value.nonce,
      },
      signature: signature
    }
  };

  return Buffer.from(JSON.stringify(paymentPayload)).toString('base64');
}

// Usage
async function buyContent() {
  let response = await axios.get(MERCHANT_URL + '/premium', {
    validateStatus: () => true
  });

  if (response.status === 402) {
    const requirements = response.data;
    const paymentHeader = await createPolygonPayment(requirements);
    
    response = await axios.get(MERCHANT_URL + '/premium', {
      headers: { 'X-PAYMENT': paymentHeader },
      validateStatus: () => true
    });
  }

  return response.data;
}

Avalanche Payment Example

import axios from 'axios';
import { ethers } from 'ethers';

const AVALANCHE_CONFIG = {
  network: 'avalanche',
  chainId: 43114,
  usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
  rpcUrl: 'https://api.avax.network/ext/bc/C/rpc'
};

const wallet = new ethers.Wallet(process.env.CONSUMER_PRIVATE_KEY);

async function createAvalanchePayment(requirements: any): Promise<string> {
  const domain = {
    name: 'USD Coin',
    version: '2',
    chainId: AVALANCHE_CONFIG.chainId,
    verifyingContract: requirements.asset,
  };

  const types = {
    TransferWithAuthorization: [
      { name: 'from', type: 'address' },
      { name: 'to', type: 'address' },
      { name: 'value', type: 'uint256' },
      { name: 'validAfter', type: 'uint256' },
      { name: 'validBefore', type: 'uint256' },
      { name: 'nonce', type: 'bytes32' },
    ],
  };

  const value = {
    from: wallet.address,
    to: requirements.payTo,
    value: requirements.maxAmountRequired,
    validAfter: 0,
    validBefore: Math.floor(Date.now() / 1000) + 3600,
    nonce: ethers.hexlify(ethers.randomBytes(32)),
  };

  const signature = await wallet.signTypedData(domain, types, value);

  const paymentPayload = {
    x402Version: 1,
    scheme: 'exact',
    network: 'avalanche',
    payload: {
      authorization: {
        from: wallet.address,
        to: requirements.payTo,
        value: requirements.maxAmountRequired,
        validAfter: value.validAfter.toString(),
        validBefore: value.validBefore.toString(),
        nonce: value.nonce,
      },
      signature: signature
    }
  };

  return Buffer.from(JSON.stringify(paymentPayload)).toString('base64');
}

Multi-Endpoint Merchant

This example shows a merchant that accepts payments on multiple networks:

import express from 'express';
import axios from 'axios';

const app = express();
app.use(express.json());

const MERCHANT_CONFIG = {
  walletAddress: process.env.MERCHANT_WALLET_ADDRESS,
  facilitatorUrl: 'https://facilitator.octox402.xyz',
  supportedNetworks: ['base', 'polygon', 'avalanche', 'solana']
};

const USDC_ADDRESSES = {
  base: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
  polygon: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
  avalanche: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
  solana: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
};

async function createPaymentMiddleware(
  network: string,
  amount: string,
  description: string
) {
  return async (req: any, res: any, next: any) => {
    const paymentHeader = req.headers['x-payment'];
    
    const paymentRequirements = {
      scheme: 'exact',
      network: network,
      maxAmountRequired: amount,
      payTo: MERCHANT_CONFIG.walletAddress,
      asset: USDC_ADDRESSES[network as keyof typeof USDC_ADDRESSES],
      resource: `${req.protocol}://${req.get('host')}${req.originalUrl}`,
      description: description,
      mimeType: 'application/json',
      maxTimeoutSeconds: 300
    };
    
    if (!paymentHeader) {
      return res.status(402).json(paymentRequirements);
    }
    
    try {
      const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');
      const paymentPayload = JSON.parse(decoded);
      
      // Verify
      const verifyResponse = await axios.post(
        `${MERCHANT_CONFIG.facilitatorUrl}/verify`,
        { paymentPayload, paymentRequirements }
      );
      
      if (!verifyResponse.data.data.isValid) {
        return res.status(402).json({
          error: 'Payment verification failed',
          reason: verifyResponse.data.data.invalidReason
        });
      }
      
      // Settle
      const settleResponse = await axios.post(
        `${MERCHANT_CONFIG.facilitatorUrl}/settle`,
        { paymentPayload, paymentRequirements }
      );
      
      if (!settleResponse.data.data.success) {
        return res.status(402).json({
          error: 'Payment settlement failed'
        });
      }
      
      console.log(`✅ Payment received on ${network}:`, settleResponse.data.data.transaction);
      next();
      
    } catch (error: any) {
      return res.status(500).json({
        error: 'Payment processing failed',
        message: error.message
      });
    }
  };
}

// Endpoints with different networks
app.get('/premium-base', 
  await createPaymentMiddleware('base', '10000', 'Premium content on Base'),
  (req, res) => {
    res.json({ 
      content: 'Your premium content',
      network: 'base',
      paid: true 
    });
  }
);

app.get('/premium-polygon',
  await createPaymentMiddleware('polygon', '10000', 'Premium content on Polygon'),
  (req, res) => {
    res.json({ 
      content: 'Your premium content',
      network: 'polygon',
      paid: true 
    });
  }
);

app.get('/premium-avalanche',
  await createPaymentMiddleware('avalanche', '10000', 'Premium content on Avalanche'),
  (req, res) => {
    res.json({ 
      content: 'Your premium content',
      network: 'avalanche',
      paid: true 
    });
  }
);

app.get('/premium-solana',
  await createPaymentMiddleware('solana', '10000', 'Premium content on Solana'),
  (req, res) => {
    res.json({ 
      content: 'Your premium content',
      network: 'solana',
      paid: true 
    });
  }
);

app.listen(3000, () => {
  console.log('✅ Multi-network merchant running on port 3000');
  console.log('Supported networks:', MERCHANT_CONFIG.supportedNetworks);
});

Security

  1. Never expose private keys in code or version control

  2. Use environment variables for sensitive configuration

  3. Validate all payment requirements match expected values

  4. Implement rate limiting on merchant endpoints

  5. Use HTTPS for all production deployments

Performance

  1. Cache payment verification results where appropriate

  2. Implement request timeouts (recommended: 30 seconds)

  3. Use connection pooling for RPC endpoints

  4. Monitor facilitator health regularly

Error Handling

  1. Always validate payment payload format before processing

  2. Return clear error messages to consumers

  3. Log all payment attempts for debugging

  4. Implement retry logic for network failures

  5. Handle expired signatures gracefully

Cost Optimization

EVM (Base)

  • Gas fees: ~$0.001 per transaction (paid by facilitator)

  • Payment amount: $0.01+ USDC

  • Total consumer cost: Payment amount only

SVM (Solana)

  • Transaction fees: ~$0.000005 per transaction (paid by consumer)

  • Payment amount: $0.01+ USDC

  • Total consumer cost: Payment amount + ~$0.000005


Support

  • Facilitator URL: https://facilitator.octox402.xyz

  • Documentation: https://docs.octonet.ai/key-features/octo-x402

  • Website: https://octonet.ai

  • Protocol Version: x402 v1

Network Status

  • Production Ready: Base, Base Sepolia, Abstract, Abstract Testnet, Polygon, Polygon Amoy, Avalanche, Avalanche Fuji, SEI, SEI Testnet, IoTeX, Peaq, Solana, Solana Devnet (12 networks)

  • Testing Phase: BSC (Binance Smart Chain), Ethereum Mainnet, Optimism, Arbitrum

Key Features

  • ✅ 12 production-ready networks across EVM and SVM

  • ✅ Instant micropayments with USDC

  • ✅ HTTP 402 payment protocol

  • ✅ EIP-712 signatures for EVM

  • ✅ Versioned transactions (v0) for Solana

  • ✅ Facilitator pays gas on EVM networks

  • ✅ Consumer pays minimal fees on Solana (~$0.000005)

  • ✅ Production-grade facilitator with 99.9% uptime

Sample Transactions

EVM (Base): 0x1f00f9... SVM (Solana): 4haFW9...

Last updated