Docs

Everything an agent, or the person setting one up, needs. Short on purpose: the router speaks standard MCP and standard x402, so most of this is the two addresses and the rules around them.

Quickstart: your agent

One package gives you a wallet on Hedera and Arc and a call that pays the 402 for you. Testnet keys; fund a wallet that exists only for this.

npm install onchainrouter
import { createWallet, pay } from "onchainrouter";

const wallet = createWallet({
  hedera: { accountId: "0.0.12345", privateKey: "0x..." },   // ECDSA key
  arc: { privateKey: "0x..." },                               // or a Circle wallet
  maxPerCall: { hbar: "0.2", usdc: "0.05" },                  // defaults
});

const { status, data, receipt } = await pay(
  "https://onchainrouter.io/api/tools/lending-rates",
  { asset: "USDC", chain: "base" },
  wallet,
);

data.assessment;        // the answer
receipt?.explorer;      // HashScan link on Hedera; Gateway transfer id on Arc

wallet.fetch is a drop-in fetch that pays 402s anywhere. walletFromEnv() reads the same keys from the environment. Over MCP instead: wrapMCPClientWithPayment(mcpClient, wallet.client) from @x402/mcp, connected to https://onchainrouter.io/mcp.

Quickstart: Claude Code

Claude Code cannot sign a payment, so it gets two MCP servers: the router, and a wallet that signs when a tool asks. Keys stay in your environment.

claude mcp add --transport http onchainrouter https://onchainrouter.io/mcp

claude mcp add onchain-wallet \
  -e HEDERA_AGENT_ACCOUNT_ID=0.0.12345 -e HEDERA_AGENT_PRIVATE_KEY=0x... \
  -e ARC_AGENT_PRIVATE_KEY=0x... \
  -- npx -y onchainrouter wallet

Then ask something the tools can answer: where should I lend USDC on base? Claude calls lending_rates, gets a payment-required result, hands it to sign_x402_payment, calls the tool again with the signature, and reads the answer. Three tool calls, no action from you. For Arc through a Circle agent wallet, pass the four CIRCLE_* variables instead of a key.

HTTP reference

Every tool is one endpoint. POST a JSON body; the response is JSON.

POST https://onchainrouter.io/api/tools/<slug>
GET  https://onchainrouter.io/api/tools            the catalogue, free
402Unpaid. PAYMENT-REQUIRED header carries base64 JSON with accepts: one entry per rail with network, amount (atomic units), asset, payTo.
200Paid and answered. Send the signed payment in PAYMENT-SIGNATURE (or X-PAYMENT). PAYMENT-RESPONSE on the reply carries the settlement receipt.
400Malformed input. Answered before the paywall; nothing to pay.
404Unknown tool, or a tool with no answer for this input: { answer: null, reason, charged: false }. Never settled.
502The tool or a facilitator failed. Never settled.

MCP reference

Streamable HTTP at https://onchainrouter.io/mcp, stateless. tools/list is free and returns every tool with its input schema. A paid call without a payment returns a result with isError: true whose structuredContent is the same payment-required object as the HTTP 402. Pass the signed payment back either in _meta["x402/payment"] (what @x402/mcp does) or as a payment argument (what a chat client does). The receipt comes back in _meta["x402/payment-response"].

submit_tool is also on the server, free: it probes an endpoint's 402 and returns a listing request. See Sell a tool.

Tools

6 tools, 0.1 HBAR or 0.01 USDC per call. Names below are the MCP names; the HTTP slug replaces underscores with dashes. Generated from the registry, so this is what is served.

lending_rates tool page

Best place to lend or borrow an asset, weighed against liquidity depth.

  • asset: Asset symbol, e.g. USDC or WETH.
  • chain: Chain to search. One of ethereum, arbitrum, bsc, avalanche, polygon, base, optimism, gnosis, scroll.
{"asset":"USDC","chain":"ethereum"}

governance_power tool page

How concentrated a protocol's voting power is, and how much of it never votes.

  • protocol: Protocol whose delegate table to measure. One of ampleforth, compound, cryptex, ens, euler, gitcoin, hifi, hop, ousd, pooltogether, radicle, rarible, reflexer, threshold, uniswap.
{"protocol":"uniswap"}

withdrawal_risk tool page

Whether a deposit can actually leave a lending market right now, and how much can.

  • asset: Asset symbol, e.g. USDC or WETH.
  • chain: Chain to search. One of ethereum, arbitrum, bsc, avalanche, polygon, base, optimism, gnosis, scroll.
  • amountUsd (optional): Withdrawal size in USD, to check whether it clears.
{"asset":"USDC","chain":"base","amountUsd":50000}

liquidation_pressure tool page

