Agent Margin Router
by NovaNest
checking…
x402 · Base · USDC / USDT · from $0.01 / request

Agent Margin RouterData infrastructure for autonomous AI agents

Web search & extraction, PDF text, SEO, e-mail & DNS checks, market data, gas fees, DeFi yields, wallet balances and more — 16 endpoints routed across multiple providers and settled instantly with x402 micropayments in USDC or USDT on Base. No API keys, no invoices, no accounts — just HTTP and a wallet.

Daten-Infrastruktur für autonome KI-Agenten — bezahlt pro Anfrage, ohne Vertrag, ohne API-Key.

per request
$0.01+
requests / wallet
3 free
endpoints
16
terminal — first call, free tier
curl -s -X POST https://agent-margin-router-production.up.railway.app/market-spread \  -H "Content-Type: application/json" \  -H "X-WALLET: 0xYourAgentWallet" \  -d '{"asset": "ethereum", "buy_venue": "binance", "sell_venue": "coinbase"}'
→ 200 OK · ~700 ms · provider: coingeckofree 2/3 remaining
How it works

Three HTTP round-trips. Zero onboarding.

x402 turns the HTTP 402 status code into a machine-native payment rail. Your agent never leaves the request loop.

So funktioniert's: Anfrage → Zahlung → Daten. Keine Registrierung, kein Vertrag.

01

Request

Your agent calls an endpoint over plain HTTPS with a JSON body. No signup, no API key.

POST /extract-clean
02

x402 Payment

The API answers 402 with exact payment terms. The agent signs a $0.01–$0.05 USDC or USDT transfer on Base and retries with the X-PAYMENT header.

402 → X-PAYMENT: <payload>
03

Data Response

The facilitator verifies the payment, the router picks the healthiest provider and returns strict JSON — with provenance and billing metadata.

200 OK · application/json

Free tier: 3 requests per wallet — no payment required

Identify your agent with an X-WALLET: 0x… header and the first 3 calls skip the 402 step entirely. Once exhausted, the API switches to pay-per-use from $0.01 per request. Perfect for integration tests and CI.

Free-Tier: 3 kostenlose Anfragen pro Wallet, danach ab $0.01 pro Request.

Read the auth flow
Endpoints

Sixteen production endpoints. From $0.01.

Flat per-endpoint pricing from $0.01 to $0.05 per successful request, regardless of provider or payload size. Failed requests (4xx/5xx) are never charged.

Sechzehn Endpunkte ab 0,01 $ pro erfolgreicher Anfrage. Fehler werden nie berechnet.

POST/extract-clean

Web Extraction

Fetch any public URL and return clean, selector-scoped text as strict JSON. Rendered via Apify Web Scraper for JS-heavy pages; falls back to a direct httpx fetch when the page is static or the primary is degraded.

Saubere Web-Extraktion per CSS-Selektor als striktes JSON — mit automatischem Fallback.

  • CSS selectors → arrays of text
  • JS rendering via Apify
  • Automatic httpx fallback
  • Provenance & latency in meta
Price
$0.02
USDC / USDT
Latency
p50 ≈ 1.8 s
typical
Providers
apifyhttpx_direct
/extract-clean · request
{  "url": "https://example.com",  "selectors": ["h1", ".price"]}
POST/market-spread

DeFi / CEX Spread Analysis

Compare an asset’s price between two venues and receive gross spread, estimated fees, slippage, net spread in bps and an execution-risk score. CoinGecko primary, CoinMarketCap fallback — with confidence weighting.

Spread-Analyse zwischen zwei Handelsplätzen inkl. Gebühren, Slippage und Risiko-Score.

  • Gross / net spread in bps
  • Fee & slippage estimate
  • Confidence + execution risk
  • Multi-provider price feed
Price
$0.05
USDC / USDT
Latency
p50 ≈ 0.7 s
typical
Providers
coingeckocoinmarketcap
/market-spread · request
{  "asset": "ethereum",  "buy_venue": "binance",  "sell_venue": "coinbase"}
POST/gas-fees

Gas Fees (EIP-1559)

Live base fee, gas price and slow / standard / fast tiers for Base, Ethereum, Arbitrum, Optimism and Polygon — plus the USD cost of a transfer, approve, swap or mint per tier. Read straight from public RPC with automatic fallback nodes.

Live-Gaspreise mit Slow/Standard/Fast-Stufen und USD-Kosten pro Transaktionstyp für 5 Chains.

  • 5 chains: base · ethereum · arbitrum · optimism · polygon
  • EIP-1559 tiers + trend
  • USD cost per tx type
  • Public RPC, no API key
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.3 s
typical
Providers
public RPCbinancecoinbase
/gas-fees · request
{  "chain": "base"}
POST/token-price

Token Price (multi-venue median)

One manipulation-resistant price per asset: median over Binance, Coinbase, Kraken and CoinGecko with min / max, deviation between venues, 24h change and per-venue bid / ask / volume. Failed venues are reported, never silently dropped.

Manipulationsresistenter Median-Preis über 4 Handelsplätze inkl. Abweichung und 24h-Änderung.

  • Median over 4 venues
  • Deviation & min / max
  • Bid / ask / volume per venue
  • Failed sources reported
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.4 s
typical
Providers
binancecoinbasekrakencoingecko
/token-price · request
{  "asset": "ETH",  "quote": "USD"}
POST/wallet-balance

Wallet Balance (native + stablecoins)

Native token plus USDC, USDT, DAI and WETH balances for any address on 5 chains, each with raw units, decimals, contract and USD value — and a total. Ideal for agents that must check spending power before acting.

Native- und Stablecoin-Guthaben einer Adresse mit USD-Bewertung und Gesamtsumme.

  • ETH + USDC / USDT / DAI / WETH
  • USD value per token + total
  • Batched RPC, one round-trip
  • Any address, 5 chains
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.5 s
typical
Providers
public RPCbinancecoinbase
/wallet-balance · request
{  "address": "0xf7a181bbe5d29924e800df4ba93418ef94f4e7c2",  "chain": "base"}
POST/web-search

Web Search (ranked, deduplicated)

Live web results for any query: ranked title, URL, domain and snippet, deduplicated and region-aware. No API key, no browser — one POST and the agent has citable sources.

Live-Websuche mit Rang, URL, Domain und Snippet — ohne eigenen Such-API-Key.

  • Up to 20 ranked results
  • Title / URL / domain / snippet
  • Region selectable (wt-wt default)
  • Short cache, always fresh
Price
$0.02
USDC / USDT
Latency
p50 ≈ 0.8 s
typical
Providers
duckduckgo
/web-search · request
{  "query": "x402 payment protocol",  "max_results": 3,  "region": "wt-wt"}
POST/email-validate

Email Validation (syntax + MX + risk)

Syntax check, disposable-domain and free-provider detection, role-account flag, live MX lookup and a 0-100 deliverability score with a single verdict: deliverable, risky, undeliverable, disposable or invalid.

