API reference
Base URL https://api.flashrouter.io. JSON in, JSON out. Public reads are rate-limited per client IP; write routes require Authorization: Bearer <api key> issued under an engagement letter. Chains, pools, and assets are allowlisted server-side; anything else returns 400. Every chain read carries read_at and max_age_sec so a consumer can treat it as stale.
Status: REAL, deployed 2026-09-04. If a chain node does not answer, the API returns 502 upstream_unavailable rather than a cached number.
Endpoints
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /v1/health | public | Version, Base and XRPL reachability, whether a signing key is configured. |
| GET | /v1/status | public | The versioned public-status.json. |
| GET | /v1/chain/aave-premium?chain=base | public | Flash premium read from the Aave V3 Pool now, with pool, block, chain-id check, timestamp, allowlisted assets. |
| GET | /v1/chain/head?chain=base | public | Latest and finalized block numbers, hashes, timestamps. |
| GET | /v1/quote/aave?chain=base&asset=USDC&amount=250000 | public | Premium amount, total to repay, available liquidity, depth check. |
| GET | /v1/pof/key | public | Current and historical attestation public keys with kid and SHA-256 fingerprint. |
| POST | /v1/pof/attest | api key | Issue an attestation. Body: chain, address, asset, claimed, window_blocks?. |
| GET | /v1/pof/{id} | public | The signed envelope. |
| GET | /v1/pof/{id}/verify | public | Re-checks the signature and re-reads the balance at the current finalized block. |
| GET | /v1/xrpl/amendments?network=mainnet | public | Decoded Amendments ledger entry for the features the desk depends on. |
| GET | /v1/xrpl/tradeline/{account}?network=mainnet | public | Trust lines with side and authorization state, escrows, credentials, flags. |
| POST | /v1/xrpl/tradeline/quote | api key | Read-only pre-check of an account for a facility: reserve, existing line, credential. |
| POST | /v1/intake | public, limited | Engagement intake; returns a reference id. |
Examples
Quote:
GET /v1/quote/aave?chain=base&asset=USDC&amount=250000
{
"chain": "base", "asset": "USDC", "amount": "250000",
"premium_bps": 5, "premium_amount": "125", "total_repay": "250125",
"available_liquidity": 17945551.63, "depth_ok": true,
"block": 50874066, "pool": "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5",
"addresses_verified": "2026-09-04", "read_at": "2026-09-04T15:57:59Z"
}
Premium source for the estimator:
GET /v1/chain/aave-premium?chain=base
{
"chain": "base", "chain_id": 8453, "provider": "Aave V3",
"pool": "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5", "premium_bps": 5,
"block": 50875270, "read_at": "2026-09-04T16:38:09Z", "max_age_sec": 120,
"assets": [ { "symbol": "USDC", "token": "0x8335...2913", "a_token": "0x4e65...c0AB", "decimals": 6, "verified": "2026-09-04" } ]
}
Attestation:
POST /v1/pof/attest
Authorization: Bearer <key>
{ "chain": "base", "address": "0x...", "asset": "USDC", "claimed": "250000" }
201 -> the signed envelope with "id" and "verify_url"
422 -> { "error": "held_for_not_satisfied", "min_balance": "...", "claimed": "...", "observation": { ... } }
Tradeline read (testnet demo client):
GET /v1/xrpl/tradeline/rpno8F79Pd9Zd9goD9S7zryU1bDebgroAx?network=testnet
{
"account": "rpno8F79Pd9Zd9goD9S7zryU1bDebgroAx", "network": "testnet", "exists": true,
"ledger_index": 20482588, "xrp_balance": "89.999952",
"flags": { "requireAuth": false, "defaultRipple": false, "allowClawback": false },
"lines": [ { "counterparty": "rhqGoX6Fai9V3AfoWEjDRtoJyW1sk4b2GK", "side": "holder", "currency": "USD",
"limit": "100000", "drawn": "20197.260274", "authorized_by_issuer": true } ],
"escrows": [ { "destination": "rhqGoX6Fai9V3AfoWEjDRtoJyW1sk4b2GK", "amount": "10000000", "finish_after": 841853999 } ]
}
Errors
| Status | error | Meaning |
|---|---|---|
| 400 | bad_request | Missing or malformed parameter, or a chain, asset, or network outside the allowlist. detail names it. |
| 401 | unauthorized | Missing or wrong API key on a write route. |
| 404 | not_found | Unknown attestation id or route. |
| 422 | held_for_not_satisfied | Balance at one of the two observations is below the claim. |
| 422 | depth_insufficient | Available liquidity is under 1.5 times the requested flash amount. |
| 429 | rate_limited | Per-IP limit hit; retry_after in seconds. |
| 501 | control_proof_not_implemented | control_signature supplied; reserved in version 2.0.0. |
| 502 | upstream_unavailable | The chain or ledger node did not answer. No cached number is returned. |
| 503 | signing_key_not_configured | The deployment has no attestation key. |
Rate limits and CORS
Public reads: 60 requests per minute per IP per route family. Intake: 5 per hour per IP. Browser origins allowed: https://flashrouter.io and the site's preview hosts. API keys are compared in constant time and are at least 24 characters.
Freshness
Every chain read includes read_at (UTC) and max_age_sec (120). A consumer that displays the value should show the timestamp and treat anything older than max_age_sec as stale. Public RPC endpoints are used with failover; a dedicated node replaces them before any client service level is promised.