Whether borrowers against an asset are being liquidated right now, and how much room the terms leave.

  • asset: Asset symbol, e.g. WETH or USDC.
  • chain: Chain to search. One of ethereum, arbitrum, bsc, avalanche, polygon, base, optimism, gnosis, scroll.
{"asset":"USDC","chain":"base"}

protocol_health tool page

Whether a protocol is growing or draining, and whether it earns anything from what it holds.

  • protocol: Protocol name. One of aave-amm, aave-arc, aave-rwa, aave-v2, aave-v3, abracadabra, alpaca-finance-lending, banker-joe, bastion-protocol, benqi, burrow, compound-v2, compound-v3, cream-finance, dforce, euler-finance, geist-finance, goldfinch, inverse-finance, iron-bank, kinza-finance, liquity, makerdao, maple-finance-v1, maple-finance-v2, moonwell, morpho-aave-v2, morpho-aave-v3, morpho-compound, pac-finance, qidao, radiant-capital, rari-fuse, scream, seamless-protocol, seismic, sonne-finance, spark-lend, truefi, uwu-lend, venus, vesta-finance, zerolend.
  • chain: Chain the deployment runs on. One of ethereum, arbitrum, bsc, avalanche, polygon, base, optimism, gnosis, scroll.
{"protocol":"moonwell","chain":"base"}

governance_pulse tool page

Whether a protocol's governance is still deciding anything, and whether votes clear quorum.

  • protocol: Protocol whose proposal history to read. One of ampleforth, compound, cryptex, ens, euler, gitcoin, hifi, hop, ousd, pooltogether, radicle, rarible, reflexer, threshold, uniswap.
{"protocol":"ens"}

Sell a tool

Wrap a function in an x402 paywall on your own server. Both rails, your address in the 402, settlement straight to you. Return null when there is no answer and the caller is not charged.

import { paid } from "onchainrouter/server";

export const POST = paid(
  {
    price: { hbar: "0.1", usdc: "0.01" },
    payTo: { hedera: "0.0.12345", arc: "0xYourAddress" },
    description: "Liquidation risk for a lending position",
    parse: (body) => Input.parse(body),   // optional; throw to answer 400 unpaid
  },
  async (input) => {
    const result = await yourExistingLogic(input);
    if (!result) return null;
    return result;
  },
);

That is a Next.js route handler and a plain (Request) => Response for Hono, Bun, Workers or Express. Then list it: the submit page reads price, rails and payout off your 402 and opens a prefilled GitHub issue. Agents can do the same with submit_tool over MCP or POST https://onchainrouter.io/api/submit; both return the issue URL and the external() entry a pull request would add to lib/tools/registry.ts. Already on x402? Skip the wrapper; the router relays your endpoint as is. Endpoints quoting only some other network are refused, since nothing here could pay them.

Rails and prices

Hedera testnethedera:testnet · 0.1 HBAR per call · Blocky402 facilitator, which also sponsors the gas. Gas sponsored.
Arc testneteip155:5042002 · 0.01 USDC per call · Circle Gateway, gasless from a deposited balance. Gasless.

One 402 offers both; the client pays on whichever it holds. Testnet only for now. Hedera pays in native HBAR (no token association needed); Arc pays USDC from a Circle Gateway balance, batched, so the receipt is a transfer id rather than a per-payment transaction hash. Spend caps in the client default to 0.2 HBAR and 0.05 USDC per payment.

Funding a wallet

This is the part that takes time. Do it once, in a wallet used for nothing else.

Hedera

  1. portal.hedera.com: create a testnet account, ECDSA key type. It comes with test HBAR.
  2. Set HEDERA_AGENT_ACCOUNT_ID and HEDERA_AGENT_PRIVATE_KEY. Gas is sponsored by the facilitator; the balance only pays the price.

Arc

  1. An EVM key (ARC_AGENT_PRIVATE_KEY), or a Circle developer-controlled wallet on ARC-TESTNET (EOA, not SCA) via CIRCLE_API_KEY, CIRCLE_ENTITY_SECRET, CIRCLE_WALLET_ID, CIRCLE_WALLET_ADDRESS.
  2. Test USDC from faucet.circle.com (Arc Testnet) to that address.
  3. Deposit once into Circle Gateway (0x0077777d7EBA4688BDeF3E311b846F25870A19B9); payments draw on that balance, gasless. The repo has npm run arc:deposit for this.

Rules

  • The agent pays with its own wallet. The router holds no keys and no funds. The playground is the one exception: a capped wallet we fund so the product can be tried without one.
  • No answer, no charge. A 4xx on HTTP or isError on MCP is never settled.
  • 0% commission. The 402 names the author's address; money goes agent to author.
  • Two rails. Hedera and Arc, testnet. Listings on other networks are refused.
  • Coverage is measured. npm run probe records which subgraphs answer; the catalogue reads from that.

Source and issues: github.com/web3xDev/onchainrouter. For agents, the same in one file: /llms.txt.