Syntax, Wegwerf-Domains, MX-Check und Zustellbarkeits-Score mit klarem Verdict.

  • Live MX lookup
  • Disposable & role detection
  • Score 0-100 + verdict
  • Batch-friendly, ~30 ms
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.05 s
typical
Providers
DNS over HTTPS
/email-validate · request
{  "email": "[email protected]",  "check_mx": true}
POST/dns-whois

DNS + WHOIS (RDAP)

Any record types (A, AAAA, MX, NS, TXT, CNAME, SOA, CAA) with TTLs plus registrar, status, creation / expiry dates, nameservers and DNSSEC from the authoritative RDAP source. Per-type errors are reported, never hidden.

DNS-Records mit TTL plus Registrar, Ablaufdatum und DNSSEC aus der offiziellen RDAP-Quelle.

  • 8 record types with TTL
  • Registrar / created / expires
  • Nameservers & DNSSEC
  • Per-type error map
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.35 s
typical
Providers
DNS over HTTPSRDAP
/dns-whois · request
{  "domain": "x402.org",  "record_types": ["A", "MX", "NS"],  "include_whois": true}
POST/pdf-text

PDF Text Extraction

Fetch any public PDF up to 25 MB and return clean text per page plus a joined body, page counts, word counts and document metadata. Select specific pages or cap the page count to control context-window usage.

Öffentliche PDFs in sauberen Text pro Seite umwandeln — inkl. Metadaten und Seitenauswahl.

  • Up to 25 MB / 200 pages
  • Per-page + joined text
  • Page selection & caps
  • Metadata included
Price
$0.02
USDC / USDT
Latency
p50 ≈ 0.3 s
typical
Providers
httpxpypdf
/pdf-text · request
{  "url": "https://arxiv.org/pdf/1706.03762v7",  "max_pages": 2}
POST/seo-check

SEO Check (score + graded issues)

One-shot technical SEO audit of any URL: status and redirects, HTTPS, load time, title / description lengths, canonical, headings, images without alt, link counts, Open Graph, JSON-LD, robots.txt and sitemap — condensed into a 0-100 score, a letter grade and a prioritised issue list.

Technischer SEO-Audit einer URL mit Score, Note und priorisierter Problemliste.

  • Score 0-100 + grade A-F
  • Prioritised issue list
  • OG / JSON-LD / robots / sitemap
  • Headings, images, links
Price
$0.03
USDC / USDT
Latency
p50 ≈ 1 s
typical
Providers
httpx
/seo-check · request
{  "url": "https://example.com",  "check_robots": true}
POST/defi-yields

DeFi Yields (filtered pool screener)

Screen thousands of DeFi pools by chain, asset, protocol, minimum TVL and stablecoin-only — returns APY (base / reward / 30-day mean), TVL, impermanent-loss risk and exposure per pool, sorted by APY. Built for treasury and yield agents that need a shortlist, not a data dump.

DeFi-Pool-Screener nach Chain, Asset, Protokoll, TVL und Stablecoin-Filter — sortiert nach APY.

  • Chain / asset / project filters
  • APY base, reward, 30d mean
  • TVL + IL-risk per pool
  • Stablecoin-only mode
Price
$0.02
USDC / USDT
Latency
p50 ≈ 0.7 s
typical
Providers
DefiLlama
/defi-yields · request
{  "chain": "Base",  "stablecoins_only": true,  "min_tvl_usd": 1000000,  "limit": 5}
POST/currency-convert

Currency Convert (ECB reference rates)

Convert one amount into up to 10 target currencies in a single call using official ECB reference rates — returns the raw rates, the converted amounts and the rate date. Ideal for invoicing, pricing and reporting agents that must show a defensible source.

Betrag in bis zu 10 Zielwährungen umrechnen — offizielle EZB-Referenzkurse mit Kursdatum.

  • 30+ fiat currencies
  • Up to 10 targets per call
  • Rate date included
  • ECB reference source
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.2 s
typical
Providers
Frankfurter / ECB
/currency-convert · request
{  "amount": 250,  "from": "EUR",  "to": ["USD", "GBP", "JPY"]}
POST/geo-ip

Geo-IP Lookup

Geolocate any IPv4 / IPv6 address: country, region, city, postal code, coordinates, timezone with UTC offset, ASN, organisation, ISP and EU flag — with automatic provider fallback. Useful for routing, fraud checks, localisation and compliance decisions.

IP-Geolokation mit Land, Stadt, Koordinaten, Zeitzone, ASN und Provider — inkl. Fallback.

  • IPv4 + IPv6
  • Timezone + UTC offset
  • ASN / org / ISP
  • Provider fallback
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.2 s
typical
Providers
ipwho.isip-api
/geo-ip · request
{  "ip": "8.8.8.8"}
POST/rss-feed

RSS / Atom Feed → JSON

Fetch any RSS 2.0 or Atom feed and return normalised items — title, link, ISO timestamp, author, summary and optionally full content — plus feed metadata and counts. Lets monitoring and research agents watch sources without parsing XML themselves.

RSS-/Atom-Feeds als normalisiertes JSON — Titel, Link, Zeitstempel, Autor, Zusammenfassung.

  • RSS 2.0 + Atom
  • ISO-8601 timestamps
  • Optional full content
  • Item caps 1-100
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.4 s
typical
Providers
httpx
/rss-feed · request
{  "url": "https://hnrss.org/frontpage",  "max_items": 5,  "include_content": false}
POST/crypto-ohlcv

Crypto OHLCV Candles

Historical candles for any major crypto pair at 1m to 1w intervals (up to 500 per call) with a ready-made summary: first open, last close, period high / low / volume and percentage change. Binance primary, Coinbase fallback — no exchange keys needed.

Historische Kerzen (1m–1w, bis 500) mit Zusammenfassung — Binance primär, Coinbase-Fallback.

  • Intervals 1m – 1w
  • Up to 500 candles
  • Summary block included
  • Exchange fallback
Price
$0.02
USDC / USDT
Latency
p50 ≈ 0.3 s
typical
Providers
BinanceCoinbase
/crypto-ohlcv · request
{  "symbol": "ETH",  "quote": "USDT",  "interval": "1h",  "limit": 24}
POST/ens-resolve

ENS Resolve (name → address + records)

Resolve an ENS name on Ethereum mainnet to its address plus selected text records (url, com.twitter, avatar, email …) via direct on-chain calls with multi-RPC fallback. Returns namehash and resolver so payment agents can verify before they send.

ENS-Namen on-chain zu Adresse und Text-Records auflösen — mit Multi-RPC-Fallback.

  • On-chain, no indexer
  • Text records (up to 8 keys)
  • Namehash + resolver
  • Multi-RPC fallback
Price
$0.01
USDC / USDT
Latency
p50 ≈ 0.4 s
typical
Providers
Ethereum RPC
/ens-resolve · request
{  "name": "vitalik.eth",  "text_keys": ["url", "com.twitter", "avatar"]}
API Documentation

API Reference

