Agent Integration Guide

Everything an agent — or the person wiring one up — needs to discover, connect to, and pay Cabrini. Human-friendly product pages live on the homepage; this page is the technical source of truth.

Discovery endpoints

Cabrini describes itself over every major agent discovery standard. All of these are free:

MCP capability card
/.well-known/mcp.json
A2A agent card
/.well-known/agent-card.json
llms.txt
/llms.txt
OpenAPI 3 spec
/openapi.json

Connect over MCP

Cabrini runs a streamable-HTTP MCP server at https://cabrini.ai/mcp. For Claude Code:

claude mcp add --transport http cabrini https://cabrini.ai/mcp

Or in any MCP client config that supports HTTP transports:

{ "mcpServers": { "cabrini": { "type": "http", "url": "https://cabrini.ai/mcp" } } }

MCP tools

ToolArgumentsPrice
query_minute_barsticker, date, interval?$0.025
list_tickersdate$0.005
query_rangeticker, start, end$0.01/day
query_batchtickers[], date$0.02/ticker
query_dailyticker, start, end$0.001/year
scan_marketdate, criteria$0.10
get_companyticker$0.005
get_fundamentalsticker$0.02
get_insidersticker$0.02
get_filingsticker, types?, sections?$0.01 / $0.05 w. sections
get_barsticker, interval, date/start/end$0.015/day
get_briefticker, lookback_days$0.25
get_pricingfree
get_statsfree

Intraday bar endpoints accept interval (3, 6, 9, 12, 15, 30, 60, or 240 minutes; default 3) and, like the daily endpoint, "adjusted": true for split-adjusted prices. Fundamentals and insider data come from SEC EDGAR filings, refreshed nightly.

Paid tools are payable inside MCP. Calling one without payment returns a tool result with isError: true whose structuredContent is an x402 PaymentRequired object. Sign it and retry the same tools/call with the payload in params._meta["x402/payment"]; the result comes back with settlement details in result._meta["x402/payment-response"]. This is the x402 MCP transport binding — the HTTP flow below remains available and costs the same.

tools/list prices every paid tool in its _meta, so an agent can budget from the catalog without a probe call.

# Retry a paid tool with payment inside MCP POST https://cabrini.ai/mcp { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "query_daily", "arguments": {"ticker": "AAPL", "start": "2024-01-01", "end": "2024-12-31"}, "_meta": {"x402/payment": "<base64-encoded-signed-payload>"} } }

Pay with x402

x402 v2, USDC on Base mainnet (eip155:8453). The full cycle:

# 1. Request without payment POST https://cabrini.ai/v1/query {"ticker": "AAPL", "date": "2024-01-15"} # 2. 402 response carries base64 payment terms HTTP/1.1 402 Payment Required PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6... # 3. Decode → {amount, receiver, network, asset} # 4. Sign USDC transfer for the exact amount # 5. Retry with signed payload POST https://cabrini.ai/v1/query X-PAYMENT: <base64-encoded-signed-payload> {"ticker": "AAPL", "date": "2024-01-15"} # 6. Data + receipt HTTP/1.1 200 OK PAYMENT-RESPONSE: <settlement-receipt>

Python example

# pip install x402 httpx eth-account import json, base64, httpx from eth_account import Account from x402.mechanisms.evm.exact.client import ExactEvmScheme from x402.mechanisms.evm import EthAccountSigner from x402 import x402ClientSync, parse_payment_required account = Account.from_key("0x...") # agent's funded wallet (USDC on Base) signer = EthAccountSigner(account) scheme = ExactEvmScheme(signer) client = x402ClientSync() client.register(network="eip155:8453", client=scheme) # 1. Hit endpoint → get 402 with payment terms r = httpx.post("https://cabrini.ai/v1/query", json={"ticker": "AAPL", "date": "2024-01-15"}, headers={"User-Agent": "my-agent/1.0"}) # 2. Parse terms, sign payment pr = parse_payment_required(json.loads(base64.b64decode( r.headers["payment-required"]))) payload = client.create_payment_payload(pr) encoded = base64.b64encode(json.dumps( payload.model_dump()).encode()).decode() # 3. Retry with payment → get data r2 = httpx.post("https://cabrini.ai/v1/query", json={"ticker": "AAPL", "date": "2024-01-15"}, headers={"X-PAYMENT": encoded}) bars = r2.json()["data"] # 130 bars: OHLC + pct change from daily open + volume

TypeScript example

// npm install x402-fetch viem import { wrapFetchWithPayment } from "x402-fetch"; import { privateKeyToAccount } from "viem/accounts"; const account = privateKeyToAccount("0x..."); const fetchWithPay = wrapFetchWithPayment(fetch, account); const res = await fetchWithPay("https://cabrini.ai/v1/query", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ticker: "AAPL", date: "2024-01-15" }), });

What you get back

Intraday endpoints — /v1/query, /v1/range, /v1/batch, /v1/bars — return absolute prices and normalised change on every bar, plus raw volume and transaction counts.

{"window_start": "2024-01-02T14:30:00", "timestamp": 1704204600000000000, "open": 191.52, "high": 191.76, "low": 191.43, "close": 191.68, "pct_open": 0.0, "pct_high": 0.001253, "pct_low": -0.000470, "pct_close": 0.000835, "volume": 47000, "transactions": 312}

pct_x = (bar_x − day_open) / day_open, so 0.0012 is +0.12%. Read close when you want the level; read pct_close when you are comparing across tickers or dates, where levels are not comparable. Both are in the same response — you never need a second call for either.

bar["close"] # 191.68 — the price day_open * (1 + bar["pct_close"]) # the same number, by construction

POST /v1/daily rolls these up to the session — open, high, low, close, volume, transactions and VWAP — and is the cheapest way to cover long histories.

One caveat: day_open is the first bar of the session and includes pre-market, so the percentages are measured from that rather than a third party’s 09:30 open, which can differ by a percent or two. The absolute prices are unaffected.

Volatility is precomputed so you don’t have to derive it. Every intraday response carries a day-level range_pct, and /v1/daily adds true_range_pct per day:

range_pct = (high − low) / open true_range_pct = (max(high, prev_close) − min(low, prev_close)) / prev_close

true_range_pct is the standard true range — it includes the overnight gap, range_pct does not. Both span the full session in our data, including pre- and post-market prints, so they read wider than a regular-session-only range.

Check the shape for free before paying anything: GET /v1/sample returns real bars in exactly this format, no payment and no parameters.

Operational notes for agents

TopicDetail
Rate limit30/min per IP unpaid; 120/min on /mcp. No limit on paid (x402-settled) requests.
Output formatIntraday bars carry absolute OHLC and fractional change from the daily open; /v1/daily adds session aggregates + VWAP
Free sampleGET /v1/sample — real bars, no payment, no parameters
HealthGET /health — check before retry loops
No data404 means weekend, holiday, or ticker not yet listed — don't pay-retry
IdempotencyIdentical request + valid payment always returns the same data
TimestampsNanoseconds since Unix epoch, UTC
Pricing sourceGET /v1/pricing is authoritative and machine-readable, free

A2A

The agent card at /.well-known/agent-card.json advertises capabilities (market-data, historical-prices, intraday-bars, fundamentals, sec-filings) and declares x402 as the authentication scheme. A2A clients should treat Cabrini as a data-provider agent with per-request payment and no session state.