# Markets

> GET /v1/markets — lending markets (Aave V4 spokes) with supplied, borrowed, and per-reserve detail.

A **market** is the user-facing lending market a depositor picks:

| Protocol     | Market is…                   | Reserves in it                    |
| ------------ | ---------------------------- | --------------------------------- |
| Aave v2 / v3 | the **Pool** deployment      | every aToken reserve in that pool |
| Aave v4      | the **spoke** (not the hub)  | every reserve on that spoke       |
| SparkLend    | the **Pool**                 | every spToken reserve             |
| Compound v3  | the **Comet**                | one — the Comet's base asset      |
| Morpho Blue  | the **loan/collateral pair** | none — see below                  |

Ethereum alone runs Aave V3 Main, Lido, EtherFi and Horizon side by side over overlapping assets
with different collateral policies — which is exactly the distinction this surface exposes.

In Aave V4 the market is the **spoke** — `Main`, `Bluechip`, `EtherFi Cash` — not the liquidity hub.

Aave V4 separates the two: a hub pools liquidity per asset and owns the rate accounting, while
several spokes draw on it, each with its own collateral set and risk policy. Markets are keyed on
the spoke because that is what a depositor chooses; `hub_address` records which hub it draws from,
so markets sharing liquidity remain identifiable.

Every reserve inside a market is also served as its own [vault](/docs/api-reference/vaults) row —
`reserves[].vault_id` links the two — and a market's totals are aggregated from exactly those rows
at request time, so the two surfaces cannot disagree.

## GET /v1/markets

List lending markets with supplied/borrowed rollups.

### Query Parameters

| Parameter | Type             | Default            | Description                                                            |
| --------- | ---------------- | ------------------ | ---------------------------------------------------------------------- |
| page      | number           | 1                  | Page number                                                            |
| limit     | number           | 20                 | Results per page (1–100)                                               |
| protocol  | string           | —                  | Filter by protocol id, e.g. `aave`                                     |
| version   | string           | —                  | Filter by protocol version, e.g. `v4`                                  |
| chain     | number or string | —                  | Chain: integer id (e.g. `10`) or slug (e.g. `ethereum`, `solana`)      |
| sortBy    | string           | total_supplied_usd | `total_supplied_usd`, `total_borrowed_usd`, `reserve_count`, or `name` |
| sortOrder | string           | desc               | Sort order: `asc` or `desc`                                            |

### Example

```bash
curl "https://api.philidor.io/v1/markets?protocol=aave&version=v4"
```

### Response

```json
{
  "data": [
    {
      "id": "aave-v4-10-etherfi-cash",
      "protocol_id": "aave",
      "protocol_version": "v4",
      "chain_id": 10,
      "market_key": "etherfi-cash",
      "name": "Aave V4 EtherFi Cash",
      "address": "0xdffcc3536d932eb51df51a7f5fa407c4270d5308",
      "hub_address": "0x66753c4e3fc84f1ed0e3c267c927284e9d90c572",
      "source": "onchain_rpc",
      "reserve_count": 22,
      "borrow_observed_count": 2,
      "total_supplied_usd": 243900000,
      "total_borrowed_usd": 18800000,
      "utilization": 0.3542,
      "last_synced_at": "2026-08-23T18:00:00Z",
      "protocol_name": "Aave",
      "chain_name": "Optimism"
    }
  ],
  "meta": { "page": 1, "limit": 20, "total": 12, "totalPages": 1 }
}
```

### Two market shapes, two totals sources

Pool-shaped markets (Aave, Spark, Compound) are parents: vaults belong to them and
their totals are summed from those rows. Morpho Blue markets are one loan asset
against one collateral asset — they are not parents, because MetaMorpho vaults
allocate **across** many Blue markets rather than belonging to one.

`totals_source` always tells you which you are reading:

| Value          | Meaning                                         |
| -------------- | ----------------------------------------------- |
| `members`      | summed from this market's own `/v1/vaults` rows |
| `protocol_api` | reported by the protocol (pair-shaped markets)  |

Pair-shaped markets also carry `loan_asset_symbol`, `collateral_asset_symbol` and
`lltv`; these are `null` on pool-shaped markets, whose reserves each carry their own.

### How the totals are computed

| Field                | Definition                                                                   |
| -------------------- | ---------------------------------------------------------------------------- |
| `total_supplied_usd` | Sum of member reserve TVL — the supply side, borrowed amounts **included**   |
| `total_borrowed_usd` | Sum of `utilization × TVL` over reserves with an **observed** utilization    |
| `utilization`        | `total_borrowed_usd` over the supplied value of those observed reserves only |

A reserve whose utilization is unknown contributes to supplied but **not** to borrowed.
`borrow_observed_count` tells you how many of the `reserve_count` reserves had one, so a partly
observed market is visible as such rather than silently understated. When no reserve in a market
has an observed borrow side, `total_borrowed_usd` and `utilization` are `null` — never `0`.

