# X402 + AnySpend: Chain-Agnostic, Token-Agnostic Payments for Autonomous Agents > The upgrade that turns X402 into a universal payment standard. **Published by:** [HeimLabs](https://paragraph.com/@heimlabs/) **Published on:** 2025-11-19 **Categories:** web3, x402, anyspend **URL:** https://paragraph.com/@heimlabs/x402-anyspend-chain-agnostic-token-agnostic-payments-for-autonomous-agents ## Content IntroductionX402 introduced a simple idea: let agents pay for API access using the native semantics of the web, HTTP 402. No accounts, no custodians, no browser redirects. Just a request, a payment prompt, and a retry with a signed authorization. But X402 originally operated on a single chain and token, which restricted how widely agents could function. AnySpend removes those limits. It keeps the familiar X402 flow exactly as it is, while adding the ability to pay with any token on any chain. Under the hood, AnySpend performs swaps, bridging, and settlement, completely invisible to the buyer and seller. With this upgrade, X402 becomes a universal, chain-agnostic payment layer for agents.Why This Matters for Autonomous AgentsAgents rarely hold the “correct” asset for every service. One might have USDC on Base, another might earn fees in ETH on Optimism, while a service might settle in DAI on Ethereum. Before AnySpend, these mismatches broke automation. Now, they don’t matter.Agents pay with whatever they already haveSellers receive exactly what they wantNo one has to orchestrate routing or bridging logicThis allows autonomous systems to operate fluidly across chains and economies.ImplementationLet’s walk through how to set up both server and client that charges users for API access using Anyspend X402. We’ll be building a weather API that requires payment before access. Users can pay with any tokens to access the weather endpoint, but the server requires B3 tokens on the Base network. (Watch the video here) Setting Up the Express ServerFirst, let’s start with a basic Express setup. Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.import express from "express"; import { config } from "dotenv"; config(); const app = express(); app.use(express.json());Here, we:Import Express and dotenv for environment variable managementLoad environment variables from a .env fileCreate an Express application instanceConfigure Express to parse JSON request bodiesTo enable payment functionality, we need to install and import two key libraries from the Anyspend X402 ecosystem: @b3dotfun/anyspend-x402-express — Provides Express middleware for handling payments @b3dotfun/anyspend-x402 — Core library with facilitator configuration utilities @b3dotfun/anyspend-x402-fetch — library that extends the standard fetch API with payment capabilitiesimport { paymentMiddleware } from "@b3dotfun/anyspend-x402-express"; import { createFacilitatorConfig, } from '@b3dotfun/anyspend-x402'; import { FacilitatorConfig } from "@b3dotfun/anyspend-x402/types";The paymentMiddleware is what we’ll use to protect our API routes, while createFacilitatorConfig helps us set up the facilitator configuration that handles payment processing.Setting Up the Facilitator URLThe facilitator is a service that handles payment verification and processing. In our case, we’re using the mainnet facilitator:const facilitatorUrl = "https://mainnet.anyspend.com/x402"; const payTo = "0x6aed5ca43987221f41ba4bb2ebe29a7f583a53ff" as `0x${string}`This URL points to the production Anyspend facilitator service that will verify payments on the blockchain before allowing requests to proceed. The payTo address is the cryptocurrency address where payments will be sent. This is your revenue address: All payments for API access will be sent to this payTo address. Make sure this is an address you control!Setting Up the Facilitator ConfigThe facilitator configuration tells the payment system how to interact with the facilitator service:const facilitatorConfig: FacilitatorConfig = { …createFacilitatorConfig(), url: facilitatorUrl };We use createFacilitatorConfig() to get default configuration settings.This configuration will be passed to the payment middleware to handle payment verification.Defining the Payment MiddlewareNow comes the exciting part, setting up the payment middleware. This middleware will intercept requests to protected routes and verify that payment has been made before allowing access:app.use( paymentMiddleware( payTo, { // Cross-chain: Accept B3 on Base "GET /weather": { price: { amount: '1000000000000000', // 0.001 B3 tokens (18 decimals) asset: { address: '0xB3B32F9f8827D4634fE7d973Fa1034Ec9fdDB3B3', decimals: 18, eip712: { name: 'B3', version: '1', }, }, }, network: "base", config: { description: "Premium weather content paid with B3 on base", }, }, }, facilitatorConfig, ), );Let’s break down what’s happening here:payTo: The address that receives paymentsRoute configuration: We’re protecting the GET /weather endpointPrice: Set to 1000000000000000 wei (0.001 B3 tokens, since B3 has 18 decimals)Asset: The B3 token contract address on Base networkNetwork: “base” — we’re accepting payments on the Base networkDescription: A human-readable description of what the payment is forThe middleware will automatically:Check if a valid payment proof is included in the requestVerify the payment with the facilitatorAllow the request to proceed if payment is validReject the request if payment is missing or invalidPlugging It In with the Weather APIFinally, we define our actual weather endpoint. This is a simple endpoint that returns weather data:app.get("/weather", (req, res) => { res.send({ report: { weather: "sunny", temperature: 70, }, }); });Because we’ve applied the payment middleware earlier, this endpoint is now protected. Users must include a valid payment proof in their request headers to access this endpoint.Starting the ServerWe start the server on port 4021:app.listen(4021, () => { console.log(`Multi-token server listening at http://localhost:${4021}`); });Setting up the clientThe client uses a wrapped fetch function that automatically handles payment processing, so you can make API calls just like you would with regular HTTP requests, but with built-in cryptocurrency payment support. But first, we need to configure our environment variables. The client requires a private key for signing transactions and an optional API URL:import { config } from "dotenv"; config(); const privateKey = process.env.PRIVATE_KEY as Hex | string; const apiUrl = process.env.API_URL || "http://localhost:3001"; const MAX_PAYMENT_VALUE = BigInt("5000000000000000000"); // 5 ethers maxHere’s what each variable does:PRIVATE_KEY: Your Ethereum private key used to sign payment transactions. This should be kept secret and stored in a .env file.API_URL: The base URL of the API server. Defaults to http://localhost:3001 if not provided.MAX_PAYMENT_VALUE: A safety limit for maximum payment amount (5 ETH in this case) to prevent accidental overpayments.Installing and Importing the Client LibraryThe client uses @b3dotfun/anyspend-x402-fetch, a library that extends the standard fetch API with payment capabilities:import { decodeXPaymentResponse, wrapFetchWithPayment, createSigner, type Hex, } from "@b3dotfun/anyspend-x402-fetch";Let’s break down these imports:wrapFetchWithPayment: The main function that wraps the standard fetch to add automatic payment handlingcreateSigner: Creates a cryptographic signer from a private key for signing payment transactionsdecodeXPaymentResponse: Decodes payment information from API response headersHex: TypeScript type for hexadecimal strings (Ethereum addresses, transaction hashes, etc.)Creating a SignerBefore we can make paid requests, we need to create a signer that will sign payment transactions on behalf of the user: const network = “ethereum” const signer = await createSigner(network, privateKey); The signer:Takes a network identifier (in this case, “ethereum”)Uses your private key to sign transactionsEnables the client to authorize payments automaticallyThe signer is what allows the wrapped fetch function to create and sign payment transactions without requiring manual wallet interactions for each request.Wrapping Fetch with PaymentThis is where the magic happens. We wrap the standard fetch function to add automatic payment processing:const fetchWithPayment = wrapFetchWithPayment( fetch, signer, MAX_PAYMENT_VALUE, undefined, undefined, { preferredNetwork: network, preferredToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" // $USDC token on ethereum } );Let’s understand each parameter:fetch: The standard fetch function to wrapsigner: The signer we created earlier for authorizing paymentsMAX_PAYMENT_VALUE: Maximum payment amount as a safety limit.Configuration object:preferredNetwork: The blockchain network to use for payments (“ethereum” in this case)preferredToken: The token contract address to use for payments (USDC on Ethereum)Making the API CallWith our payment-enabled fetch function, making a paid API call is as simple as a regular HTTP request: const response = await fetchWithPayment(`${apiUrl}/weather`, { method: “GET”, }); The wrapped fetch handles all the payment complexity behind the scenes. If the API requires payment, it will:Check the payment requirements from the APICreate and sign a payment transactionInclude the signature in the requestThen retries the API callHandling Payment ResponsesThe API server includes payment information in response headers. We can extract and decode this information:// Get payment response header const paymentResponseHeader = response.headers.get("X-PAYMENT-RESPONSE"); if (paymentResponseHeader) { const paymentInfo = decodeXPaymentResponse(paymentResponseHeader); console.log(JSON.stringify(paymentInfo, null, 2)); }The X-PAYMENT-RESPONSE header contains encoded payment details such as:Transaction hashPayment amountToken usedNetworkTimestampThis is useful for tracking payments, displaying receipts, or debugging payment issues.Handling ErrorsWe include comprehensive error handling:if (!response.ok) { const errorData = await response.json(); console.error("❌ Request failed:"); console.error(JSON.stringify(errorData, null, 2)); return; }If the API call fails (due to payment issues, network problems, or API errors), we:Check if the response is not OKParse the error responseDisplay it in a readable formatExit gracefullyProcessing the Response DataFinally, we extract and display the actual API response:// Get the response data const data = await response.json(); console.log(JSON.stringify(data, null, 2));In our weather API example, this would display:{ "report": { "weather": "sunny", "temperature": 70 } }How the Flow Works The X402 flow stays exactly the same:Client requests a resourceServer responds with 402 + payment detailsClient retries with a signed payment authorizationService grants accessThe only difference now is what the facilitator is capable of. Once the signed message arrives, AnySpend handles everything else:Validates the signature (EIP-2612 / EIP-3009 typed data)Pulls the specified fundsSwaps the token if neededBridges to the seller’s chain, if neededSettles in the seller’s preferred tokenTo the client, nothing changes. To the seller, everything becomes interoperable.Security ModelThe security guarantees come from the signature standards themselves—not the facilitator.Standard signature with EIP 2612 and EIP 3009, which offers replay protection via noncesSignature expiration via deadlinesSigner verification via EIP-712 address recovery by the contractA facilitator cannot forge or spoof signatures AnySpend only executes what the wallet owner explicitly authorizes.Developer IntegrationAnySpend is designed so both sides can integrate easily:For SellersExpress middleware to monetize any endpoint with a 402 paywallSettlement configuration (desired chain + token)REST API for low-level controlFor Buyers/AgentsClient SDK for easy integration.Preparing and signing typed-data payments is handled automatically.Drop-in compatibility with existing X402 agent scriptsThe integration experience remains simple and consistent.A Simple Mental ModelYou keep writing X402 the way you always have. AnySpend makes it work everywhere. That’s the entire upgrade.ConclusionX402 keeps the simple flow, and AnySpend extends it across chains and assets. Agents pay with what they have, services settle how they prefer, and the whole loop stays automated.Resources AnySpend WebsiteAnySpend - Swap & trade crypto tokens from any chainAnySpend is a secure cross-chain crypto swapping platform that lets you seamlessly trade tokens across any blockchain network. Get the best rates, fast transactions, and easy token swaps between Base, Ethereum, Solana, and other major chains.https://anyspend.comHeimLabsHeimLabs | Trusted Blockchain Solutions ProviderRevolutionize your business with HeimLabs' blockchain development solutions. Our expert team offers end-to-end services for smart contracts, DApps & more.https://www.heimlabs.comThis is the foundation of open, intelligent, multi-chain autonomous commerce. Share what you’re building with the CDP stack! Follow HeimLabs for unapologetically practical Web3 dev content. Twitter, LinkedIn. Happy Building 🚀 ## Publication Information - [HeimLabs](https://paragraph.com/@heimlabs/): Publication homepage - [All Posts](https://paragraph.com/@heimlabs/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@heimlabs): Subscribe to updates - [Twitter](https://twitter.com/heimlabs): Follow on Twitter - [Farcaster](https://farcaster.xyz/heimlabs): Follow on Farcaster