Docs

Build with
Siro.

Every Siro resource is an HTTP endpoint that charges per call with x402 v2. There are no accounts and no API keys: the payment is the authentication.

  • Base URL: https://siro.pawww.sbs
  • Catalog: GET /v1/resources (free, JSON)
  • Call: POST /v1/<resource-id> with a JSON body
  • Pay: USDG on Robinhood Chain (eip155:4663), or USDC on Solana, Base (eip155:8453), Arbitrum (eip155:42161) or Polygon (eip155:137)

Quickstart

The shortest path is the SDK or the CLI. Below is the whole protocol by hand: Node 18+ or any modern runtime, with viem. Use a fresh wallet that holds only what your agent should spend.

// npm i viem
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.AGENT_KEY);
const CHAIN_ID = { "eip155:4663": 4663, "eip155:8453": 8453, "eip155:42161": 42161, "eip155:137": 137 };

async function call(id, body, network = "eip155:4663") {
  const url = `https://siro.pawww.sbs/v1/${id}`;
  const init = { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) };
  let res = await fetch(url, init);
  if (res.status !== 402) return res.json();

  const quote = await res.json();
  const req = quote.accepts.find((r) => r.network === network);
  const nonce = "0x" + crypto.getRandomValues(new Uint8Array(32)).reduce((s, b) => s + b.toString(16).padStart(2, "0"), "");
  const validBefore = BigInt(Math.floor(Date.now() / 1000) + 120);
  const signature = await account.signTypedData({
    domain: { name: req.extra.name, version: req.extra.version, chainId: CHAIN_ID[network], verifyingContract: req.asset },
    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" } ] },
    primaryType: "TransferWithAuthorization",
    message: { from: account.address, to: req.payTo, value: BigInt(req.amount), validAfter: 0n, validBefore, nonce },
  });
  const payment = { x402Version: 2, resource: quote.resource, accepted: req, payload: { signature,
    authorization: { from: account.address, to: req.payTo, value: req.amount, validAfter: "0", validBefore: String(validBefore), nonce } } };
  init.headers["PAYMENT-SIGNATURE"] = btoa(JSON.stringify(payment));
  res = await fetch(url, init);
  return res.json(); // { resource, result, receipt: { amountUsd, tx, network } }
}

const out = await call("market-brief", { network: "robinhood" });
console.log(out.result.brief, out.receipt.tx);

How x402 works

  1. Request. POST /v1/<id> with your JSON input. Input is validated first, so a bad request costs nothing.
  2. 402 quote. The response is 402 Payment Required. The body (and the base64 PAYMENT-REQUIRED header) lists accepts: one quote per network with amount (6 decimals), asset, payTo and the token's EIP-712 domain in extra.
  3. Sign. Sign an EIP-3009 transferWithAuthorization for exactly amount to payTo. Signing costs no gas. Send it base64-encoded in PAYMENT-SIGNATURE (the legacy X-PAYMENT header also works).
  4. Deliver. The facilitator verifies the signature, the resource runs, and only then the transfer settles on-chain. The response carries the result, a receipt and a base64 PAYMENT-RESPONSE header with the transaction hash.

Networks & assets

NetworkCAIP-2AssetContractEIP-712 domain
Robinhood Chaineip155:4663USDG0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168"Global Dollar", "1"
Solanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpUSDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1vextra.feePayer
Baseeip155:8453USDC0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"USD Coin", "2"
Arbitrum Oneeip155:42161USDC0xaf88d065e77c8cC2239327C5EDb3A432268e5831"USD Coin", "2"
Polygon PoSeip155:137USDC0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"USD Coin", "2"

Every asset uses 6 decimals, so a $0.005 call is amount: "5000" on any network. Payments are gasless for you on all of them: the facilitator pays the gas (Coinbase CDP on Solana, Base, Arbitrum and Polygon). On Solana the payload is { transaction }: a v0 transaction with SetComputeUnitLimit, SetComputeUnitPrice, a USDC TransferChecked and a Memo, signed by you, with the quote's extra.feePayer as fee payer and its signature left empty. The 402 lists every network a resource can be paid on right now; if you name no network in your payment, Robinhood Chain is assumed.

Endpoints

GET /v1/resourcesFull catalog: id, price, input fields, returns, networks. Free.
GET /v1/resources/:idOne resource. Free.
POST /v1/:idRun a resource. Answers 402 until paid.
GET /v1/payments?payer=0x…Settled payments for one payer (public on-chain data). Free.
GET /api/discover?q=…Search third-party x402 services in the open x402 Bazaar index. Payable ones (USDG on Robinhood Chain, USDC on Base) first. Free.
GET /api/tokens?network=…Swappable tokens: ETH, WETH, the stablecoin and, on Robinhood Chain, every stock token. Free.
GET /api/statsLive totals: resources, paid calls, volume. Free.

Errors & refunds

Errors look like {"error":{"code","message"}}. Siro settles a payment only after the resource succeeded, so there is nothing to refund: if the model, the chain or the page you asked for fails, the signed authorization is released and never executed.

