For autonomous agents
A pre-trade firewall your agent pays for per call.
Before an agent touches a token or pool, it asks Kestrel. ALLOW, WARN or BLOCK, from live bytecode, pools and bridge parity. 0.01 USDC per full verdict on Base.
GET | POST /api/v1/guard
The pre-trade verdict
A machine-readable verdict built from live bytecode, proxy slots, owner posture, pool depth, overnight deltas and bridge parity on Base or Robinhood Chain. The free preview tier is always on. POST takes the same fields as a JSON body.
- address
- Token, pool, wallet or escrow (0x…). The zero address is rejected with 400.
- chainId
- 8453 (Base) or 4663 (Robinhood Chain). Anything else is 400.
- mode
preview(free, default) orfull(x402, 0.01 USDC).- intent
trade(default: a token or pool you will trade or approve) orcounterparty(a wallet you will send to). A smart-wallet target is BLOCKed for trade intent.
When a live read fails part-way, the verdict comes back as WARN with status: "degraded" and retryAfterSec. When the scan cannot classify the address at all, the answer is HTTP 503 with Retry-After, never a guessed verdict.
GET https://usekestrel.vercel.app/api/v1/guard?address=0x…&chainId=8453&intent=trade { "verdict": "ALLOW" | "WARN" | "BLOCK", "riskScore": 0-100 | null, // null when degraded with scanError "band": "NOMINAL" | "ELEVATED" | "CRITICAL" | null, "status": "complete" | "degraded", "retryAfterSec": 15, // only when degraded "intent": "trade", "reasons": [{ "severity": "warn", "title": "…" }], "simulatedSlippage": { "priceImpactBps": 98, … }, "poolDepthWethRaw": "10052414182037559293", "bridgeParity": { "verified": true, "verdict": "EXACT", "pendingPackets": 0, "spreadBps": -93, "netEdgeBps": … }, "blockNumber": "…", "chainId": 8453, "tier": "preview"}
HTTP 402 · Base USDC
How a paid call settles
Full verdicts are paid with the open x402 ↗ HTTP 402 standard. Payments settle on Base only; scans cover Base and Robinhood Chain.
- 01
402 challenge
GET /api/v1/guard?mode=full without payment answers HTTP 402. The x402 v2 PaymentRequired is in the base64 PAYMENT-REQUIRED header (network eip155:8453); the legacy v1 form is in the JSON body (network "base"). Both quote 0.01 USDC to the same receiver. - 02
Signed authorization
The agent signs an EIP-3009 TransferWithAuthorization for the exact price and retries with PAYMENT-SIGNATURE (v2) or X-PAYMENT (v1). Kestrel never holds keys or funds. The signature is the payment. - 03
Verify, scan, settle
Kestrel checks the amount, recipient and time window, verifies the signature through the PayAI facilitator (keyless; the facilitator pays the gas, the agent only needs USDC), runs the full scan, then has the facilitator settle the transfer on Base. The verdict comes back only after settlement, with a PAYMENT-RESPONSE (or X-PAYMENT-RESPONSE) receipt carrying the transaction hash. If the scan fails, nothing is settled and the same header can be retried. - 04
Single-use payments
Each (payer, nonce) authorization is claimed with an atomic SET NX lock before verification, checked against USDC.authorizationState onchain, and each settlement transaction is delivered once. Replaying a header, even in parallel, returns 402 payment_already_used or payment_in_flight, never a second verdict.
GET /api/v1/guard?address=0x…&mode=full← 402 PAYMENT-REQUIRED: base64({ "x402Version": 2, "resource": { "url": "https://usekestrel.vercel.app/api/v1/guard?mode=full", … }, "accepts": [{ "scheme": "exact", "network": "eip155:8453", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "amount": "10000", // 0.01 USDC "payTo": "0xEbB92c8f27368222E4B722FB386DbC6Fe80CC426", "maxTimeoutSeconds": 300, "extra": { "name": "USD Coin", "version": "2" } }], "extensions": { "bazaar": { "info": …, "schema": … } } }) body: { "x402Version": 1, "accepts": [{ "network": "base", "maxAmountRequired": "10000", … }] } → retry, v2: PAYMENT-SIGNATURE: base64({ x402Version: 2, accepted, payload: { signature, authorization } })→ retry, v1: X-PAYMENT: base64({ x402Version: 1, scheme, network, payload: { signature, authorization } }) verify (facilitator) → full scan → settle on Base← 200 + verdict + payment.transaction PAYMENT-RESPONSE (v2) | X-PAYMENT-RESPONSE (v1): base64({ success, transaction, network, payer })
Simulate Agent x402 Call
Run the handshake yourself.
These buttons hit this deployment's real endpoint. Step 2 returns the actual HTTP 402. Step 3 asks your wallet to sign a real EIP-3009 TransferWithAuthorization for 0.01 USDC (x402 v2 by default, v1 selectable). The server verifies it, runs the scan, settles it onchain and only then returns the verdict and the Basescan link.
GET /api/x402/revenue
Revenue, proven onchain
Every number here is read from Base: USDC Transfer logs into the receiver, scanned in 50,000-block windows. The server's own delivery ledger sits beside it so the two can be compared.
POST /api/mcp
An MCP server with 11 tools
Add Kestrel to Claude Code, Claude Desktop or any MCP client. Eight tools are read-only and hit mainnet live; three manage Night-Shift Pager watches with a desk key passed as a tool argument. Browser requests from other origins get 403.
- scan_contract
- { address, chainId, intent? } → guard verdict
- check_bridge_parity
- {} → OFT 1:1 invariant, signed verdict and spread
- simulate_exit
- { address, chainId, sellBpsOfReserve, lpPullBps, whaleDumpBpsOfSupply }
- inspect_vibestarter_escrow
- { address?, chainId } → tranche timeline and challenge windows
- challenge_copilot
- { escrow, chainId, wallet? } → phase, 72h window and backer readiness
- challenge_dry_run
- { escrow, outcomes? } → real escrow bytecode through eth_simulateV1
- ecosystem_health
- { chainId?, escrow? } → every Vibestarter launch, live health board
- vibestarter_pulse
- {} → platform figures from Vibestarter's own MCP server
- create_watch
- Night-Shift Pager watch
- list_watches
- Your desk's pager watches
- delete_watch
- Removes a pager watch
# Claude Code
claude mcp add --transport http kestrel https://usekestrel.vercel.app/api/mcp
# .mcp.json
{
"mcpServers": {
"kestrel": { "type": "http", "url": "https://usekestrel.vercel.app/api/mcp" }
}
}curl -s -X POST https://usekestrel.vercel.app/api/mcp \ -H 'content-type: application/json' -d '{ "jsonrpc":"2.0","id":1,"method":"tools/call", "params":{"name":"check_bridge_parity","arguments":{}}}'
GET /llms.txt
The whole surface in one fetch
/llms.txt ↗ describes every page, endpoint and MCP tool in plain text for language models. /api/openapi.json ↗ is the OpenAPI 3.1 spec. Kestrel itself consumes Vibestarter's MCP server (https://app.vibestarter.xyz/mcp) and public campaigns API for Backer Shield enrichment.
x402 Bazaar
Discovery and validation
Every 402 carries x402 Bazaar metadata (extensions.bazaar input and output schema, plus outputSchema for v1 clients), and Kestrel re-attaches it to every settle. After its first CDP-settled call the endpoint is listed in the x402 Bazaar ↗ catalog that agents search. Check the 402 against Coinbase's keyless validator, then look the service up.
curl -s -X POST https://api.cdp.coinbase.com/platform/v2/x402/validate \
-H 'content-type: application/json' \
-d '{"resource":"https://usekestrel.vercel.app/api/v1/guard?mode=full","method":"GET"}'
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/search?query=robinhood%20chain%20pre-trade%20security&limit=5"