npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@x402-agent-gateway/server

v1.0.3

Published

Backend SDK for x402-native agent and tool orchestration

Readme

@x402-agent-gateway/server

Backend SDK for x402-native agent and tool orchestration. This package provides a server-side framework for creating payment-enabled tool servers with integrated OpenAI chat completions.

For the client SDK, see @x402-agent-gateway/client.

Installation

npm install @x402-agent-gateway/server

Quick Start

import { createToolServer, registerTool } from '@x402-agent-gateway/server';
import { PublicKey } from '@solana/web3.js';
import { z } from 'zod';

// Create the server
const server = createToolServer({
  port: 3000,
  facilitatorUrl: 'https://facilitator.payai.network',
  recipientWallet: 'YourSolanaWalletAddress',
  network: 'solana-devnet',
  openaiApiKey: process.env.OPENAI_API_KEY,
});

// Register a tool

const USDC_MINT = new PublicKey(
  'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // Mainnet USDC
  // For devnet: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU'
);

registerTool({
  name: 'echo',
  description: 'Echoes back the input message',
  inputSchema: z.object({
    message: z.string(),
  }),
  price: {
    asset: 'USDC',
    amount: '10000', // 0.01 USDC (6 decimals)
    mint: USDC_MINT,
  },
  handler: async (args) => {
    return { echo: args.message };
  },
});

// Start the server
server.start();

Configuration

The server accepts a ServerConfig object with the following options:

interface ServerConfig {
  port?: number;                    // Server port (default: 3000)
  facilitatorUrl: string;           // x402 facilitator URL (required)
  recipientWallet: string;          // Solana wallet address to receive payments (required)
  network: Network;                 // "solana" | "solana-devnet" (required)
  devMode?: boolean;                // Disable payments for testing (default: false)
  openaiApiKey?: string;            // OpenAI API key for chat completions (optional)
  chatPaymentPrice?: ChatPaymentPrice; // Price for chat completions (optional)
}

type ChatPaymentPrice =
  | PaymentPrice                    // Static price
  | TokenBasedPricing               // Dynamic token-based pricing
  | null                            // Free chat completions
  | ((messages: ChatMessage[]) => PaymentPrice | Promise<PaymentPrice>); // Custom function

Configuration Options

  • port (optional): The port number to listen on. Defaults to 3000
  • facilitatorUrl (required): The URL of the x402 payment facilitator service (e.g., "https://facilitator.payai.network")
  • recipientWallet (required): A valid Solana public key address where payments will be sent
  • network (required): The Solana network to use. Must be either "solana" (mainnet) or "solana-devnet" (devnet)
  • devMode (optional): When true, disables payment verification for testing. Defaults to false
  • openaiApiKey (optional): Your OpenAI API key. Required if you want to use the chat completions endpoint
  • chatPaymentPrice (optional): The payment price for chat completions. Can be:
    • null - Free chat completions
    • PaymentPrice - Static fixed price
    • TokenBasedPricing - Dynamic price based on message token count
    • Function - Custom pricing function

Chat Payment Pricing

The chatPaymentPrice option supports multiple pricing models:

Static Pricing

Use a fixed price for all chat completions:

const server = createToolServer({
  // ... other config
  chatPaymentPrice: {
    asset: 'USDC',
    amount: '10000', // 0.01 USDC (6 decimals)
    mint: USDC_MINT,
  },
});

Token-Based Pricing (Recommended)

Automatically calculate price based on the number of tokens in the messages. This ensures fair pricing that scales with usage:

const server = createToolServer({
  // ... other config
  chatPaymentPrice: {
    asset: 'USDC',
    mint: USDC_MINT,
    costPerToken: '1',        // 1 micro-USDC per token (0.000001 USDC)
    baseAmount: '0',          // Optional base amount to add
    min: '100',                // Minimum price: 100 micro-USDC (0.0001 USDC)
    max: '1000000',            // Optional maximum: 1 USDC
    model: 'gpt-4o',          // Model for token counting (default: "gpt-4o")
  },
});

Token-Based Pricing Options:

  • asset (required): The payment asset (e.g., "USDC")
  • mint (optional): SPL token mint address (required for tokens, not needed for SOL)
  • costPerToken (required): Price per token in the same unit as baseAmount
  • baseAmount (optional): Base amount to add to the token-based calculation (default: "0")
  • min (optional): Minimum price to charge regardless of token count
  • max (optional): Maximum price cap
  • model (optional): OpenAI model name for accurate token counting (default: "gpt-4o")

The final price is calculated as: max(min, min(max, baseAmount + (tokens × costPerToken)))

Custom Function Pricing

For advanced use cases, you can provide a custom function:

const server = createToolServer({
  // ... other config
  chatPaymentPrice: async (messages) => {
    // Custom logic to calculate price
    const tokenCount = /* your calculation */;
    return {
      asset: 'USDC',
      amount: (tokenCount * 0.00001).toString(),
      mint: USDC_MINT,
    };
  },
});

Free Chat Completions

Set chatPaymentPrice to null to make chat completions free:

const server = createToolServer({
  // ... other config
  chatPaymentPrice: null, // Free chat completions
});

Registering Tools

Tools are registered using the registerTool function. Each tool must have:

  • name: A unique identifier for the tool
  • description: A description of what the tool does (used by OpenAI)
  • inputSchema: A Zod schema defining the input parameters
  • outputSchema (optional): A Zod schema for validating the output
  • price: A fixed price or a function that calculates the price based on input
  • handler: An async function that executes the tool logic

Fixed Price Example

import { registerTool } from '@x402-agent-gateway/server';
import { z } from 'zod';

registerTool({
  name: 'calculate',
  description: 'Performs basic arithmetic calculations',
  inputSchema: z.object({
    operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
    a: z.number(),
    b: z.number(),
  }),
  outputSchema: z.object({
    result: z.number(),
  }),
  price: {
    asset: 'USDC',
    amount: '5000', // 0.005 USDC (6 decimals)
    mint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
  },
  handler: async (args) => {
    let result: number;
    switch (args.operation) {
      case 'add': result = args.a + args.b; break;
      case 'subtract': result = args.a - args.b; break;
      case 'multiply': result = args.a * args.b; break;
      case 'divide': result = args.a / args.b; break;
    }
    return { result };
  },
});

Dynamic Price Example

registerTool({
  name: 'data-processor',
  description: 'Processes data with variable pricing',
  inputSchema: z.object({
    dataSize: z.number(),
  }),
  price: async (args) => {
    // Calculate price based on data size
    const basePrice = 10000; // 0.01 USDC
    const sizeMultiplier = args.dataSize / 1000;
    return {
      asset: 'USDC',
      amount: (basePrice * sizeMultiplier).toString(),
      mint: USDC_MINT,
    };
  },
  handler: async (args) => {
    // Process the data...
    return { processed: true };
  },
});

Payment Price Format

PaymentPrice Interface

The price field for tools accepts either a PaymentPrice object or a function that returns one:

interface PaymentPrice {
  asset: string;        // Asset name (e.g., "USDC")
  amount: string;       // Amount as a string (supports decimals)
  mint?: PublicKey;     // Required: SPL token mint address
}

TokenBasedPricing Interface

For chat completions, you can use the TokenBasedPricing interface for dynamic token-based pricing:

interface TokenBasedPricing {
  asset: string;         // Asset name (e.g., "USDC")
  mint?: PublicKey;     // SPL token mint address (required for tokens)
  costPerToken: string; // Price per token
  baseAmount?: string;  // Optional base amount to add
  min?: string;         // Optional minimum price
  max?: string;         // Optional maximum price
  model?: string;       // Model name for token counting (default: "gpt-4o")
}

USDC Payments

import { PublicKey } from '@solana/web3.js';

price: {
  asset: 'USDC',
  amount: '10000', // 0.01 USDC (6 decimals)
  mint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
}

API Endpoints

The server automatically creates the following endpoints:

GET /tools

Returns metadata for all registered tools.

Response:

[
  {
    "name": "echo",
    "description": "Echoes back the input message",
    "inputSchema": { ... },
    "outputSchema": { ... },
    "price": { ... }
  }
]

POST /tools/:name/invoke

Invokes a specific tool. Requires payment verification.

Request Body:

{
  "arg1": "value1",
  "arg2": 123
}

Response: The tool handler's return value, validated against outputSchema if provided.

POST /v1/chat/completions

OpenAI-compatible chat completions endpoint with automatic tool integration.

Request Body:

{
  "model": "gpt-4",
  "messages": [
    { "role": "user", "content": "Hello!" }
  ],
  "tools": "auto",
  "temperature": 0.7
}

Response: OpenAI-compatible chat completion response with tool calls if applicable.

Advanced Usage

Using the Express App Directly

If you need more control, you can access the underlying Express app:

const server = createToolServer({ ... });
const app = server.getApp();

// Add custom middleware or routes
app.use('/custom', customRouter);

Manual Router Setup

For more advanced use cases, you can use the router directly:

import { createX402Router, registerTool } from '@x402-agent-gateway/server';
import express from 'express';

const app = express();
const router = createX402Router({
  recipientWallet: '...',
  network: 'solana-devnet',
  facilitatorUrl: '...',
  openaiApiKey: process.env.OPENAI_API_KEY,
});

app.use('/', router);
app.listen(3000);

Error Handling

The server returns standardized error responses:

{
  "code": "ERROR_CODE",
  "message": "Human-readable error message",
  "retriable": true,  // Whether the client should retry
  "details": "..."    // Additional error details (optional)
}

Common error codes:

  • TOOL_NOT_FOUND: The requested tool doesn't exist
  • VALIDATION_ERROR: Input validation failed (not retriable)
  • EXECUTION_ERROR: Tool execution failed (retriable)
  • PAYMENT_REQUIRED: Payment verification failed
  • OPENAI_API_ERROR: OpenAI API error

Development Mode

When devMode is enabled, payment verification is bypassed, allowing you to test your tools without making actual payments:

const server = createToolServer({
  // ... other config
  devMode: true, // Payments disabled
});