Base URL: https://agent-margin-router-production.up.railway.app — all endpoints speak JSON over HTTPS. Content-Type: application/json.

Vollständige API-Referenz: Authentifizierung, Schemas, Fehlercodes, Beispiele in Python und cURL.

Code samples

Overview

Base URL
https://agent-margin-router-production.up.railway.app
Protocol
HTTPS · JSON request & response bodies
Payment
x402 · $0.01 – $0.05 per successful request (flat per endpoint)
Tokens
USDC or USDT on Base (chain id 8453)
Free tier
3 requests per wallet via X-WALLET header
Rate limit
Anonymous: 10 req/min per IP · with X-WALLET or payment: no per-minute cap · API key: 100 req/min

All responses include provider, fetched_at and latency_ms for provenance. Cached results are served from Redis for up to 60 s and are marked with X-Cache: HIT. Cached hits are still billed at the same price.

Authentication — x402 payment flow

There are no API keys. Access is granted by payment. The protocol is x402: the server replies 402 Payment Required with the exact terms; the client signs an EIP-3009 transferWithAuthorization for USDC or USDT on Base and resends the request with the signed payload base64-encoded in X-PAYMENT. Verification and settlement are performed by the PayAI x402 facilitator (facilitator.payai.network); the v2 header names PAYMENT-SIGNATURE / PAYMENT-RESPONSE are accepted as aliases.

  1. step 1
    Probe
    POST without payment → 402 + accepts[]
  2. step 2
    Pay
    Sign transfer for maxAmountRequired to payTo
  3. step 3
    Retry
    Same request + X-PAYMENT header → 200 + data
402 response — payment requirements
HTTP/1.1 402 Payment RequiredContent-Type: application/json {  "x402Version": 1,  "error": "Payment required",  "accepts": [    {      "scheme": "exact",      "network": "base",      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",      "symbol": "USDC",      "maxAmountRequired": "50000",      "payTo": "0xf7a181bbe5d29924e800df4ba93418ef94f4e7c2",      "resource": "/extract-clean",      "maxTimeoutSeconds": 60    },    {      "scheme": "exact",      "network": "base",      "asset": "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",      "symbol": "USDT",      "maxAmountRequired": "50000",      "payTo": "0xf7a181bbe5d29924e800df4ba93418ef94f4e7c2",      "resource": "/extract-clean",      "maxTimeoutSeconds": 60    }  ],  "free_tier": {    "remaining": 0,    "hint": "Send X-WALLET header to use 3 free requests per wallet"  }}
Headers
  • X-PAYMENT — request; base64 JSON of the signed x402 payload.
  • X-WALLET — request; EVM address to claim the free tier.
  • X-PAYMENT-RESPONSE — response; base64 settlement receipt incl. tx hash.
  • X-Free-Remaining — response; free requests left for the wallet.
Payment constants
  • network base (8453)
  • amount 10000 – 50000 (= $0.01 – $0.05, 6 decimals — see 402 body)
  • payTo 0xf7a181bbe5d29924e800df4ba93418ef94f4e7c2
  • USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
  • USDT 0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2
  • facilitator https://facilitator.payai.network/verify
Free tier — Python
free_tier.py
import httpx # 3 free requests per wallet — identify yourself with X-WALLETr = httpx.post(    "https://agent-margin-router-production.up.railway.app/extract-clean",    headers={"X-WALLET": "0xYourWalletAddress"},    json={"url": "https://example.com", "selectors": ["h1"]},)print(r.status_code, r.json())
Manual x402 flow (without SDK)
manual_x402.py
import base64, json, httpx API = "https://agent-margin-router-production.up.railway.app"body = {"asset": "ethereum", "buy_venue": "binance", "sell_venue": "coinbase"} # 1) Probe → 402 with payment requirementsr = httpx.post(f"{API}/market-spread", json=body)assert r.status_code == 402req = r.json()["accepts"][0]          # pick USDC (or [1] for USDT) # 2) Sign an EIP-3009 transferWithAuthorization for req["maxAmountRequired"]#    to req["payTo"] on Base (see x402 spec) → payload dictpayload = sign_x402_payment(req)      # your wallet logic / x402 SDK # 3) Retry with X-PAYMENT headerr = httpx.post(    f"{API}/market-spread",    json=body,    headers={"X-PAYMENT": base64.b64encode(json.dumps(payload).encode()).decode()},)print(r.status_code, r.json())print("settlement:", r.headers.get("X-PAYMENT-RESPONSE"))
GET

/health

Public, unauthenticated, never billed. Returns service status, per-provider health, Redis connectivity and uptime. Poll it from your orchestrator before dispatching paid requests; returns 503 when degraded.

Try it live— calls the production API from your browser
request
curl -s https://agent-margin-router-production.up.railway.app/health | jq
200 response
{  "status": "ok",  "version": "1.0.0",  "uptime_seconds": 864213,  "redis": "connected",  "providers": {    "apify": "healthy",    "coingecko": "healthy",    "coinmarketcap": "healthy",    "httpx_direct": "healthy"  },  "payment": {    "network": "base",    "accepted": ["USDC", "USDT"],    "price_per_request": "0.01-0.05"  }}
POST

/extract-clean

Extracts selector-scoped text from a URL. Payment required (or free tier). Price: $0.02. Timeout: 45 s. Response bodies larger than 1 MB are truncated per selector with meta.truncated = true.

Request body
urlrequiredstring (https)Publicly reachable URL to extract from. Max 2048 chars.
selectorsstring[]CSS selectors. Each selector maps to an array of text values. Default: ["body"]. Max 20.
request body
{  "url": "https://example.com",  "selectors": ["h1", ".price"]}
200 response
{  "url": "https://example.com",  "provider": "apify",  "fetched_at": "2026-09-10T14:02:11Z",  "latency_ms": 1840,  "data": {    "h1": ["Example Domain"],    ".price": []  },  "meta": {    "status_code": 200,    "content_type": "text/html",    "fallback_used": false  },  "billing": {    "charged": "0.05",    "token": "USDC",    "network": "base",    "tx_hash": "0x9c1f…e2a4"  }}
Response fields
datarequiredobject<string, string[]>Selector → array of trimmed text content.
providerrequired"apify" | "httpx_direct"Provider that served this response.
meta.fallback_usedrequiredbooleanTrue if the primary provider was unavailable.
fetched_atrequiredISO-8601Source timestamp (UTC).
latency_msrequirednumberUpstream fetch latency.
billingobjectPresent on paid calls: charged, token, network, tx_hash.
extract.py
# pip install x402 httpx eth-accountimport httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks BASE_URL = "https://agent-margin-router-production.up.railway.app" # Agent wallet holding USDC or USDT on Baseaccount = Account.from_key("0x<AGENT_PRIVATE_KEY>") # The hook transparently handles the 402 → pay → retry loopclient = httpx.Client(    base_url=BASE_URL,    event_hooks=x402_payment_hooks(account),    timeout=60,) resp = client.post(    "/extract-clean",    json={"url": "https://example.com", "selectors": ["h1", ".price"]},)resp.raise_for_status()print(resp.json()["data"])
POST

/market-spread

Computes the price spread of an asset between two venues with fee/slippage adjustment and a risk score. Payment required (or free tier). Price: $0.05. Quotes are at most 60 s old.Not financial advice. Spreads exclude transfer time and gas; there is no risk-free arbitrage.

Request body
assetrequiredstringCoinGecko asset id, e.g. "ethereum", "bitcoin", "solana".
buy_venuerequiredstringExchange id where the asset is bought, e.g. "binance".
sell_venuerequiredstringExchange id where the asset is sold, e.g. "coinbase".
request body
{  "asset": "ethereum",  "buy_venue": "binance",  "sell_venue": "coinbase"}
200 response
{  "asset": "ethereum",  "buy_venue": "binance",  "sell_venue": "coinbase",  "buy_price": 3412.18,  "sell_price": 3416.92,  "gross_spread_bps": 13.9,  "fees_bps": 10.0,  "slippage_bps": 2.5,  "estimated_net_spread_bps": 1.4,  "confidence": 0.81,  "execution_risk": "high",  "provider": "coingecko",  "fetched_at": "2026-09-10T14:02:15Z",  "billing": {    "charged": "0.05",    "token": "USDT",    "network": "base"  }}
Response fields
buy_price / sell_pricerequirednumber (USD)Latest quotes per venue.
gross_spread_bpsrequirednumberRaw price difference in basis points.
fees_bps / slippage_bpsrequirednumberEstimated taker fees and slippage for a reference size.
estimated_net_spread_bpsrequirednumberGross minus fees and slippage. Can be negative.
confidencerequirednumber 0–1Cross-provider agreement and data freshness.
execution_riskrequired"low" | "medium" | "high"Heuristic based on liquidity, spread size and staleness.
spread.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),) spread = client.post(    "/market-spread",    json={"asset": "ethereum", "buy_venue": "binance", "sell_venue": "coinbase"},).json() if spread["estimated_net_spread_bps"] > 5 and spread["confidence"] > 0.7:    print("opportunity:", spread)
POST

/gas-fees

Live EIP-1559 gas data for 5 EVM chains with slow / standard / fast tiers and the USD cost of common transaction types. Read from public RPC with automatic node fallback. Payment required (or free tier). Price: $0.01. Freshness ≤ 10 s by default.

Request body
chainstring"base" (default) | "ethereum" | "arbitrum" | "optimism" | "polygon".
max_age_secondsinteger 0–300Accept a cached reading up to this age. Default 10.
request body
{  "chain": "base"}
200 response
{  "chain": "base",  "chain_id": 8453,  "native_token": "ETH",  "native_price_usd": 2609.97,  "block_number": 51175271,  "base_fee_gwei": 0.005,  "gas_price_gwei": 0.006,  "trend": "low",  "tiers": {    "slow":     { "max_fee_gwei": 0.0051, "cost_usd": { "erc20_transfer": 0.00087, "swap": 0.0024 } },    "standard": { "max_fee_gwei": 0.0062, "cost_usd": { "erc20_transfer": 0.00105, "swap": 0.0029 } },    "fast":     { "max_fee_gwei": 0.0081, "cost_usd": { "erc20_transfer": 0.00138, "swap": 0.0038 } }  },  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "onchain", "cache_hit": false, "latency_ms": 312 }}
Response fields
base_fee_gwei / gas_price_gweirequirednumberCurrent EIP-1559 base fee and legacy gas price of the latest block.
trendrequired"low" | "normal" | "high"Base fee relative to the recent fee history.
tiers.{slow,standard,fast}requiredobjectmax_priority_fee_gwei, max_fee_gwei and cost_usd per tx type (native_transfer, erc20_transfer, erc20_approve, swap, nft_mint).
native_price_usdrequirednumberNative token price used for USD conversion (multi-venue median).
block_numberrequiredintegerBlock the reading was taken from.
gas.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),) gas = client.post("/gas-fees", json={"chain": "base"}).json()swap_cost = gas["tiers"]["standard"]["cost_usd"]["swap"]if swap_cost < 0.01:    print("cheap block — execute swap now", gas["tiers"]["standard"])
POST