Only active, non-shutdown reserves roll up into these numbers.

### `source`

| Value          | Meaning                                |
| -------------- | -------------------------------------- |
| `protocol_api` | Discovered from the protocol's own API |
| `onchain_rpc`  | Discovered on-chain                    |

Some Aave V4 instances are operated by third parties rather than the Aave DAO and are absent from
the official Aave API — EtherFi Cash on Optimism is one. Those are indexed directly from chain, from
a reviewed allowlist of hub addresses. Their numbers come from the same on-chain reads as every
other Aave V4 row.

---

## GET /v1/markets/\{id\}

Get a market with every reserve it contains.

### Path Parameters

| Parameter | Type   | Description                               |
| --------- | ------ | ----------------------------------------- |
| id        | string | Market ID, e.g. `aave-v4-10-etherfi-cash` |

The ID is `{protocol}-{version}-{chain}-{market_key}`. Version is part of it because one protocol
can run several generations whose market names collide — `Main` exists in both v3 and v4.

**IDs are stable.** A market's key is assigned the first time we see its contract address and is
never recomputed, so an upstream rename or the appearance of a similarly-named market elsewhere
cannot change an existing `/v1/markets/{id}` URL or re-point it at a different market.

### Example

```bash
curl https://api.philidor.io/v1/markets/aave-v4-10-etherfi-cash
```

### Response

```json
{
  "data": {
    "market": {
      "id": "aave-v4-10-etherfi-cash",
      "name": "Aave V4 EtherFi Cash",
      "chain_id": 10,
      "total_supplied_usd": 243900000,
      "total_borrowed_usd": 18800000,
      "reserve_count": 22
    },
    "reserves": [
      {
        "vault_id": "aave-10-0x8f2c...",
        "asset_symbol": "USDC",
        "asset_address": "0x0b2c639c533813f4aa9d7837caf62653d097ff85",
        "chain_id": 10,
        "supplied_usd": 49423733,
        "supply_apr": 0.0094,
        "borrowed_usd": 18596000,
        "borrow_apr": 0.03553,
        "borrow_apr_net": 0.03553,
        "utilization": 0.3763,
        "fee_rate": 0.1,
        "borrow_status": "unknown",
        "is_depositable": true,
        "deposit_capacity_usd": null,
        "risk_tier": "Core",
        "total_score": 7.4,
        "is_shutdown": false
      }
    ]
  }
}
```

`reserves` is ordered by supplied value descending and includes shutdown reserves, flagged via
`is_shutdown`, so a market's history stays readable. Follow `vault_id` into
[`GET /v1/vaults/{id}`](/docs/api-reference/vault-detail) for scores, exposures, and risk vectors.

## GET /v1/markets/\{id\}/events

Published risk events scoped to one lending market: incidents, bad debt and liquidation cascades (PHI-244). This is the surface that answers "what has gone wrong on this market" — raw protocol telemetry (routine repays, accruals, cap changes) is deliberately not part of it.

### Scoping semantics

Market-scoped events carry `scope: "protocol"` with the on-chain market id (for Morpho Blue, the bytes32 market id) as their entity key. Vault-scoped `BadDebt` rows attributed to the same market are included, since bad debt is socialized across the market's lenders but recorded per affected vault. A market with no vault allocation still produces market-scoped events — coverage does not depend on a MetaMorpho vault holding the market.

### Path Parameters

| Parameter | Description                                                |
| --------- | ---------------------------------------------------------- |
| `id`      | Market id, e.g. `morpho-v1-1-pt-reusd-10dec2026-usdc-91-5` |

### Query Parameters

| Parameter | Description                  |
| --------- | ---------------------------- |
| `limit`   | Max rows, 1-100 (default 50) |

### Example

```bash
curl "https://api.philidor.io/v1/markets/morpho-v1-1-pt-reusd-10dec2026-usdc-91-5/events"
```

### Response

```json
{
  "data": [
    {
      "id": 7771205,
      "market_id": "morpho-v1-1-pt-reusd-10dec2026-usdc-91-5",
      "event_type": "Incident",
      "severity": "Critical",
      "title": "Liquidation cascade detected on Morpho Blue market 0x1e9d6146...a4fc64",
      "description": "Cumulative liquidations of approximately $35,188,279 occurred ...",
      "scope": "protocol",
      "vault_id": null,
      "loss_amount_usd": null,
      "remediation_status": "unresolved",
      "tx_hash": null,
      "block_number": null,
      "occurred_at": "2026-08-25T04:48:35.000Z",
      "detected_at": "2026-08-25T18:20:00.000Z",
      "data": {
        "cumulative1hUsd": 35188279,
        "cascadeTrigger": "$35,188,279 liquidated within 1 hour"
      }
    }
  ]
}
```

Events are newest first. Only published, non-retracted rows are served.

## Access

`/v1/markets` is anonymous, like `/v1/vaults`. An API key raises rate limits.