Morpho Midnight
How to query Morpho Midnight data with the API?
Discovery & listing
List all markets
Returns all Midnight markets, optionally filtered by chain, loan token, or collateral. Supported chains: Ethereum (1), Base (8453), Arc (5042) and Robinhood Chain (4663).
GET /v0/midnight/markets
All markets:
# All markets on Ethereum mainnet
curl "https://api.morpho.org/v0/midnight/markets?chain_ids=1"Filtered by token:
# USDC markets on Base with wETH as collateral
curl "https://api.morpho.org/v0/midnight/markets\
?chain_ids=8453\
&loan_assets=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\
&collateral_assets=0x4200000000000000000000000000000000000006"Get market detail
Immutable configuration for a single market: market family, loan token, maturity, collaterals (with LLTV, liquidation cursor, oracle), and gates. Does not include fees or total units (those live on the state endpoint).
GET /v0/midnight/markets/{market-id}
Each entry in the response's collaterals list carries exactly these fields:
token, lltv, liquidation_cursor, oracle
curl "https://api.morpho.org/v0/midnight/markets/0xcc9418ea594c6e658650aedd205ce4544b266b69493f56fd2adc65c14bd06738"
// Response - immutable market definition:
{
"data": {
"chain_id": 8453,
"market_id": "0xcc9418ea594c6e658650aedd205ce4544b266b69493f56fd2adc65c14bd06738",
"market_family_id": "0x9a6ece688006fb810141501154acfd1aa29ae7ac3753452f4931a092f2653f1f",
"loan_token": "0x4200000000000000000000000000000000000006", // WETH on Base
"maturity": 1784300400, // July 17, 2026 at 15:00 UTC
"rcf_threshold": "0",
"enter_gate": "0x0000000000000000000000000000000000000000",
"liquidator_gate": "0x0000000000000000000000000000000000000000",
"collaterals": [
{
"token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"lltv": "860000000000000000",
"liquidation_cursor": "300000000000000000",
"oracle": "0xD09048c8B568Dbf5f189302beA26c9edABFC4858"
}
]
}
}Market state & metrics
Get market state
Live market state: total units outstanding, fee configuration, and tick granularity. Separated from the market definition because these values change over time.
GET /v0/midnight/markets/{market-id}/state
curl "https://api.morpho.org/v0/midnight/markets/0xcc9418ea594c6e658650aedd205ce4544b266b69493f56fd2adc65c14bd06738/state"
// Response:
{
"data": {
"chain_id": 8453,
"market_id": "0xcc9418ea594c6e658650aedd205ce4544b266b69493f56fd2adc65c14bd06738",
"market_family_id": "0x9a6ece688006fb810141501154acfd1aa29ae7ac3753452f4931a092f2653f1f",
"last_indexed_block": "48408699",
"total_units": "1481439992020013", // total units outstanding
"tick_granularity": 4, // valid ticks must be multiples of this
"settlement_fee_schedule": [
{ "time_to_maturity_days": 0, "fee_cbp": "0" },
{ "time_to_maturity_days": 1, "fee_cbp": "0" },
{ "time_to_maturity_days": 7, "fee_cbp": "0" },
{ "time_to_maturity_days": 30, "fee_cbp": "0" },
{ "time_to_maturity_days": 90, "fee_cbp": "0" },
{ "time_to_maturity_days": 180, "fee_cbp": "0" },
{ "time_to_maturity_days": 360, "fee_cbp": "0" }
],
"current_settlement_fee_wad": "0",
"current_settlement_fee_cbp": "0", // interpolated for current TTM
"continuous_fee_rate": "0" // per-second, WAD-scaled
}
}Offers & rates
List policy-admitted books
The endpoint returns only active maturities admitted by the current policy. Unlisted and past maturities stay excluded even when requested with ids; if a maturity leaves the policy, its books disappear immediately, including books with existing offers.
Each book includes the top 3 ask and bid levels. Sorting: Sort by comma-separated fields (`id`, `ask`, `bid`, `maturity`). Prefix a field with `-` for descending. Max 3 fields.
GET /v0/midnight/books
By maturity:
curl "https://api.morpho.org/v0/midnight/books\
?chain_ids=8453\
&loan_tokens=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\
&sort=maturity"By best lend rate:
# Sort by best ask (lowest price = highest lend rate)
curl "https://api.morpho.org/v0/midnight/books\
?chain_ids=8453\
&loan_tokens=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\
&sort=ask"Get full book for a market
Each level sums all offers at that tick. Levels returned per side: Maximum levels returned per side. Default: 100. Maximum: 6745 (ticks 0 through 6744, inclusive).
GET /v0/midnight/books/{market-id}
Each price level carries exactly these fields:
tick, price, units, assets, count
curl "https://api.morpho.org/v0/midnight/books/0xcc9418ea594c6e658650aedd205ce4544b266b69493f56fd2adc65c14bd06738?depth=50"
// Response:
{
"data": {
"market_id": "0xcc9418ea594c6e658650aedd205ce4544b266b69493f56fd2adc65c14bd06738",
"chain_id": 8453,
"midnight": "0x2F7a3AA739ba5792Ce1b4eA046117f2C0095BCA6",
"loan_token": "0x4200000000000000000000000000000000000006",
"collaterals": [
{
"token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"lltv": "860000000000000000",
"liquidation_cursor": "300000000000000000",
"oracle": "0xD09048c8B568Dbf5f189302beA26c9edABFC4858"
}
],
"maturity": 1784300400,
"rcf_threshold": "0",
"enter_gate": "0x0000000000000000000000000000000000000000",
"liquidator_gate": "0x0000000000000000000000000000000000000000",
"asks": [
{ "tick": 42, "price": "952380952380952380", "units": "10000000000", "assets": "9523809523", "count": 3 },
{ "tick": 43, "price": "948000000000000000", "units": "18500000000", "assets": "17538000000", "count": 5 }
],
"bids": [
{ "tick": 41, "price": "956937000000000000", "units": "8000000000", "assets": "7655497000", "count": 2 }
]
}
}Compute rates from prices (TTM = seconds to maturity):
// lend rate (from asks): (1 / (price / 1e18) - 1) × 365×86400 / TTM
// borrow rate (from bids): (1 / (price / 1e18) - 1) × 365×86400 / TTMGet one side of the book
{side} is one of asks, bids.
GET /v0/midnight/books/{market-id}/{side}
# Just the asks (lender opportunities)
curl "https://api.morpho.org/v0/midnight/books/0xd92d...7614/asks?depth=100"
# Just the bids (borrower opportunities)
curl "https://api.morpho.org/v0/midnight/books/0xd92d...7614/bids?depth=100"Quotes & execution
Get a quote (execution plan)
Given a target amount (in assets or units) and a side, the Router returns execution-ready takeable offers sorted by best price with fallback excess.
GET /v0/midnight/books/{market-id}/{side}/quote
Each takeable offer's offer struct carries exactly these fields:
market, buy, maker, max_units, start, expiry, tick, group, callback, callback_data, receiver_if_maker_is_seller, ratifier, reduce_only, max_assets, continuous_fee_cap
Lend (take asks):
// "I want to lend 10,000 USDC" → take asks
curl "https://api.morpho.org/v0/midnight/books/0xd92d...7614/asks/quote\
?assets=10000000000\
&slippage=0.5\
&limit=10000"
// Response:
{
"data": {
"average_best_price": "947619047619047619", // realized target fill, using onchain per-offer rounding and rounded against the taker
"average_worst_price": "952300000000000000", // conservative adverse-placement bound across returned caps; not the caller's guard
"available_assets": "15000000000",
"available_units": "15750000000",
"takeable_offers": [
{
"market_id": "0xd92d...7614",
"units": "5000000000",
"offer": {
"market": {
"chain_id": 8453,
"midnight": "0x2F7a3AA739ba5792Ce1b4eA046117f2C0095BCA6",
"loan_token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"collaterals": [
{
"token": "0x4200000000000000000000000000000000000006",
"lltv": "860000000000000000",
"liquidation_cursor": "300000000000000000",
"oracle": "0x45093658BE7f90B63D7c359e8f408e503c2D9401"
}
],
"maturity": 1798761600,
"rcf_threshold": "0",
"enter_gate": "0x0000000000000000000000000000000000000000",
"liquidator_gate": "0x0000000000000000000000000000000000000000"
},
"buy": false,
"maker": "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
"max_units": "0",
"start": 1761922790,
"expiry": 1798761600,
"tick": 42,
"group": "0x000000000000000000000000000000000000000000000000000000000008b8f4",
"callback": "0x0000000000000000000000000000000000000000",
"callback_data": "0x",
"receiver_if_maker_is_seller": "0x7b093658BE7f90B63D7c359e8f408e503c2D9401",
"ratifier": "0x0000000000000000000000000000000000000002",
"reduce_only": false,
"max_assets": "5000000000",
"continuous_fee_cap": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
},
"ratifier_data": "0x4a8b...f201",
"valid_until": 1761922799,
"warning": null
}
]
}
}Borrow (take bids):
# "I want to borrow 5,000 USDC" → take bids
curl "https://api.morpho.org/v0/midnight/books/0xd92d...7614/bids/quote\
?assets=5000000000\
&slippage=0.5\
&limit=10000"
# Same response shape - but offers have buy=true (lenders' buy-offers)By units:
# Quote by units instead of assets
curl "https://api.morpho.org/v0/midnight/books/0xd92d...7614/asks/quote\
?units=10500000000"List takeable offers (raw)
Individual executable offers with the full offer struct and ratifier data. Use when building custom routing or analysis.
By market side:
GET /v0/midnight/books/{market-id}/{side}/takeable-offers
Across markets, by maker:
GET /v0/midnight/takeable-offers
By market side:
curl "https://api.morpho.org/v0/midnight/books/0xd92d...7614/asks/takeable-offers"By maker:
# All active offers from a specific maker
curl "https://api.morpho.org/v0/midnight/takeable-offers\
?maker=0xMakerAddress...\
&limit=100"Takeability warnings
The warning field explains why only part of an offer, or none of it, can be taken right now. Makers get it on their own offers from GET /v0/midnight/takeable-offers. A null value means the offer's complete remaining capacity is takeable. A non-null value gives the primary reason why more of the active offer is not currently takeable. On the book listing (GET /v0/midnight/books/{market-id}/{side}/takeable-offers) and quote (GET /v0/midnight/books/{market-id}/{side}/quote) endpoints, warning is deprecated: it will become null, then be removed. Use units there instead. On the book listing, it gives how much of each offer can be taken. On a quote, it's a per-offer cap, and the caps together can exceed the requested size. See Takeability warnings for how to read and surface them.
| Code | Meaning |
|---|---|
| Limit how much can be taken (possibly to zero) | |
MAKER_LIQUIDITY | Maker-controlled liquidity cannot back more units. |
MAKER_ALLOWANCE | The maker's loan-token approval cannot back more units. |
SOURCE_LIQUIDITY | The underlying protocol cannot currently release more liquidity. |
REDUCE_ONLY | More units would increase rather than reduce the maker's position. |
POSITION_CAPACITY | The maker's credit or debt position has no room for more units. |
AMOUNT_ROUNDING | Asset and unit rounding prevents another meaningful unit from executing. |
SINGLE_TAKE_LIMIT | The offer exceeds the maximum units allowed in one take. |
| None of it can be taken right now | |
CALLBACK_NOT_REGISTERED | The callback was not registered to the maker before the offer was submitted. |
RATIFIER_NOT_AUTHORIZED | The maker does not currently authorize the offer's ratifier. |
SIMULATION_FAILED | Router simulation failed for the offer's group and market. |
RESTRICTED_TAKER | The offer is reserved for a specific taker and cannot be taken publicly. Only the reserved taker can take it. |
ROOT_CANCELED | The offer's Ecrecover Merkle root was permanently canceled. |
ROOT_NOT_RATIFIED | The maker has not currently ratified the offer's Setter Merkle root. |
SIGNER_NOT_AUTHORIZED | The maker does not currently authorize the offer tree's signer. |
BELOW_MINIMUM_SIZE | The offer was removed after its supported size fell below policy minimum. |
For codes in the "Limit how much can be taken" group, the offer's units on GET /v0/midnight/takeable-offers shows how much can still be taken.
Some codes also return extra fields (limit_units, root, signer, observed_assets, minimum_assets). They're deprecated and not listed here, so rely on code alone.
Example:
// One takeable offer (excerpt; other fields omitted, values illustrative)
{
"market_id": "0xa249f0b3ffe8891c96ec93fd9c7d00e479da04e4ffe2f2502ea0e5db8eabc75d",
"units": "1000000",
// offer, ratifier_data, ...
"warning": {
"code": "MAKER_ALLOWANCE"
}
}Position tracking
List user positions
Returns all positions for a user across markets. Includes cost_basis and effective_rate_wad inline. Position types: lend, borrow, collateral_only.
GET /v0/midnight/users/{user-address}/positions
All positions:
curl "https://api.morpho.org/v0/midnight/users/0xAlice.../positions"
// Response:
{
"cursor": null,
"data": [
{
"chain_id": 8453,
"market_id": "0xd92d...7614",
"user_address": "0xAlice...",
"loan_token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"maturity": 1798761600,
"credit": "10500000000",
"pending_fee": "12000",
"last_loss_factor": "0",
"loss_factor": "0",
"debt": "0",
"cost_basis": "952380952380952380",
"effective_rate_wad": "52000000000000000",
"effective_apr": 0.0508,
"collaterals": [],
"created_at": 1761922790,
"type": "lend"
}
]
}Lend only:
curl "https://api.morpho.org/v0/midnight/users/0xAlice.../positions?types=lend"Borrow only:
curl "https://api.morpho.org/v0/midnight/users/0xAlice.../positions?types=borrow"Get position detail
Raw position state in a specific market. Does not include cost_basis or effective_rate_wad (use the performance endpoint for those).
GET /v0/midnight/markets/{market-id}/users/{user-address}/position
curl "https://api.morpho.org/v0/midnight/markets/0xd92d...7614/users/0xBob.../position"
// Response (borrow position):
{
"data": {
"chain_id": 8453,
"market_id": "0xd92d...7614",
"user_address": "0xBob...",
"loan_token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"maturity": 1798761600,
"credit": "0",
"pending_fee": "0",
"last_loss_factor": "0",
"loss_factor": "0",
"debt": "9000000000", // debt to clear
"collaterals": [
{
"token": "0x4200000000000000000000000000000000000006", // WETH on Base
"amount": "2000000000000000000" // 2 WETH
},
{
"token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
"amount": "10000000" // 10 USDC
}
],
"type": "borrow",
"last_indexed_block": "47457420"
}
}Get position performance
Cost basis and effective rate for P&L computation. Uses average cost accounting.
GET /v0/midnight/markets/{market-id}/users/{user-address}/position/performance
curl "https://api.morpho.org/v0/midnight/markets/0xd92d...7614/users/0xAlice.../position/performance"
// Response:
{
"data": {
"chain_id": 8453,
"market_id": "0xd92d...7614",
"user_address": "0xAlice...",
"type": "lend",
"cost_basis": "952380952380952380",
"effective_rate_wad": "52000000000000000",
"effective_apr": 0.0508,
"last_indexed_block": "47457420",
"accounting_method": "average_cost"
}
}List all positions in a market
Find all borrowers, cross-reference with oracle prices to find unhealthy positions.
GET /v0/midnight/markets/{market-id}/positions
# All borrowers in a market
curl "https://api.morpho.org/v0/midnight/markets/0xd92d...7614/positions?types=borrow"
# Active positions only (market not yet matured)
curl "https://api.morpho.org/v0/midnight/markets/0xd92d...7614/positions\
?types=borrow\
&active_only=true"Transaction history
User transactions
All onchain events for a user. Filter by event_types to focus on specific actions. Valid values:
borrow, lend, exit_lend_primary, exit_lend_secondary, exit_borrow_primary, exit_borrow_secondary, partial_liquidation, full_liquidation, withdraw_collateral, supply_collateral, roll
lend- entered a lending position (bought units)exit_lend_primary- redeemed credit (1:1 withdrawal)exit_lend_secondary- sold credit units earlyborrow- entered a borrowing position (sold units)exit_borrow_primary- repaid debtexit_borrow_secondary- bought units to close debt earlysupply_collateral- deposited collateralwithdraw_collateral- withdrew collateralpartial_liquidation/full_liquidation- liquidations; events include the borrower, collateral, seized assets, repaid units, post-maturity mode, bad debt, and latest loss factorroll- the borrower's Midnight debt and collateral were rolled into a Morpho Blue market under a rolling configuration the borrower authorized; events include the destination market, debt and collateral moved, and the incentive paid to the caller
GET /v0/midnight/users/{user-address}/transactions
Lending activity:
curl "https://api.morpho.org/v0/midnight/users/0xAlice.../transactions\
?event_types=lend,exit_lend_primary,exit_lend_secondary"Borrowing activity:
curl "https://api.morpho.org/v0/midnight/users/0xBob.../transactions\
?event_types=borrow,exit_borrow_primary,exit_borrow_secondary,supply_collateral,withdraw_collateral"Market transactions
GET /v0/midnight/markets/{market-id}/transactions
# All activity in a market since a specific time
curl "https://api.morpho.org/v0/midnight/markets/0xd92d...7614/transactions?created_at_gte=1719000000"Offer management
List offer groups
Track a maker's consumption groups and which offers belong to them. statuses selects one or
more lifecycle states (groups matching any of them are returned) and defaults to active.
Groups can also be narrowed to verified Blue callbacks with
callback_type=blue_buy, and to Midnight market families with market_family_ids.
GET /v0/midnight/users/{user-address}/offer-groups
# All active offer groups for this maker (default lifecycle state)
curl "https://api.morpho.org/v0/midnight/users/0xMaker.../offer-groups"
# Active offer groups filtered by market and group
curl "https://api.morpho.org/v0/midnight/users/0xMaker.../offer-groups\
?market_ids=0xd92d...7614\
&groups=0xMyGroupId..."
# Expired offer groups with verified Blue-buy callbacks
curl "https://api.morpho.org/v0/midnight/users/0xMaker.../offer-groups\
?statuses=expired\
&callback_type=blue_buy"Mempool
Validate offers before publishing
Check whether the Router will index your offers. Payload is version byte + 4-byte big-endian gzip length + gzip(ABI-encoded (Offer, bytes ratifierData)[]). Optionally pass a timestamp to validate against a specific policy snapshot.
POST /v0/midnight/mempool/validate
Current policy:
curl -X POST "https://api.morpho.org/v0/midnight/mempool/validate" \
-H "Content-Type: application/json" \
-d '{
"chain_id": 8453,
"payload": "0x01..."
}'
# Success (Router will index):
{ "data": { "issues": [] } }
# Issues found (Router will ignore):
{ "data": { "issues": [{ "rule": "blue_callback", "details": null }] } }At a specific time:
# Validate against the policy snapshot active at a specific time
# Uses the latest 15:00 UTC boundary at or before the given timestamp
curl -X POST "https://api.morpho.org/v0/midnight/mempool/validate\
?timestamp=2026-06-28T12:00:00Z" \
-H "Content-Type: application/json" \
-d '{
"chain_id": 8453,
"payload": "0x01..."
}'Pagination & filtering
List endpoints support cursor-based pagination. The response includes a cursor field - pass it as a query parameter to get the next page.
# First page
curl "https://api.morpho.org/v0/midnight/markets?chain_ids=8453"
// Response includes:
{ "cursor": "***...", "data": [...] }
# Next page - pass the cursor
curl "https://api.morpho.org/v0/midnight/markets?chain_ids=8453&cursor=***..."
// cursor is null when there are no more pagesThe markets list carries the richest filter set - other list endpoints follow the same conventions:
All these parameters are optional query parameters.
| Name | Type | Description |
|---|---|---|
chain_ids | array | Filter by chain ids. Supported chains: Ethereum (1), Base (8453), Arc (5042), and Robinhood Chain (4663). Required when any address filter is provided. |
market_ids | array | Filter by Midnight market ids. These ids are globally unique. |
market_family_ids | array | Filter by Midnight market family ids. A family contains markets whose immutable parameters differ only by maturity. |
loan_assets | array | Filter by loan token addresses. Combine with chain_ids; lowercase input is checksummed. |
collateral_assets | array | Filter by collateral token addresses. Combine with chain_ids; lowercase input is checksummed. |
oracle_addresses | array | Filter by collateral oracle addresses. Combine with chain_ids; lowercase input is checksummed. |
enter_gates | array | Filter by enter gate addresses. Combine with chain_ids; lowercase input is checksummed. |
liquidator_gates | array | Filter by liquidator gate addresses. Combine with chain_ids; lowercase input is checksummed. |
maturities | array | Filter by exact maturity timestamps, in unix seconds. |
active_only | string | When true, enforces maturity strictly after the current timestamp. |
maturity_gte | anyOf | Filter for maturities greater than or equal to this unix timestamp. |
maturity_lte | anyOf | Filter for maturities less than or equal to this unix timestamp. |
total_units_gte | string | Filter for total units greater than or equal to this value. |
total_units_lte | string | Filter for total units less than or equal to this value. |
lend_depth_gte | string | Filter for cached lend-side order-book depth, in loan-token units, greater than or equal to this value. |
lend_depth_lte | string | Filter for cached lend-side order-book depth, in loan-token units, less than or equal to this value. |
borrow_depth_gte | string | Filter for cached borrow-side order-book depth, in loan-token units, greater than or equal to this value. |
borrow_depth_lte | string | Filter for cached borrow-side order-book depth, in loan-token units, less than or equal to this value. |
listed | string | Filter by listing status. When true, returns only markets surfaced by the app trust layer; when false, only unlisted markets. Omit to return both. |
sort_by | string | Sort field for cursor pagination. |
sort_direction | string | Sort direction for cursor pagination. |
limit | integer | Maximum number of items to return. |
cursor | string | Opaque cursor from a previous page response. |