API Documentation
The pigi.finance Data API (v1) gives programmatic access to the same DeFi vault data that powers this site — current metrics, daily history, aggregated stats, benchmark rates, and hack/loss history. All responses are JSON and CORS is open, so you can call it from a server or a browser.
Need a key? Request access on the API page. You'll receive a key like pigi_….
Machine-readable spec: OpenAPI 3 (openapi.yaml) — import it into Postman, Swagger UI, or your codegen of choice.
Authentication
Auth is a two-step API key → token exchange. Your long-lived API key is secret; you trade it for a short-lived JWT (≈1 hour) and send that as a Bearer token on every request. When the token expires, exchange the key again.
# 1. Exchange your API key for a short-lived token
curl -X POST https://pigi.finance/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"apiKey":"pigi_live_xxxxxxxxxxxxxxxx"}'
# → { "token": "<JWT>", "expiresIn": 3600, "plan": "free" }
# 2. Call any data endpoint with the token
curl "https://pigi.finance/api/v1/vaults?limit=5" \
-H "Authorization: Bearer <JWT>"Keep your API key server-side. The short-lived token is safe to use from the browser. A token from this API can't be used on any other pigi endpoint and vice-versa.
Endpoints
/api/v1/auth/tokenNo authExchange an API key for a short-lived bearer token.
Request body (JSON)
| Parameter | Type | Description |
|---|---|---|
| apiKey | string | Your secret API key. |
Response
{ "token": "<JWT>", "expiresIn": 3600, "plan": "free" }/api/v1/vaultsBearer tokenList vaults with optional filters and pagination.
Query parameters (all optional)
| Parameter | Type | Description |
|---|---|---|
| protocol_name | string | Filter by protocol (e.g. Aave, Morpho, Euler, Uniswap). |
| chain_id | number | Filter by chain id (e.g. 1, 8453, 42161). |
| strategy_id | number | Filter by a strategy (compat) id. |
| tvl_filter | string | TVL band, e.g. gte_1m, gte_5m, non_na, na. |
| apr_filter | string | APR band, e.g. gt_5, gt_10, lte_10, non_na, na. |
| age_filter | string | Pool age, e.g. new, 3mo, 6mo, 12mo, non_na, na. |
| limit | number | Page size. Default 100, max 1000. |
| offset | number | Rows to skip. Default 0. |
Response
{
"data": [ { /* Vault */ } ],
"pagination": { "total": 1342, "limit": 100, "offset": 0, "hasMore": true },
"availableFilters": { "protocol_names": [...], "chain_ids": {...}, "all_chain_ids": [...] }
}/api/v1/vaults/:idBearer tokenFetch a single vault by its pool id. Returns 404 if not found.
Response
{ "data": { /* Vault */ } }/api/v1/vaults/:id/historyBearer tokenDaily time-series for a vault. Here :id is the strategy id (strategy_id on the Vault object).
Query parameters
| Parameter | Type | Description |
|---|---|---|
| range | string | Window: 7D, 30D, 90D, or 180D. Default 7D. |
Response
{
"data": [
{ "timestamp": "2026-06-23T00:00:00Z", "tvl": 12500000, "apr": 6.21,
"apy": 6.40, "ra_apr": 5.11, "tvl_30d_ma": 12100000, "apr_30d_ma": 6.05,
"apy_30d_ma": 6.18 }
],
"lastTvl": 12500000, "lastApr": 6.21, "lastApy": 6.40, "lastRaApr": 5.11,
"lastTvl30dMa": 12100000, "lastApr30dMa": 6.05, "lastApy30dMa": 6.18, "lastRaApr30dMa": 4.95
}ra_apr is risk-adjusted APR: APR minus a penalty derived from the vault's published overall risk score (0–100, higher = safer); it is null when the vault has no published assessment.
/api/v1/vaults/:id/statsBearer tokenAggregated stats over fixed windows for a vault (:id = strategy id). Omit period to get all windows.
Query parameters
| Parameter | Type | Description |
|---|---|---|
| period | string | weekly, monthly, quarterly, yearly, or lifetime (optional). |
Response
{
"weekly": { "tvl_low": 11.8e6, "tvl_high": 12.6e6, "apr": 6.1, "apy": 6.3,
"inflows": 2.1e5, "period_start": "...", "period_end": "...",
"cagr": 6.2, "volatility": 1.4, "sharpe": 1.8, "sortino": 2.3 },
"monthly": { ... }, "quarterly": { ... }, "yearly": { ... },
"lifetime": { ... }
}inflows is the net TVL change over the window (last day − first day): positive = net inflow, negative = net outflow. It is TVL-based, so it also reflects yield earned over the window, not just deposits/withdrawals. Each window also includes risk/return metrics — cagr, volatility, sharpe, and sortino — plus a lifetime (all-time) window.
/api/v1/vaults/:id/holdersBearer tokenThe vault's holder list — :id = strategy id. Each entry is an address with its balance and share of the vault's TVL. (Vault.holders gives just the holder count.)
Response
{
"data": [
{ "address": "0x1a2b…c3d4", "balance": 12345.6, "share_pct": 4.2 }
]
}/api/v1/ratesBearer tokenDaily history of the DeFi Base Rate — the mean yield across the tracked stablecoin (stable) and ETH (eth) vault sets — plus the 3-month U.S. T-Bill risk-free rate (tbills). No parameters; each series is sorted oldest to newest.
Response
{
"stable": [ { "timestamp": "2026-06-23T00:00:00Z", "apr": 5.4, "apy": 5.55,
"apr_30d_ma": 5.2, "apy_30d_ma": 5.34 } ],
"eth": [ { "timestamp": "2026-06-23T00:00:00Z", "apr": 3.1, "apy": 3.15,
"apr_30d_ma": 3.0, "apy_30d_ma": 3.05 } ],
"tbills": [ { "timestamp": "2026-06-23T00:00:00Z", "rate": 3.79 } ]
}/api/v1/hacksBearer tokenHack and loss events — every tracked DeFi exploit plus a reference set of major TradFi banking losses, the dataset behind our DeFi vs TradFi losses analysis. Each event carries its date, the protocol or institution, the amount lost in USD, and — for DeFi — what kind of protocol was hit.
Query parameters (all optional)
| Parameter | Type | Description |
|---|---|---|
| category | string | defi, tradfi, or all. Default all. |
| type | string | DeFi, Dexes, or Bridges (case-insensitive). DeFi events only — TradFi rows carry no type, so this excludes them. |
| from | string | Only events on/after this date — YYYY-MM-DD or ISO 8601. |
| to | string | Only events on/before this date (inclusive of the whole day). |
| min_amount | number | Only events at or above this USD amount. |
| sort | string | date_asc (default), date_desc, amount_desc, or amount_asc. |
| limit | number | Page size. Default 100, max 1000. |
| offset | number | Rows to skip. Default 0. |
Response
{
"data": [
{ "id": 1937, "date": "2022-03-28T23:00:00+00:00", "name": "Ronin",
"amount_hacked": 624000000, "category": "defi", "type": "Bridges" }
],
"summary": { "count": 285, "total_amount_hacked": 18824475500,
"first_date": "2020-09-28T23:00:00+00:00",
"last_date": "2026-07-10T00:00:00+00:00" },
"pagination": { "total": 285, "limit": 100, "offset": 0, "hasMore": true }
}summary covers the entire filtered set, not just the returned page — so total losses for a window can be read without paging through every event.
type is present on DeFi events only, and is one of DeFi (lending, yield, staking, stablecoins), Dexes, or Bridges. TradFi events are bank failures, which the taxonomy does not describe, so they omit the field.
Example — DeFi losses in 2025, biggest first
curl -H "Authorization: Bearer $TOKEN" \ "https://pigi.finance/api/v1/hacks?category=defi&from=2025-01-01&to=2025-12-31&sort=amount_desc"
Example — total ever lost to bridge exploits
curl -H "Authorization: Bearer $TOKEN" \ "https://pigi.finance/api/v1/hacks?type=bridges&limit=1" # read summary.total_amount_hacked
/api/v1/usageBearer tokenYour request count for the current calendar month (UTC) and your plan limit.
Response
{
"clientId": 1, "plan": "free",
"period": { "start": "2026-06-01T00:00:00Z", "end": "2026-07-01T00:00:00Z" },
"used": 1423, "limit": 100000, "remaining": 98577
}limit and remaining are null when your plan has no cap.
/api/v1No authDiscovery index — lists the available endpoints and the docs URL.
The Vault object
Returned by /vaults and /vaults/:id.
| Parameter | Type | Description |
|---|---|---|
| id | number | Pool id (use for /vaults/:id). |
| strategy_id | number | Strategy id (use for /history and /stats). |
| protocol_name | string | Protocol, e.g. Aave, Morpho, Euler. |
| chain_id | number | Chain id. |
| pool_name | string | Human-readable vault/pool name. |
| pool_address | string | On-chain pool/vault address. |
| asset_address | string | null | Underlying asset address. |
| type | string | Pool-type category (Lending, AMM, …). |
| tvl_30d_ma | number | 30-day moving-average TVL (USD). |
| apr_30d_ma | number | 30-day moving-average APR (%). |
| holders | number | null | Holder count. |
| pool_creation_date | string | null | ISO date the pool was created. |
| updated_at | string | null | Block-time of the newest data point. |
| tvl_flow_1d | number | null | 1-day TVL flow. |
| tvl_flow_7d | number | null | 7-day TVL flow. |
| apr_trend_1d | number | null | 1-day APR trend. |
| risk_band | string | null | Published pigi risk band: A (safest) … F. null = not assessed yet. |
| active_addresses | number | null | Count of active holder addresses. |
| deposit_count | number | null | Number of deposit events. |
| tvl_concentration_top10pct | number | null | % of TVL held by the top 10% of holders. |
Errors & conventions
Errors are JSON: { "error": "<code>" }. Successful data responses are cached for 5 minutes (Cache-Control: public, max-age=300); auth and usage responses are never cached. Every authenticated request counts toward your monthly usage. Each response carries RateLimit-Limit/RateLimit-Remaining/RateLimit-Reset; once you reach your plan's monthly limit, requests return 429 (with Retry-After) until it resets at the start of the next UTC month.
| Parameter | Type | Description |
|---|---|---|
| 400 | missing_api_key / invalid_id | Malformed request. |
| 401 | invalid_api_key / invalid_token | Bad key on exchange, or missing/expired token. |
| 403 | client_suspended | Your API client is suspended. |
| 404 | not_found | No vault with that id. |
| 405 | method_not_allowed | Wrong HTTP method for the route. |
| 429 | rate_limit_exceeded | Monthly request limit reached — see RateLimit-* / Retry-After; resets at the start of next month (UTC). |
| 500 | internal_error | Unexpected server error. |