/token-price

Median price across Binance, Coinbase, Kraken and CoinGecko with min / max, inter-venue deviation and 24h change. Failed venues are listed in sources_failed instead of being dropped. Payment required (or free tier). Price: $0.01. Freshness ≤ 5 s by default.

Request body
assetrequiredstringTicker, e.g. "ETH", "BTC", "SOL". Case-insensitive.
quotestringQuote currency. Default "USD".
venuesstring[]Subset of binance, coinbase, kraken, coingecko. Default: all four.
max_age_secondsinteger 0–300Accept a cached quote up to this age. Default 5.
request body
{  "asset": "ETH",  "quote": "USD"}
200 response
{  "asset": "ETH",  "quote": "USD",  "price": 2609.57,  "price_min": 2607.52,  "price_max": 2609.82,  "max_deviation_pct": 0.078,  "change_24h_pct": 6.99,  "sources": [    { "venue": "binance",   "price": 2609.82, "pair": "ETH/USDT", "volume_24h_usd": 1411339492 },    { "venue": "coinbase",  "price": 2609.77, "pair": "ETH/USD" },    { "venue": "kraken",    "price": 2609.36, "pair": "ETH/USD" },    { "venue": "coingecko", "price": 2607.52, "pair": "ETH/USD" }  ],  "sources_failed": {},  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "onchain", "cache_hit": false, "latency_ms": 420 }}
Response fields
pricerequirednumberMedian across all responding venues.
price_min / price_max / max_deviation_pctrequirednumberSpread between venues — reject when deviation is too high.
change_24h_pctrequirednumber | null24h change (from venues that report it).
sources[]requiredobject[]Per venue: price, bid, ask, volume_24h_usd, pair.
sources_failedrequiredobject<string, string>Venues that failed with the error reason. Never silently dropped.
token_price.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),) quote = client.post("/token-price", json={"asset": "ETH", "quote": "USD"}).json() # Median across 4 venues — reject if venues disagree too muchif quote["max_deviation_pct"] < 0.5:    print("ETH/USD", quote["price"], "from", len(quote["sources"]), "venues")
POST

/wallet-balance

Native token plus USDC, USDT, DAI and WETH balances for any address on 5 chains, USD-valued and totalled. One batched RPC round-trip. Payment required (or free tier). Price: $0.01.

