Docs

List active Midnight offer groups for a user

Cursor-paginated list of a user's active offer groups with nested active offers.

Active offers have started, have not passed their offer expiry or market maturity, and still have remaining group capacity. Asset-capped offers are considered fully consumed when consumed >= max_assets; unit-capped offers are fully consumed when consumed >= max_units. Fully consumed offers are excluded, and a group is omitted entirely when no active offers remain in it. Each group returns the max expiry across all unexpired and unmatured offers in the whole group, including future-start offers, one deterministic representative offer limit (max_units, max_assets), the latest group-level consumed value, and all active offers in that group matching the non-market request filters. Each offer includes both market_id and the immutable market config used to derive it, because uncreated markets cannot be decoded from market_id alone.

Filters. market_ids filters the group page to groups containing at least one active offer in any requested market, but nested offers are not narrowed by market_ids; all active sibling offers in each returned group remain visible. chain_ids, loan_assets, and groups filter both the group page and nested offers. listed=true returns only groups where every active offer is on a listed market; listed=false returns groups with at least one active offer on an unlisted market. loan_assets matches loan token addresses across all chains unless chain_ids is also provided. The group-level expiry is computed for the whole offer group and is not narrowed by market_ids or loan_assets. created_at_gte and created_at_lte filter by the first active matching offer created in each group. market_ids, loan_assets, and groups are capped at 20 values.

Pagination. Response follows the list envelope: { cursor, data }. Pagination is over groups; nested offers are not split across pages. Sort groups with sort_by=id|created_at and sort_direction=asc|desc.

Path Parameters

user-address*string

User address whose active offer groups should be listed.

Query Parameters

chain_ids?array<>

Filter by chain ids. Supported chains: Base (8453).

Itemsitems <= 100
market_ids?array<string>

Filter groups to those containing active offers in these Midnight markets. Nested offers are not narrowed by this filter.

Itemsitems <= 20
loan_assets?array<string>

Filter nested active offers by loan token addresses. Combined with market_ids and groups using AND semantics.

Itemsitems <= 20
groups?array<string>

Filter by offer group ids. Combined with market_ids and loan_assets using AND semantics.

Itemsitems <= 20
created_at_gte?|

Filter for group created_at greater than or equal to this unix timestamp.

created_at_lte?|

Filter for group created_at less than or equal to this unix timestamp.

listed?string

Filter by market listing status. When true, returns only groups where every active offer is on a listed market; when false, groups with at least one active offer on an unlisted market. Omit to return both.

Value in"true" | "false"
sort_by?string

Sort field for group cursor pagination.

Default"id"
Value in"id" | "created_at"
sort_direction?string

Sort direction for group cursor pagination.

Default"asc"
Value in"asc" | "desc"
limit?integer

Maximum number of groups to return.

Default100
Range1 <= value <= 100
cursor?string

Opaque cursor from a previous page response.

Length1 <= length <= 4096

Response Body

application/json

application/json

const baseUrl = "https://api.morpho.org";const userAddress = "0x958eB498a4172EA513c79b09E7f064070C5b1917";const url = new URL(`${baseUrl}/v0/midnight/users/${userAddress}/offer-groups`);url.searchParams.set("chain_ids", "8453");const response = await fetch(url, {  headers: {    accept: "application/json",  },});if (!response.ok) throw new Error(await response.text());const body = await response.json();
{
  "cursor": "eyJzb3J0QnkiOiJpZCIsInNvcnREaXJlY3Rpb24iOiJhc2MiLCJjaGFpbklkIjo4NDUzLCJncm91cCI6IjB4MGJhYjUxZmFiNjQxNTdiYzEwMTFjZTY1YjliZjliMmIxMWYyMDJiOGE3YWI3NmI0MDhjZjQwYjhhZGYwNjlkMyJ9",
  "data": [
    {
      "id": "0x0bab51fab64157bc1011ce65b9bf9b2b11f202b8a7ab76b408cf40b8adf069d3",
      "chain_id": 8453,
      "created_at": 1783584485,
      "expiry": 1784300399,
      "max_units": "0",
      "max_assets": "80000000000000",
      "consumed": "0",
      "offers": [
        {
          "market_id": "0xcc9418ea594c6e658650aedd205ce4544b266b69493f56fd2adc65c14bd06738",
          "market": {
            "loan_token": "0x4200000000000000000000000000000000000006",
            "maturity": 1784300400,
            "rcf_threshold": "0",
            "enter_gate": "0x0000000000000000000000000000000000000000",
            "liquidator_gate": "0x0000000000000000000000000000000000000000",
            "collaterals": [
              {
                "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "lltv": "860000000000000000",
                "liquidation_cursor": "300000000000000000",
                "oracle": "0xD09048c8B568Dbf5f189302beA26c9edABFC4858"
              }
            ]
          },
          "created_at": 1783584485,
          "buy": true,
          "maker": "0x958eB498a4172EA513c79b09E7f064070C5b1917",
          "max_units": "0",
          "max_assets": "80000000000000",
          "continuous_fee_cap": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
          "start": 1783584483,
          "expiry": 1784300399,
          "tick": 4408,
          "callback": "0x0000000000000000000000000000000000000000",
          "callback_data": "0x",
          "receiver_if_maker_is_seller": "0x0000000000000000000000000000000000000000",
          "ratifier": "0xd6e70365C8E8DDa9a4ca662C07bbE663b017755E",
          "reduce_only": false
        }
      ]
    }
  ]
}
{
  "error": {
    "code": "INVALID_CURSOR",
    "message": "Invalid user group cursor",
    "details": null,
    "request_id": "f0e1d2c3-b4a5-4968-8728-1c0d1e2f3a4b"
  }
}