DEV Community

Nikola Bencic
Nikola Bencic

Posted on

How to Route x402 Payments Across Multiple Chains (Save 90%+ on Fees)

Your AI agent just got a 402 Payment Required response. It needs to pay — but on which chain?

If it picks Base, the fee is $0.003. If it picks Polygon, $0.0075. If it picks Stellar, $0.00001. If it picks Ethereum L1... $3.50. That's a 350,000x difference for the same $0.10 USDC transfer.

Most agents today pay on whatever chain the server lists first. At 10,000 payments per day, that's the difference between $0.10/day and $350/day in fees alone.

Routex fixes this. It evaluates fees across all available chains in real time and picks the cheapest one — automatically, on every single payment.


The x402 Protocol (Quick Primer)

x402 is an open protocol by Coinbase that enables HTTP-native payments. When a server wants payment, it returns:

HTTP/1.1 402 Payment Required
Enter fullscreen mode Exit fullscreen mode

The response body lists accepted chains, amounts, and recipient addresses. The client pays, attaches proof, and retries. Simple.

The problem: the 402 response often lists multiple chains. The client has to choose. Without a router, it guesses.


3 Lines to Optimal Routing

Install Routex and the chain adapters you need:

npm install @routexcc/core @routexcc/chain-base @routexcc/chain-solana
Enter fullscreen mode Exit fullscreen mode

Create a router:

import { createRouter, LocalFeeOracle } from '@routexcc/core';
import { createBaseAdapter } from '@routexcc/chain-base';
import { createSolanaAdapter } from '@routexcc/chain-solana';

const adapters = new Map([
  ['base', createBaseAdapter(viemClient)],
  ['solana', createSolanaAdapter(solanaConnection)],
]);

const feeOracle = new LocalFeeOracle({
  adapters,
  pollIntervalMs: 30_000,
  maxFeeAgeMs: 60_000,
});

const router = createRouter({
  adapters,
  feeOracle,
  strategy: 'cheapest',
  maxFeeAgeMs: 60_000,
});
Enter fullscreen mode Exit fullscreen mode

Route a payment:

const result = await router.route(paymentRequirement, signer);
console.log(result.chainId);  // 'solana' — cheapest right now
console.log(result.fee.feeUsd); // 250n — that's $0.00025
Enter fullscreen mode Exit fullscreen mode

That's it. Every route() call evaluates all chains, checks your balances, filters out anything ineligible, and returns the best option with a signed payload ready to submit.


How Much Do You Actually Save?

Here's what a $0.10 USDC transfer costs on each chain right now:

Chain Typical Fee Finality Cost per 10K payments/day
Stellar ~$0.00001 ~5s $0.10
Solana ~$0.00025 ~400ms $2.50
Base ~$0.003 ~2s $30
Polygon ~$0.0075 ~2s $75
Ethereum L1 ~$3.50 ~12s $35,000

Routex checks these fees every 30 seconds. When Solana congestion spikes and Base is cheaper, it routes to Base. When Base L1 fees surge, it routes to Stellar. Your agent always pays the minimum.

At scale, the savings are massive. An agent making 10,000 micropayments per day saves $30-70/day just by routing to the cheapest chain instead of a fixed one. Over a month, that's $900-2,100.


Drop-In x402 Middleware

Don't want to handle routing manually? Use the middleware:

import { routexMiddleware } from '@routexcc/x402';

const middleware = routexMiddleware({
  routeConfig: {
    adapters,
    feeOracle,
    strategy: 'cheapest',
    maxFeeAgeMs: 60_000,
  },
  signer: mySigner,
});

// When your HTTP client gets a 402:
const parsed = middleware.parseResponse(response.status, response.data);
if (parsed) {
  const { payload, chainId } = await middleware.handlePaymentRequired(parsed);
  // payload is ready — submit to the facilitator and retry the request
}
Enter fullscreen mode Exit fullscreen mode

The middleware intercepts 402 responses, routes the payment, and gives you back a signed payload. One integration point, all chains handled.


Four Routing Strategies

Not every agent optimizes for cost. Routex ships four strategies:

Cheapest — minimize fee in USD. Best for high-volume micropayments.

strategy: 'cheapest'
// score = 1 / (feeUsd + 0.0001)
Enter fullscreen mode Exit fullscreen mode

Fastest — minimize time to finality. Best for latency-sensitive agents.

strategy: 'fastest'
// score = 1 / (finalityMs + 1)
// Solana wins at ~400ms
Enter fullscreen mode Exit fullscreen mode

Balanced — 60% cost, 40% speed. Good default.

strategy: 'balanced'
// score = 0.6 * normFee + 0.4 * normFinality
Enter fullscreen mode Exit fullscreen mode

Custom — your own scoring function.

strategy: {
  type: 'custom',
  scorer: (options) => {
    // Prefer Base for compliance, fall back to cheapest
    return [...options].sort((a, b) => {
      if (a.chainId === 'base') return -1;
      if (b.chainId === 'base') return 1;
      return Number(a.fee.feeUsd - b.fee.feeUsd);
    });
  },
}
Enter fullscreen mode Exit fullscreen mode

Security: Non-Custodial by Design

Routex never touches your private keys. The entire architecture uses a Signer interface:

interface Signer {
  address: string;
  sign(data: Uint8Array): Promise<Uint8Array>;
  signTypedData?(typedData: Record<string, unknown>): Promise<string>;
}
Enter fullscreen mode Exit fullscreen mode

You provide a signer. Routex calls .sign() and gets back a signature. It never sees .privateKey, .secretKey, or .mnemonic. If you grep the entire codebase for these strings, you get zero results.

Other security guarantees:

  • All token amounts use bigint — no floating-point rounding errors
  • Every route() call is stateless — no mutable global state
  • Typed errors with context — never silent failures
  • Error messages never contain credentials or RPC keys
  • 10 security invariants, each annotated in code and tested

Try It in 5 Minutes

Clone the starter template:

git clone https://github.com/routexcc/x402-agent-starter.git
cd x402-agent-starter
pnpm install
cp .env.example .env
# Add your Base Sepolia RPC URL and testnet private key to .env

pnpm server   # Terminal 1 — starts a local 402 test server
pnpm agent    # Terminal 2 — runs the agent, pays via Routex
Enter fullscreen mode Exit fullscreen mode

The agent hits the test server, gets a 402, routes the payment through Routex, and pays on the cheapest chain. You'll see the chain selection, fee, and finality in the console output.


The Packages

Routex is modular — install only what you need:

Package What it does
@routexcc/core Router engine, strategies, fee oracle
@routexcc/chain-base Base L2 adapter
@routexcc/chain-solana Solana adapter
@routexcc/chain-stellar Stellar adapter
@routexcc/chain-polygon Polygon adapter
@routexcc/x402 x402 middleware wrapper

All packages are TypeScript-first (strict mode), dual CJS/ESM, and MIT licensed.


Links


Routex is open source (MIT) We'd love your feedback — open an issue or star the repo if this is useful.

Top comments (0)