Request body
addressrequiredstring (0x…)EVM address to inspect (40 hex chars).
chainstring"base" (default) | "ethereum" | "arbitrum" | "optimism" | "polygon".
max_age_secondsinteger 0–300Accept a cached reading up to this age.
request body
{  "address": "0xf7a181bbe5d29924e800df4ba93418ef94f4e7c2",  "chain": "base"}
200 response
{  "address": "0xf7a181bbe5d29924e800df4ba93418ef94f4e7c2",  "chain": "base",  "chain_id": 8453,  "block_number": 51175277,  "balances": {    "ETH":  { "balance": 0.0,      "decimals": 18, "contract": null, "usd": 0.0 },    "USDC": { "balance": 6.274089, "decimals": 6,  "contract": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "usd": 6.27 },    "USDT": { "balance": 6.211248, "decimals": 6,  "contract": "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2", "usd": 6.21 }  },  "total_usd": 12.49,  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "onchain", "cache_hit": false, "latency_ms": 740 }}
Response fields
balances.{ETH,USDC,USDT,DAI,WETH}requiredobjectbalance (decimal), raw (integer string), decimals, contract, usd.
total_usdrequirednumberSum of all USD-valued balances.
block_numberrequiredintegerBlock the balances were read at (single batched RPC round-trip).
wallet.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),) # Let the agent check its own spending power before a taskbal = client.post(    "/wallet-balance",    json={"address": account.address, "chain": "base"},).json() if bal["total_usd"] < 1.0:    raise SystemExit("top up USDC/USDT on Base before continuing")print("stablecoins available:", bal["total_usd"], "USD")
POST

/email-validate

Syntax, disposable / free-provider / role detection, live MX lookup and a 0–100 deliverability score condensed into one verdict. Payment required (or free tier). Price: $0.01.

Request body
emailrequiredstringAddress to validate.
check_mxbooleanPerform a live MX lookup (default true).
request body
{  "email": "[email protected]",  "check_mx": true}
200 response
{  "email": "[email protected]",  "local_part": "jane.doe",  "domain": "github.com",  "valid_syntax": true,  "disposable": false,  "free_provider": false,  "role_account": false,  "mx_checked": true,  "has_mx": true,  "mx_records": [    { "priority": 1, "exchange": "github-com.mail.protection.outlook.com", "ttl": 3600 }  ],  "domain_resolves": true,  "deliverability_score": 95,  "verdict": "deliverable",  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "webtools", "cache_hit": false, "latency_ms": 34 }}
Response fields
valid_syntax / disposable / free_provider / role_accountrequiredbooleanSyntax check, disposable-domain list, free mailbox provider, role mailbox (info@, admin@ …).
has_mx / mx_records[] / domain_resolvesrequiredboolean / object[]Live MX records (priority, exchange, ttl) and whether the domain resolves at all.
deliverability_scorerequiredinteger 0–100Composite deliverability score.
verdictrequiredstring"deliverable" | "risky" | "undeliverable" | "disposable" | "invalid" | "unknown".
email_validate.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Clean a lead list before the outreach agent sends anythingfor email in ["[email protected]", "[email protected]"]:    v = client.post("/email-validate", json={"email": email}).json()    print(email, v["verdict"], v["deliverability_score"])
POST

/dns-whois

DNS records with TTLs for up to 8 record types plus registrar, status, created / expires, nameservers and DNSSEC from the authoritative RDAP source. Payment required (or free tier). Price: $0.01.

Request body
domainrequiredstringDomain name; scheme and path are stripped automatically.
record_typesstring[] ≤ 8A, AAAA, MX, NS, TXT, CNAME, SOA, CAA (default: A, AAAA, MX, NS, TXT, CNAME).
include_whoisbooleanAdd registration data via RDAP (default true).
max_age_secondsinteger 0–3600Accept a cached lookup up to this age (default 300).
request body
{  "domain": "x402.org",  "record_types": ["A", "MX", "NS"],  "include_whois": true}
200 response
{  "domain": "x402.org",  "records": {    "A":  [ { "ttl": 300,   "data": "104.18.10.192" }, { "ttl": 300, "data": "104.18.11.192" } ],    "MX": [ { "ttl": 3600,  "data": "10 mx1.forwardemail.net.", "priority": 10, "exchange": "mx1.forwardemail.net" } ],    "NS": [ { "ttl": 86400, "data": "dolly.ns.cloudflare.com." }, { "ttl": 86400, "data": "rayden.ns.cloudflare.com." } ]  },  "whois": {    "registered": true,    "registrar": "Key-Systems GmbH",    "registrar_iana_id": "269",    "status": ["client transfer prohibited"],    "created": "2025-02-20T17:31:14.067Z",    "updated": "2026-08-12T09:36:44.39Z",    "expires": "2029-02-20T17:31:14.067Z",    "dnssec": false,    "source": "rdap.publicinterestregistry.org"  },  "errors": {},  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "webtools", "cache_hit": false, "latency_ms": 339 }}
Response fields
recordsrequiredobject<TYPE, object[]>Per record type: ttl, data (+ priority / exchange for MX).
whoisrequiredobject | nullregistered, registrar, registrar_iana_id, status[], created, updated, expires, nameservers[], dnssec, source.
errorsrequiredobject<TYPE, string>Record types that failed with the reason. Never silently dropped.
dns_whois.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Due diligence on a counterparty domain before the agent trusts itinfo = client.post(    "/dns-whois",    json={"domain": "x402.org", "record_types": ["A", "MX", "NS"]},).json() print("registrar:", info["whois"]["registrar"])print("expires:  ", info["whois"]["expires"])print("A records:", [r["data"] for r in info["records"]["A"]])
POST

/pdf-text

Fetches any public PDF (≤ 25 MB) and returns clean text per page plus a joined body, counts and document metadata. Select pages to protect the context window. Payment required (or free tier). Price: $0.02.

Request body
urlrequiredstring (https URL)Publicly reachable PDF, max 25 MB.
max_pagesinteger 1–200Cap on pages to extract (default 50).
pagesinteger[]Explicit 1-based page selection; overrides max_pages.
request body
{  "url": "https://arxiv.org/pdf/1706.03762v7",  "max_pages": 2}
200 response
{  "url": "https://arxiv.org/pdf/1706.03762v7",  "final_url": "https://arxiv.org/pdf/1706.03762v7",  "bytes": 2215244,  "fetch_ms": 35,  "page_count": 15,  "pages_extracted": 2,  "truncated": true,  "char_count": 7108,  "word_count": 1012,  "metadata": { "creator": "LaTeX with hyperref", "producer": "pdfTeX-1.40.25" },  "pages": [    { "page": 1, "text": "Attention Is All You Need\n..." },    { "page": 2, "text": "..." }  ],  "text": "Attention Is All You Need\n...",  "freshness_seconds": 0,  "cost_usdc": 0.02,  "token": "USDC",  "routing": { "provider": "webtools", "cache_hit": false, "latency_ms": 107 }}
Response fields
page_count / pages_extracted / truncatedrequiredinteger / booleanTotal pages in the document, pages returned, and whether the cap cut the output.
pages[]requiredobject[]page (1-based) and text per page.
text / char_count / word_countrequiredstring / integerJoined text of the extracted pages with counts.
metadatarequiredobjectPDF document info (creator, producer, dates …).
pdf_text.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Turn any public PDF into clean text for the agent's context windowdoc = client.post(    "/pdf-text",    json={"url": "https://arxiv.org/pdf/1706.03762v7", "max_pages": 5},).json() print(doc["page_count"], "pages,", doc["word_count"], "words extracted")print(doc["text"][:500])
POST

