Your agent plans a swap. Before it signs, one API call returns an evidence
object: an advisory verdict (clear | caution | unsupported), machine-readable
reason codes, token registry recognition, a route quality state, and the
caveats your user should read — with a methodology version on every response.
Routescore is one composable element of an agentic stack — the evidence / attestation element — alongside your planner, executor, and wallet. It never signs, executes, routes funds, or advises. The composition looks like this:
plan → preflight (Routescore) → execute (venue/agent) → record (Routescore)Think of it like a home inspection report for an onchain action: it documents what was observed, what was modeled, what was not evaluated, and when — you (or your agent's policy) still decide.
1. What one check_swap call answers
POST /api/public/v1/check/swap composes, in a single round-trip:
| Field | What it tells your agent |
|---|---|
verdict | clear | caution | unsupported — an advisory pre-sign verdict, never an instruction to execute |
reasons[] | Stable machine codes, e.g. token_unverified, sequencer_ordering_uncalibrated, route_chain_mismatch, slippage_exceeds_allowance |
chain | { chainId, name, supportLevel } — supportLevel is live | modeled | recognized |
route | Modeled route quality: grade (A–F), qualityScore (0–100), modeledRouteLeakBps, publicMempoolMevBps (null when not observable), modeledSlippageBps, orderFlow, confidenceLabel |
token_safety | Registry recognition read: state is recognized | unverified | not_evaluated, plus flags[] and caveats[]. Recognition is a registry match only — not a safety, sellability, liquidity, rights, redemption, or investment-quality verification |
caveats[] | Pre-written honest sentences meant to reach your end user |
score_state | valid | partial | unsupported — whether anything modeled is incomplete |
source_freshness | Per-source freshness states (fresh | partial | stale | unsupported | unavailable | unknown — the full published enum in the OpenAPI spec; check_swap today emits fresh | partial | unsupported), with checked_at |
methodology_version | Currently routescore.public_api.v1 — pin it, diff on change |
commercial_disclosure | paid_placement: false, score_influenced_by_partner: false — no pay-to-rank, ever |
record_id · evidence_bundle_id · record_output_hash | Additive evidence-record linkage: every keyed call persists a durable, hash-verifiable preflight record. Retrieval + offline re-verification: Verifiable pre-sign evidence records |
Everything modeled is labeled modeled and point-in-time. Gaps are stated as
unsupported or not_evaluated, never approximated away.
2. curl: a Robinhood Chain pre-sign check
Robinhood Chain is chain_id: 4663. This example checks a USDG → tokenized
AAPL swap on the day-one Uniswap route, passing the Routescore registry
contract address for the output token (for tokenized stock/ETF assets,
symbol-only input is downgraded to unverified by design — a symbol match
cannot rule out fake-contract impersonation):
curl -X POST https://www.routescore.io/api/public/v1/check/swap \
-H "Authorization: Bearer rs_live_..." \
-H "Content-Type: application/json" \
-d '{
"notional_usd": 10000,
"chain_id": 4663,
"route": "uniswap-v3-rho",
"token_in": "USDG",
"token_out": "0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9",
"slippage_allowance_bps": 75
}'The honest answer today is caution, not clear — Robinhood Chain support
is modeled and realized outcomes there are still uncalibrated. Response
(HTTP 200; timestamps illustrative):
{
"verdict": "caution",
"chain": { "chainId": 4663, "name": "Robinhood Chain", "supportLevel": "modeled" },
"route": {
"id": "uniswap-v3-rho",
"name": "Uniswap · Robinhood Chain",
"protocol": "uniswap",
"chainId": 4663,
"grade": "A",
"qualityScore": 97,
"modeledRouteLeakBps": 0.8,
"publicMempoolMevBps": null,
"modeledSlippageBps": 25.5,
"expectedTotalLossUsd": 26.26,
"orderFlow": "sequencer_ordered",
"confidenceLabel": "low"
},
"token_safety": {
"state": "recognized",
"recognized": true,
"flags": ["tokenized_asset_registry_only"],
"caveats": [
"AAPL matches Routescore's recognized token registry address for this chain.",
"Recognition is not a safety, liquidity, sellability, transferability, routing, redemption, custody, or investment-quality verification.",
"Tokenized-stock/ETF recognition is based on the Routescore registry entry; it does not verify issuer attestation, shareholder rights, beneficial ownership, dividends, corporate actions, jurisdiction eligibility, insolvency treatment, redemption, or can-sell status."
]
},
"reasons": ["sequencer_ordering_uncalibrated"],
"score_state": "partial",
"source_freshness": {
"state": "partial",
"checked_at": "2026-07-09T00:00:00.000Z",
"max_age_seconds": null,
"sources": [
{ "name": "routescore_route_model", "freshness_state": "partial", "as_of": "2026-07-09T00:00:00.000Z", "age_seconds": 0 },
{ "name": "token_registry_recognition_only", "freshness_state": "partial", "as_of": "2026-07-09T00:00:00.000Z", "age_seconds": null }
]
},
"methodology_version": "routescore.public_api.v1",
"confidence_band": { "low": null, "high": null, "unit": "bps", "label": "modeled_preflight" },
"caveats": [
"Pre-trade decision support only. Routescore does not execute trades, route funds, or promise an outcome.",
"Route and execution-risk values are modeled, point-in-time. Token-safety is registry recognition vs unverified status, not a live honeypot, can-sell, rights, redemption, or liquidity audit.",
"Route uses sequencer-ordered L2 settlement; Ethereum public-mempool sandwich assumptions are not applied, and realized RHC liquidity/slippage/oracle/finality outcomes remain uncalibrated.",
"AAPL matches Routescore's recognized token registry address for this chain.",
"Recognition is not a safety, liquidity, sellability, transferability, routing, redemption, custody, or investment-quality verification.",
"Tokenized-stock/ETF recognition is based on the Routescore registry entry; it does not verify issuer attestation, shareholder rights, beneficial ownership, dividends, corporate actions, jurisdiction eligibility, insolvency treatment, redemption, or can-sell status."
],
"commercial_disclosure": {
"paid_placement": false,
"score_influenced_by_partner": false,
"message": "Routescore does not sell paid placement or pay-to-rank treatment in score methodology."
},
"trust": { "…": "the same envelope fields nested in full, plus generated_at and decision_support_only: true" }
}Reading this response honestly:
publicMempoolMevBpsisnullbecause Robinhood Chain is a sequencer-ordered (FCFS) Arbitrum-stack L2 — there is no Ethereum public mempool there, so public-mempool sandwich framing is not applied and not claimed. What is observed instead is the caveat: ordering assumptions are different and realized outcomes are uncalibrated.recognizedmeans the address matched Routescore's registry entry for this chain — observed on-chain 2026-07-07 — and nothing more. Thetokenized_asset_registry_onlyflag exists precisely so an agent cannot read a registry match as sellability or rights.score_state: partialtells you something modeled is incomplete. Apartialis information, not decoration — surface it.
Robinhood Chain context your user deserves relayed: per issuer disclosures, Robinhood's tokenized stock/ETF assets ("Stock Tokens") are debt securities issued by Robinhood Assets (Jersey) Ltd; they carry no shareholder rights, and are not offered in the US, CA, UK, CH, or UAE. Routescore reports this as registry and rights context — it does not evaluate eligibility for any specific user or jurisdiction. The full evidence checklist behind this call lives in the companion guide, What to check before an AI agent touches a tokenized asset.
3. MCP setup: give the same check to Claude Code or Cursor
The check_swap tool ships in
@routescore/mcp
(published version 0.2.1 at the time of writing), a thin stateless
wrapper over the same keyed REST gateway.
Claude Code:
claude mcp add routescore --env ROUTESCORE_API_KEY=rs_live_... -- npx -y @routescore/mcpCursor (.cursor/mcp.json) / Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"routescore": {
"command": "npx",
"args": ["-y", "@routescore/mcp"],
"env": { "ROUTESCORE_API_KEY": "rs_live_..." }
}
}
}Run whoami first to confirm the key and its plan tier. Optional:
ROUTESCORE_API_URL overrides the API base (default
https://www.routescore.io).
How your agent should relay the result
The response is built for what Routescore's agent-first design rules call
schema-enforced honesty — structured fields the model cannot paraphrase
away: the verdict enum, caveats[], score_state, and
methodology_version. (The full rule also specifies per-caveat severity and
a relay_to_user field; those are roadmap, not shipped — see below.) The
companion rule is safe defaults: "Unknown token → caution. Missing
data → unsupported. Never a guess."
For agent builders that means one instruction:
Relay
verdict,reasons[], andcaveats[]to your user verbatim. Do not summarize a caveat into something softer, drop thepartialscore state, or convert "uncalibrated" into confidence. The caveat sentences are pre-written so they survive the trip from API to end user intact.
If your agent shows one line, show this shape:
Preflight (Routescore, modeled, routescore.public_api.v1): CAUTION —
sequencer ordering uncalibrated on Robinhood Chain; token recognized in
registry (registry match is not sellability or rights). Full caveats relayed
below.4. Handling each verdict state
| Verdict | HTTP | What it means | What your agent should do |
|---|---|---|---|
clear | 200 | No modeled downgrade triggered on the surfaces that were evaluated | Not a recommendation and not an execution instruction. Proceed only per your own policy; still relay caveats[], and check score_state — anything not evaluated stays not evaluated |
caution | 200 | At least one honest gap or modeled threshold downgraded the verdict (see reasons[]) | Relay reasons + caveats verbatim; let the user or a declared policy decide. Gate programmatically on stable codes (e.g. block on token_unverified, require confirmation on sequencer_ordering_uncalibrated) |
unsupported | 422 | Routescore cannot model this input (e.g. unknown/unsupported chain) | Do not guess. Do not substitute another chain's model, retry with fudged inputs, or infer a score. Tell the user: "not evaluated by Routescore" — and treat that as the answer |
One more case your agent must handle separately: schema-invalid inputs never
reach a verdict. A missing or invalid notional_usd, a chain_id that is
not a positive integer, or an out-of-range slippage_allowance_bps returns
HTTP 400 with an { "error": { "code": "invalid_input" } } envelope — no
verdict, no reasons[], no trust envelope. Treat a 400 as a bug in the
request your agent built, not as an unsupported evaluation.
Two invariants worth encoding in your agent policy:
clearnever upgrades an unknown. An unverified token or unknown order flow downgrades the verdict; nothing in the response marks anything "safe" — there is no such flag, by design.- Absence of a warning is not evidence of absence of risk. Check
source_freshnessforstale/unknownsources andscore_stateforpartialbefore weighing the verdict at all.
After execution, close the loop: record what was checked and what was
decided. Every keyed check_swap call already persists a durable,
hash-verifiable evidence record and returns its record_id,
evidence_bundle_id, and record_output_hash — retrieval and offline
re-verification are covered in
Verifiable pre-sign evidence records.
The app additionally provides a decision journal and exportable evidence
bundles.
5. Access, tiers, and rate limits (the honest version)
- The keyed REST API and
@routescore/mcpare bundled with the Power tier. Generate a key at Account → Developer → API & MCP (/account); keys look likers_live_…and are shown once. There is no free anonymous API tier today — if that changes it will be announced, not implied. Key setup is walked through step by step in API & MCP access. - Rate limits are per key. Read
X-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Reseton every response; a429carriesRetry-After. Build backoff against the headers, not against an assumed number. - Tier is read live on each request — a downgraded or canceled plan returns
403rather than silently degrading results. - No key needed for the browser and read-only surfaces: /route-check?chain=4663 (chain-aware route check), /swap-slippage-checker, /benchmark, /reports/robinhood-chain-risk-map, and the public snapshot endpoints listed at /developers.
Known limitations are published at /limitations; the scoring methodology at /methodology; calibration evidence publishes at /calibration as label cohorts clear the publication bar (Robinhood Chain realized outcomes are not yet calibrated — the response says so instead of hiding it).
Roadmap (clearly labeled: not available today)
These are in design/build and may change. Nothing below is callable now, and nothing above depends on it:
preflight_action— a generalized one-call preflight (beyond swaps) returning verdict + policy violations + caveats, including arelay_to_userfield: a pre-written one-sentence caveat the agent quotes verbatim. (The evidence-record half already ships forcheck_swap— see Verifiable pre-sign evidence records.)- Tokenized asset passports — structured rights-granted / rights-not-granted fields per tokenized asset.
- Basis monitor — observed token-vs-reference price basis with freshness states.
- Can-sell probes — a live token-security source; until it lands, neither
recognizednorunverifiedmay be read as "can sell". - Agent-relay eval harness — automated tests that caveats and verdicts survive into real agents' final user-facing answers.
Routescore is read-only decision support: it never signs, executes, routes
funds, custodies assets, or gives investment advice. All figures are modeled,
point-in-time, and carry methodology_version routescore.public_api.v1.
No paid placement; see /neutrality.