400 missing_field / invalid_*Your input. Not charged.
402 verify_invalidSignature, amount, balance or network did not check out.
402 nonce_usedThat authorization was already used. Sign a new one.
422 fetch_failedThe link you gave could not be read. Not charged.
429 model_busyModel at capacity. Retry. Not charged.
502 *_failed / *_unavailableUpstream failure. Not charged.

Agent wallet

The Siro Wallet generates a key in your browser and stores it in local storage. The app signs payments with it inside your per-payment and daily caps, and swaps inside a per-swap cap. Siro's servers never receive the key. Export it to use the same wallet from code, and keep only a small balance on it.

CLI

The siro command keeps the agent key on your own machine, encrypted with your password (scrypt + AES-256-GCM in ~/.siro/keystore.json), and enforces the same caps before it signs anything.

# Node 20+
npm i -g https://siro.pawww.sbs/cli/siro.tgz
siro init                                  # new encrypted wallet; prints the EVM and Solana addresses to fund
siro limits --per-payment 0.1 --per-day 1 --per-swap 25
siro balance

siro call prediction-markets query="fed rates"
siro call stock-signal symbol=TSLA
siro call flux-2-dev prompt="a glossy silicon wafer" --out tile.png
siro discover weather                      # third-party x402 services
siro pay https://x402.agentindex.world/weather city=Jakarta
siro swap 0.01 ETH USDG                    # KyberSwap route, needs a little ETH for gas
siro history

Every payment and swap asks for confirmation unless you add --yes; the caps apply either way. --network base, arbitrum, polygon or solana pays in USDC on that network (swaps run on robinhood or base). Set SIRO_PASSWORD for scripts.

Solana. Every Siro wallet (web and CLI) also has a Solana address, derived from the same key, so one backup covers both. It pays x402 services that accept USDC on Solana: it signs a USDC transfer whose network fee the service's facilitator pays, so the wallet needs no SOL. siro export-key --solana (or Reveal Solana key in Wallet) gives the key in the form Phantom and Solflare import.

MCP server

Remote: https://siro.pawww.sbs/mcp (Streamable HTTP, no install). Browse the catalog, read resource schemas, discover third-party x402 services and list swappable tokens for free; siro_call runs a paid resource when params._meta["x402/payment"] carries a signed x402 payment, and otherwise returns the payment requirements. Listed in the official MCP Registry as com.siroagent/siro.

Local, with a wallet: siro mcp runs the same tools plus automatic payments and swaps from your encrypted local wallet, inside your caps, for Claude Desktop, Claude Code, Cursor and other MCP clients.

{
  "mcpServers": {
    "siro": {
      "command": "siro",
      "args": ["mcp"],
      "env": { "SIRO_PASSWORD": "your wallet password" }
    }
  }
}
siro_walletAddress, balances on both chains, caps, today's spend.
siro_resourcesThe Siro catalog with prices and input fields.
siro_callRun a resource and pay it, within the caps.
siro_discoverSearch third-party x402 services.
siro_payCall any x402 URL and pay it, within the caps.
siro_swap_quoteBest KyberSwap route for a trade.
siro_swapExecute a swap. Off until you run siro limits --mcp-swaps on; then capped per swap.
siro_historyRecent payments and swaps.

SDK

// npm i https://siro.pawww.sbs/cli/siro.tgz
import { Siro } from "siro";

const wm = new Siro({ privateKey: process.env.AGENT_KEY, limits: { perPayment: 0.05, perDay: 2 } });

const { result, receipt } = await wm.call("stock-signal", { symbol: "TSLA" });
const [svc] = await wm.discover("token price");
const paid = await wm.pay(svc.url, { method: svc.method, input: svc.input, network: "base" });
const quote = await wm.swapQuote("ETH", "USDG", "0.01");
await wm.swap(quote);

Pass approve: (a) => boolean to confirm each payment or swap, and ledger to persist spending for the daily cap. x402fetch(url, init, { signer }) pays any x402 v1 or v2 endpoint directly.

Discovery

Beyond its own catalog, Siro searches the open x402 Bazaar index (run by Coinbase CDP, tens of thousands of services) and pays any service that accepts the exact scheme in USDG on Robinhood Chain or USDC on Solana, Base, Arbitrum or Polygon. The Siro App does this on its own when no Siro resource fits: it finds a service, fills its input, and shows you the price before paying.

Third-party services are run by their owners, not by Siro. Their answers, prices and refund rules are theirs. In the browser, calls go through a narrow relay (POST /api/relay) that only forwards to services returned by discovery and never sees your key; the CLI, SDK and MCP server call them directly.

Swaps

Swaps route through the KyberSwap aggregator on Robinhood Chain and Base. The quote and the transaction are built on your device and sent from your wallet: an exact-amount approval when needed, then the swap with 1% maximum slippage by default. Swaps need a little ETH for gas, always ask before sending in the app, and are capped per swap. Siro takes no fee on swaps.

Resource catalog

ResourceEndpointPrice