/seo-check

One-shot technical SEO audit: status, HTTPS, load time, title / description, canonical, headings, images, links, Open Graph, JSON-LD, robots.txt and sitemap — as a 0–100 score, grade and prioritised issue list. Payment required (or free tier). Price: $0.03.

Request body
urlrequiredstring (URL)Page to audit; redirects are followed.
check_robotsbooleanAlso fetch robots.txt and detect the sitemap (default true).
request body
{  "url": "https://example.com",  "check_robots": true}
200 response
{  "url": "https://example.com",  "final_url": "https://example.com/",  "http_status": 200,  "https": true,  "load_ms": 584,  "title": "Example Domain",  "title_length": 14,  "meta_description": null,  "canonical": null,  "lang": "en",  "viewport": "width=device-width, initial-scale=1",  "h1": ["Example Domain"],  "h2_count": 0,  "word_count": 31,  "images": { "total": 0, "missing_alt": 0 },  "links": { "internal": 0, "external": 1 },  "open_graph": {},  "structured_data_blocks": 0,  "robots_txt": { "found": false },  "issues": [    { "severity": "high",   "code": "missing_description", "message": "No meta description." },    { "severity": "medium", "code": "missing_canonical",   "message": "No canonical link." },    { "severity": "low",    "code": "no_structured_data",  "message": "No JSON-LD structured data." }  ],  "score": 67,  "grade": "C",  "freshness_seconds": 0,  "cost_usdc": 0.03,  "token": "USDC",  "routing": { "provider": "webtools", "cache_hit": false, "latency_ms": 1033 }}
Response fields
score / graderequiredinteger 0–100 / string A–FComposite technical SEO score and letter grade.
issues[]requiredobject[]severity (high | medium | low), code, message — sorted by severity.
title / meta_description / canonical / lang / viewport / h1[]requiredstring | nullCore on-page signals with lengths.
images / links / open_graph / structured_data_blocks / robots_txt / sitemaprequiredobject / integerImages without alt, internal / external links, OG tags, JSON-LD count, robots and sitemap status.
seo_check.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Let an SEO agent audit a page and act on the issuesaudit = client.post("/seo-check", json={"url": "https://example.com"}).json() print("grade:", audit["grade"], "score:", audit["score"])for issue in audit["issues"]:    print(f"[{issue['severity']}] {issue['message']}")
POST

/defi-yields

Screens DeFi pools (DefiLlama) by chain, asset, protocol, TVL and stablecoin filter, sorted by APY. Payment required (or free tier). Price: $0.02.

Request body
chainstringFilter by chain name, e.g. Base, Ethereum, Arbitrum (case-insensitive).
assetstringSubstring match on the pool symbol, e.g. USDC or ETH.
projectstringProtocol slug, e.g. aave-v3, morpho, uniswap-v3.
min_tvl_usdnumberMinimum pool TVL in USD (default 1,000,000).
stablecoins_onlybooleanOnly stablecoin pools (default false).
limitinteger 1–50Number of pools to return, sorted by APY desc (default 10).
request body
{  "chain": "Base",  "stablecoins_only": true,  "min_tvl_usd": 1000000,  "limit": 5}
200 response
{  "filters": { "chain": "Base", "asset": null, "project": null, "min_tvl_usd": 1000000, "stablecoins_only": true },  "pools": [    {      "pool": "7e0661bf-8cf3-45e6-9424-31916d4c7b84",      "project": "aave-v3",      "chain": "Base",      "symbol": "USDC",      "tvl_usd": 251340112.4,      "apy": 4.12,      "apy_base": 4.12,      "apy_reward": null,      "apy_mean_30d": 4.37,      "stablecoin": true,      "il_risk": "no",      "exposure": "single"    }  ],  "pool_count": 5,  "total_matching": 38,  "source": "defillama",  "freshness_seconds": 0,  "cost_usdc": 0.02,  "token": "USDC",  "routing": { "provider": "datatools", "cache_hit": false, "latency_ms": 640 }}
Response fields
pools[]requiredobject[]pool id, project, chain, symbol, tvl_usd, apy, apy_base, apy_reward, apy_mean_30d, stablecoin, il_risk, exposure.
pool_count / total_matchingrequiredintegerReturned pools vs. all pools matching the filters.
filters / sourcerequiredobject / stringEcho of the applied filters; source is always defillama.
defi_yields.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Let a treasury agent find the best stablecoin yield on Baseyields = client.post("/defi-yields", json={"chain": "Base", "stablecoins_only": True, "limit": 5}).json() for pool in yields["pools"]:    print(f"{pool['project']:<12} {pool['symbol']:<10} APY {pool['apy']:.2f}%  TVL ${pool['tvl_usd']:,.0f}")
POST

/currency-convert

Converts an amount into up to 10 currencies using ECB reference rates. Payment required (or free tier). Price: $0.01.

Request body
amountrequirednumberAmount in the source currency (> 0).
fromrequiredstring (ISO 4217)Source currency, e.g. EUR, USD, GBP.
torequiredstring[] (1–10)Target currencies.
request body
{  "amount": 250,  "from": "EUR",  "to": ["USD", "GBP", "JPY"]}
200 response
{  "amount": 250,  "from_currency": "EUR",  "rates": { "USD": 1.0842, "GBP": 0.8391, "JPY": 171.62 },  "converted": { "USD": 271.05, "GBP": 209.775, "JPY": 42905.0 },  "rate_date": "2026-09-11",  "source": "frankfurter_ecb",  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "datatools", "cache_hit": false, "latency_ms": 212 }}
Response fields
ratesrequiredobjectReference rate per target currency (1 unit of from_currency).
convertedrequiredobjectamount × rate per target currency.
rate_date / sourcerequiredstringECB publication date of the rates; source frankfurter_ecb.
currency_convert.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Convert an invoice amount with ECB reference ratesfx = client.post("/currency-convert", json={"amount": 250, "from": "EUR", "to": ["USD", "GBP"]}).json() for ccy, value in fx["converted"].items():    print(f"250 EUR = {value:.2f} {ccy}  (rate date {fx['rate_date']})")
POST

/geo-ip

Geolocates an IPv4 / IPv6 address with timezone, ASN and provider fallback. Payment required (or free tier). Price: $0.01.

