Documentation

API reference

API operational

Overview#

defipipe is a historical DeFi data API serving point-in-time contract state: the result of calling a protocol's read functions at a specific block, reconstructed historically and indexed live. Every value is exact on-chain state, never an interpolation or a dashboard average.

The API is plain HTTPS + JSON.

Base URL
https://api.defipipe.io/v1

Every series is named by one canonical series ID. Browse and copy IDs from the catalog; each dataset page shows its live series with ready-made queries.

One query shape covers all work: /v1/data returns observations for up to 10 series on one shared time grid, at any granularity from per-block to daily. Every point at every granularity is a real on-chain observation and returns both the exact raw integer and the unit-scaled float, with the scaling metadata alongside.

Authentication#

Pass your API key as a bearer token, or in an x-api-key header. Keys look like dp_... and are managed from your dashboard.

Request
curl "https://api.defipipe.io/v1/data?..." \
  -H "Authorization: Bearer dp_your_key"

Requests without a key run on the free tier: 15m resolution and coarser over the trailing 90 days, for personal and evaluation use. See tiers for the full matrix.

Series IDs#

One canonical string identifies every series in storage, API calls, the SDK, and catalog URLs. String equality is identity equality.

Grammar
{chain}:{protocol}:{version}:{instance}[/{scope}]:{kind}:{metric}
SegmentMeaningExample
chainShort chain slugeth
protocol:versionProtocol template; also the catalog namespaceaave:v3
instanceThe contract address actually called (always the proxy)0x8787...4fa4e2
/scopeOptional. The logical market inside a singleton contract (an Aave reserve, a Uniswap V4 pool). Instance-per-pool protocols have no scope./weth
kindcall (read-function result), storage (direct storage-slot read), or derived (computed from other series)call
metricFor call: method[output], lowercased. For storage: a dotted field path. For derived: a slug.getreservedata[currentvariableborrowrate]
Examples
eth:aave:v3:0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2/weth:call:getreservedata[currentvariableborrowrate]
eth:uniswap:v3:0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640:call:slot0[sqrtpricex96]
eth:lido:v2:0xae7ab96520de3a18e5e111b5eaab095312d7fe84:call:totalsupply

IDs are normalized to lowercase. A non-lowercase ID is rejected as invalid, never coerced: the catalog displays ABI casing for readability, but every copy button hands you the canonical lowercase form. URL-encode IDs when they appear in a path segment (the / before a scope and the [] around outputs must be escaped).

GET/v1/data#

Observations for up to 10 series on one shared UTC time grid. Each value is the last observation at or before the grid boundary, resolved per block, never an average. No interpolation and no lookahead: what you get at each boundary is what the chain said at that moment, which makes the output safe for backtests.

ParamDescription
seriesstringrequiredComma-separated series IDs, max 10.
freqenumrequiredblock 1m 5m 15m 1h 4h 1d 7d. 1m/5m require Analyst, block requires Quant; block returns one row per sampled block with a top-level blocks grid.
from, toISO 8601requiredThe timeframe, e.g. from=2026-07-09&to=2026-07-12.
cursorstringThe next value from the previous page, verbatim.
limitintPoints per page, capped by your tier's page size.
fieldsstringPer-series arrays to include: values,raw,blocks (the default). Trim to fields=valuesfor 2-3x lighter payloads when you don't need auditability on every call. Metadata (unit, decimals, note) always ships.
Request
curl "https://api.defipipe.io/v1/data?series=eth:lido:v2:0xae7ab96520de3a18e5e111b5eaab095312d7fe84:call:totalsupply&freq=1h&from=2026-07-09&to=2026-07-12"
Response 200
{
  "freq": "1h",
  "tier": "free",
  "index": ["2026-07-11T00:00:00.000Z", "2026-07-11T01:00:00.000Z"],
  "next": null,
  "series": {
    "eth:lido:v2:0xae7ab96520de3a18e5e111b5eaab095312d7fe84:call:totalsupply": {
      "kind": "call",
      "unit": "steth",
      "decimals": 18,
      "values": [9177023.51929694, 9177032.49730232],
      "raw": ["9177023519296935673858921", "9177032497302323064753489"],
      "blocks": [25505640, 25505939],
      "note": "values = raw / 10^18; raw is the exact on-chain integer"
    }
  }
}