Request body
iprequiredstringIPv4 or IPv6 address.
max_age_secondsintegerAccept a cached lookup up to this age (default 86400).
request body
{  "ip": "8.8.8.8"}
200 response
{  "ip": "8.8.8.8",  "version": 4,  "is_private": false,  "country": "United States",  "country_code": "US",  "region": "California",  "city": "Mountain View",  "postal": "94043",  "latitude": 37.4223,  "longitude": -122.085,  "timezone": "America/Los_Angeles",  "utc_offset": "-07:00",  "asn": 15169,  "org": "Google LLC",  "isp": "Google LLC",  "is_eu": false,  "source": "ipwho.is",  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "datatools", "cache_hit": false, "latency_ms": 188 }}
Response fields
country / country_code / region / city / postalrequiredstring | nullAdministrative location.
latitude / longitude / timezone / utc_offsetrequirednumber / stringCoordinates and IANA timezone.
asn / org / isp / is_eu / is_privaterequiredmixedNetwork ownership and flags.
sourcerequiredstringipwho.is or ip-api.com (automatic fallback).
geo_ip.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Geolocate a visitor / counterparty IP for routing or compliancegeo = client.post("/geo-ip", json={"ip": "8.8.8.8"}).json() print(geo["city"], geo["country_code"], geo["timezone"], "ASN", geo["asn"], geo["org"])
POST

/rss-feed

Fetches an RSS 2.0 / Atom feed and returns normalised JSON items. Payment required (or free tier). Price: $0.01.

Request body
urlrequiredstring (URL)Feed URL (RSS 2.0 or Atom).
max_itemsinteger 1–100Items to return (default 20).
include_contentbooleanInclude full item content when the feed provides it (default false).
request body
{  "url": "https://hnrss.org/frontpage",  "max_items": 5,  "include_content": false}
200 response
{  "url": "https://hnrss.org/frontpage",  "format": "rss",  "feed_title": "Hacker News: Front Page",  "feed_link": "https://news.ycombinator.com/",  "items": [    {      "title": "Show HN: An open protocol for agent payments",      "link": "https://example.com/post",      "published": "2026-09-11T08:14:02+00:00",      "author": "someone",      "summary": "Comments: https://news.ycombinator.com/item?id=…",      "content": null    }  ],  "item_count": 5,  "total_items": 30,  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "datatools", "cache_hit": false, "latency_ms": 402 }}
Response fields
format / feed_title / feed_linkrequiredstringrss or atom plus feed metadata.
items[]requiredobject[]title, link, published (ISO-8601), author, summary, content.
item_count / total_itemsrequiredintegerReturned vs. total items in the feed.
rss_feed.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Monitor any RSS / Atom feed as normalised JSONfeed = client.post("/rss-feed", json={"url": "https://hnrss.org/frontpage", "max_items": 5}).json() for item in feed["items"]:    print(item["published"], "-", item["title"])
POST

/crypto-ohlcv

Returns historical OHLCV candles for a crypto pair with a summary block (Binance, Coinbase fallback). Payment required (or free tier). Price: $0.02.

Request body
symbolrequiredstringBase asset, e.g. BTC, ETH, SOL.
quotestringQuote asset (default USDT; USD is mapped for Coinbase fallback).
intervalstring1m, 5m, 15m, 1h, 4h, 1d, 1w (default 1h).
limitinteger 1–500Number of candles (default 100).
request body
{  "symbol": "ETH",  "quote": "USDT",  "interval": "1h",  "limit": 24}
200 response
{  "symbol": "ETH",  "quote": "USDT",  "interval": "1h",  "candles": [    { "time": "2026-09-10T10:00:00+00:00", "open": 4412.1, "high": 4431.0, "low": 4398.4, "close": 4420.7, "volume": 8123.44 }  ],  "candle_count": 24,  "summary": {    "first_open": 4412.1,    "last_close": 4467.3,    "period_high": 4490.0,    "period_low": 4380.2,    "period_volume": 191204.9,    "change_pct": 1.25  },  "source": "binance",  "freshness_seconds": 0,  "cost_usdc": 0.02,  "token": "USDC",  "routing": { "provider": "datatools", "cache_hit": false, "latency_ms": 233 }}
Response fields
candles[]requiredobject[]time (ISO-8601), open, high, low, close, volume — oldest first.
summaryrequiredobjectfirst_open, last_close, period_high, period_low, period_volume, change_pct.
sourcerequiredstringbinance or coinbase (automatic fallback).
crypto_ohlcv.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Feed a trading agent with the last 24 hourly candlesohlcv = client.post("/crypto-ohlcv", json={"symbol": "ETH", "interval": "1h", "limit": 24}).json() s = ohlcv["summary"]print(f"ETH 24h: {s['first_open']} -> {s['last_close']}  ({s['change_pct']:+.2f}%)  high {s['period_high']}  low {s['period_low']}")
POST

/ens-resolve

Resolves an ENS name on Ethereum mainnet to its address and text records via direct on-chain calls. Payment required (or free tier). Price: $0.01.

Request body
namerequiredstringENS name, e.g. vitalik.eth (case-insensitive).
text_keysstring[] (≤ 8)Text records to read (default url, com.twitter, avatar).
request body
{  "name": "vitalik.eth",  "text_keys": ["url", "com.twitter", "avatar"]}
200 response
{  "name": "vitalik.eth",  "namehash": "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",  "resolver": "0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41",  "address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",  "texts": { "url": "https://vitalik.ca", "com.twitter": "VitalikButerin", "avatar": "eip155:1/erc1155:0xb32979486938aa9694bfc898f35dbed459f44424/10063" },  "chain": "ethereum",  "resolved": true,  "freshness_seconds": 0,  "cost_usdc": 0.01,  "token": "USDC",  "routing": { "provider": "datatools", "cache_hit": false, "latency_ms": 356 }}
Response fields
addressrequiredstring | nullResolved Ethereum address (lower-case) or null.
resolver / namehashrequiredstringResolver contract and EIP-137 namehash used for the lookup.
texts / resolvedrequiredobject / booleanRequested text records (null if unset) and overall success flag.
ens_resolve.py
import httpxfrom eth_account import Accountfrom x402.clients.httpx import x402_payment_hooks account = Account.from_key("0x<AGENT_PRIVATE_KEY>")client = httpx.Client(    base_url="https://agent-margin-router-production.up.railway.app",    event_hooks=x402_payment_hooks(account),)# Resolve a human-readable name before sending fundsens = client.post("/ens-resolve", json={"name": "vitalik.eth"}).json() if ens["resolved"]:    print("send to", ens["address"], "| twitter:", ens["texts"].get("com.twitter"))

MCP server & discovery

Every endpoint is also exposed as an MCP tool over Streamable HTTP at POST /mcp — no SDK, no session state. Add the server to Claude Desktop, Cursor, LangChain or any MCP-capable agent; tools: extract_clean, market_spread, gas_fees, token_price, wallet_balance, web_search, email_validate, dns_whois, pdf_text, seo_check, defi_yields, currency_convert, geo_ip, rss_feed, crypto_ohlcv, ens_resolve, health, payment_info. Payment works exactly like HTTP: pass wallet (free tier) or x_payment as tool arguments; a 402 is returned as a structured result with the payment requirements.

mcp.json / claude_desktop_config.json
{  "mcpServers": {    "agent-margin-router": {      "url": "https://agent-margin-router-production.up.railway.app/mcp"    }  }}
mcp.sh
# List available tools (JSON-RPC 2.0, Streamable HTTP)curl -s -X POST https://agent-margin-router-production.up.railway.app/mcp \  -H 'content-type: application/json' \  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq # Call a tool — pass your wallet for the free tier, or an x402 payment headercurl -s -X POST https://agent-margin-router-production.up.railway.app/mcp \  -H 'content-type: application/json' \  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{        "name":"market_spread",        "arguments":{"asset":"ETH","buy_venue":"binance","sell_venue":"coinbase",                     "wallet":"0xYourWallet"}}}' | jq

For crawlers and marketplaces the catalog is published in the x402 Bazaar format (every 402 also carries outputSchema), plus an llms.txt and the full OpenAPI schema.

discovery.sh
# Machine-readable catalog (x402 Bazaar format) + LLM-friendly summarycurl -s https://agent-margin-router-production.up.railway.app/.well-known/x402 | jqcurl -s https://agent-margin-router-production.up.railway.app/discovery/resources | jqcurl -s https://agent-margin-router-production.up.railway.app/llms.txtcurl -s https://agent-margin-router-production.up.railway.app/openapi.json | jq '.paths | keys'

Error codes

Errors are returned as { "error": string, "code": string, "detail"?: any }. No payment is settled on any non-2xx response — a signed authorization that was not consumed simply expires.

StatusMeaning
200
OK
Request succeeded. Payment (if any) settled.
400
Bad Request
Invalid body — missing `url`/`asset`, malformed JSON or unsupported selector.
402
Payment Required
No valid payment attached and free tier exhausted (or no X-WALLET).
403
Payment Invalid
X-PAYMENT present but facilitator verification failed (wrong amount, network, expired, replayed).
422
Unprocessable
Target URL unreachable / asset or venue unknown to all providers.
429
Rate Limited
Burst limit per wallet/IP exceeded.
502
Provider Error
All upstream providers failed for this request.
503
Degraded
Service in degraded mode (e.g. Redis unavailable).
Provider routing

Multi-provider by design

Every request is routed to the healthiest provider based on live health checks, latency and cost. Fallbacks are automatic and transparent — the response always tells you which source served it.

Jede Anfrage wird automatisch an den gesündesten Provider geroutet — Fallbacks inklusive.

Apify

Primary · Web extraction
apify

Headless-browser web scraping at scale. Handles JavaScript-rendered pages, infinite scroll and anti-bot friction.

  • JS rendering (Chromium)
  • CSS selector extraction
  • Proxy rotation
  • Structured JSON output
used by/extract-clean

CoinGecko

Primary · Market data
coingecko

Broad coverage of 15k+ assets and 1k+ venues with per-exchange tickers. Used as the primary price source for spread analysis.

  • Per-venue tickers
  • 15k+ assets
  • Volume & liquidity
  • Sub-minute freshness
used by/market-spread

CoinMarketCap

Fallback · Market data
coinmarketcap

Independent second price feed. Activated automatically when CoinGecko is rate-limited, stale or unhealthy; also used for confidence cross-checks.

  • Independent price feed
  • Exchange pair quotes
  • Cross-check weighting
  • Auto-failover
used by/market-spread

httpx direct

Fallback · Web extraction
httpx_direct

Zero-cost direct HTTP fetch with HTML parsing. Serves static pages instantly and guarantees availability if Apify is degraded.

  • Static HTML fetch
  • Sub-second latency
  • No upstream cost
  • Always available
used by/extract-clean
More upstream sources · all key-less, all with fallbacks
  • Binance · Coinbase · Kraken (median)/token-price · /crypto-ohlcv
  • Public JSON-RPC nodes (Base, Ethereum, Arbitrum, Optimism, Polygon)/gas-fees · /wallet-balance · /ens-resolve
  • DefiLlama Yields/defi-yields
  • ECB reference rates (Frankfurter)/currency-convert
  • DuckDuckGo HTML/web-search
  • DNS-over-HTTPS (Cloudflare, Google) · RDAP/email-validate · /dns-whois
  • ip-api · ipwho.is/geo-ip
  • Direct HTTPS fetch + parsers/pdf-text · /seo-check · /rss-feed

Licensing & provenance. Provider terms are respected: outputs are derived, not raw redistributions; every response carries provider and fetched_at. Provider health is monitored 24/7 and exposed at /health.

Pricing

Simple, metered, transparent.

No subscriptions, no tiers, no minimums. Try it for free, then pay exactly for what your agent consumes — in stablecoins.

Keine Abos, keine Mindestumsätze: erst kostenlos testen, dann pro Anfrage zahlen.

Free Tier

For evaluation & CI
$0/ first 3 requests per wallet

Send X-WALLET with any EVM address. No payment, no signature, full functionality.

pay-per-use

Pay-per-use

For production agents
$0.01 – $0.05/ request · USDC or USDT

Settled via x402 on Base. Flat price per endpoint: on-chain reads, e-mail & DNS checks, FX, geo-IP, RSS and ENS $0.01; web search, extraction, PDF text, DeFi yields and OHLCV $0.02; SEO audit $0.03; spread analysis $0.05. Only successful (2xx) responses are charged.

FeatureFree TierPay-per-use
Requests included3 per walletUnlimited
Price per request$0.00$0.01 – $0.05
PaymentX-WALLET header onlyx402 · USDC or USDT on Base
/extract-clean$0.02
/market-spread$0.05
/gas-fees$0.01
/token-price$0.01
/wallet-balance$0.01
/web-search$0.02
/email-validate$0.01
/dns-whois$0.01
/pdf-text$0.02
/seo-check$0.03
/defi-yields$0.02
/currency-convert$0.01
/geo-ip$0.01
/rss-feed$0.01
/crypto-ohlcv$0.02
/ens-resolve$0.01
Multi-provider fallback
Provenance & billing metadata
Failed requests charged
Account / API key required
SettlementOn-chain, instant (~2 s)
Über uns · About

Infrastruktur für die Agent Economy

Wir glauben, dass Software-Agenten in den nächsten Jahren zu den größten API-Kunden werden — und dass sie dafür Bezahlwege brauchen, die so maschinennah sind wie HTTP selbst.

English summary: NovaNest builds pay-per-request data infrastructure for autonomous agents, settled natively via x402.

Was wir bauen

Der Agent Margin Router ist ein Daten-Broker für autonome KI-Agenten: Er bündelt mehrere Datenquellen, routet jede Anfrage an den gesündesten Provider und liefert striktes JSON — bezahlt pro Anfrage, ohne Vertrag.

Wofür wir stehen

Keine erfundenen Kennzahlen, keine verschleierten Lizenzen. Jede Antwort trägt Herkunft und Zeitstempel. Providerbedingungen werden maschinenlesbar eingehalten — abgeleitete Ergebnisse statt Rohdaten-Weiterverkauf.

Wer dahinter steht

NovaNest entwickelt Infrastruktur für die Agent Economy aus Deutschland heraus. Der Router ist unser erster Baustein: kleine, klar bepreiste Datenservices, die Agenten ohne menschliche Onboarding-Schleife nutzen können.