Every series returns three parallel arrays plus its scaling metadata: values holds unit-scaled floats, ready for analysis, scaled by the recipe in note; raw holds the exact on-chain integers as strings (uint256-safe, no float precision loss), so the float arithmetic is auditable: values = raw / 10^decimals(or the unit's recipe); blocks holds the source block behind each point, at every granularity.

Boundaries land on the UTC grid; the first boundary is the first grid point at or after from. A boundary with no observation at or before it returns null in all three arrays. Derived series (kind: "derived", e.g. AMM prices decoded from sqrtPriceX96) are computed at query time: they return raw: null and expose their formula (inputs + params) instead, so the computation is auditable via the raw values of the input series. Values newer than roughly 15 minutes may be revised in the rare event of a chain reorganization; everything older is final and never changes.

Pagination:windows larger than your tier's page size return a next cursor. Pass it back as cursor with the other params unchanged and repeat until next is null. The Python SDK does this transparently.

GET/v1/limits#

Machine-readable entitlements for whatever credential you present, so clients and agents can discover their limits up front instead of finding them through 429s.

Request
curl https://api.defipipe.io/v1/limits -H "Authorization: Bearer dp_your_key"
Response 200
{
  "tier": "analyst",
  "rate": { "sustained_per_min": 300, "burst": 1000 },
  "freqs": ["1m", "5m", "15m", "1h", "4h", "1d", "7d"],
  "history_days": 730,
  "page_size": 10000,
  "fields": ["values", "raw", "blocks"],
  "license": "individual commercial",
  "raw_values": "always included on /v1/data",
  "max_active_keys": 3,
  "docs": "https://defipipe.io/docs",
  "upgrade": "https://defipipe.io/pricing"
}

Rate limits#

Limits are token buckets keyed by API key (by IP on the free tier). The bucket holds a burst allowance well above the sustained rate and refills continuously at the sustained rate, because real workloads are bursty: a backtest pulling 50 series at startup should not need to trickle requests.

Every response carries x-ratelimit-limit, x-ratelimit-burst, and x-ratelimit-remaining. An empty bucket returns 429 with a Retry-After header and a JSON body:

Response 429
{
  "error": "rate limited",
  "tier": "free",
  "sustained_per_min": 30,
  "burst": 100,
  "retry_after_seconds": 2,
  "upgrade": "/pricing"
}

Tiers#

Free ($0)Analyst ($50/mo)Quant ($200/mo)
Granularity15m and coarser1m and coarserblock-level
HistoryTrailing 90dTrailing 2yFull, since deployment
Sustained rate30 rpm300 rpm1,000 rpm
Page size1,00010,00050,000
Licensepersonal and evaluation useindividual commercialteam; in-product redistribution with attribution
Active keys0310

Response fields are not a paid feature: every tier returns the unit-scaled floats, the exact on-chain integers, and the source block of every point (all included by default; trim with fields=values). The paid axes are resolution, history depth, page size, and rate.

Plans and checkout live on the pricing page.

Errors#

Errors are JSON with an error message. Tier-gated responses include tier and an upgrade link.

StatusMeaning
400Malformed request: invalid series ID, unknown freq, bad timestamps, bad cursor.
403Your tier does not cover the request (1m/5m without Analyst, block without Quant, history beyond your window, fields beyond your tier).
404Unknown series ID: not in the registry. The error lists the unknown IDs.
429Rate limited. Honor Retry-After.
5xxOur fault. Retry with backoff.

Python SDK#

Terminal
pip install defipipe

The SDK wraps /v1/data and returns pandas DataFrames, paging through cursors transparently. Set DEFIPIPE_API_KEY in your environment or pass api_key=.

Python
from defipipe import Client

# Multiple series on one time grid
df = Client().data([
    "eth:aave:v3:0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2/weth:call:getreservedata[currentvariableborrowrate]",
    "eth:lido:v2:0xae7ab96520de3a18e5e111b5eaab095312d7fe84:call:totalsupply",
], freq="1h", since="2026-07-09", until="2026-07-12")

df.corr()
df.attrs["units"]   # unit/decimals recipe per series
df.attrs["blocks"]  # per-point source block per series
Python
# Per-block rows with exact integers (API key required)
raw = Client(api_key="dp_...").data(
    ["eth:uniswap:v3:0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640:call:slot0[sqrtpricex96]"],
    freq="block", since="2026-07-11", until="2026-07-12", raw=True,
)
raw.head()  # one row per block; values are exact Python ints (uint256-safe)

Missing a pool or market? Coverage is registry-driven: request it on the feature-request board and approved requests ship with full backfilled history.

MCP server#

Give any MCP-capable agent (Claude, Cursor, and others) direct access to the catalog and the data endpoint. The server is a thin wrapper over this API: same tiers, same limits, same series IDs. Pick your surface:

claude.ai and the Claude apps (no install)

  1. Open Settings, then Connectors, then Add custom connector.
  2. Name it defipipe and paste the URL below. Leave the OAuth fields empty: the free tier is keyless.
  3. Click Add, then Connect, then start a new chat.
  4. Ask something like: "chart the ETH price against the Aave WETH borrow rate for the last 24 hours".
Remote MCP
https://mcp.defipipe.io/mcp

Claude Code

Terminal
claude mcp add defipipe -- npx -y @defipipe/mcp

Claude Desktop, Cowork, and other local MCP clients

Add this under claude_desktop_config.json(Settings, Developer) or your client's MCP config; new sessions pick it up. The DEFIPIPE_API_KEY entry is optional and unlocks keyed tiers.

Claude Desktop · Cowork
{
  "mcpServers": {
    "defipipe": {
      "command": "npx",
      "args": ["-y", "@defipipe/mcp"],
      "env": { "DEFIPIPE_API_KEY": "dp_your_key" }
    }
  }
}

Three tools: search_datasets, get_data, and get_limits. Without DEFIPIPE_API_KEY the server runs on the free tier; tier errors pass through with upgrade hints so agents can self-diagnose.