Merkl Developer Portal logo

Positions Analytics

Access detailed position and transaction data using Merkl States Analytics API

Get User Position History

Fetch historical position data for a user across opportunities (pools, lending markets, etc.):

GET /v4/analytics/positions/{userAddress}/{chainId?}

Path Parameters:

  • userAddress (required): The user's wallet address
  • chainId (optional): Chain ID to filter by

Query Parameters:

  • includeHistory (optional, boolean): Include history snapshots. Defaults to false
  • includeMerklAPIData (optional, boolean): Include Merkl API data (opportunity ID, APR records). Defaults to false
  • maxTimestamp (optional, numeric): Maximum timestamp to fetch data until
  • protocol (optional, string): Filter by protocol name (e.g., uniswap). Case-insensitive partial match
  • identifier (optional, string): Filter to a single opportunity identifier (pool address, market id, etc.). Case-insensitive exact match. Scoped in the database, so first/after paginate over the matched opportunity only
  • indexingIds (optional, string[]): Keep only these indexingIds (comma-separated or repeated). Also scoped in the database. Combined with identifier as an intersection
  • first (optional, numeric, 1–1000): Number of historical snapshots to return. Defaults to 1000
  • after (optional, string): Cursor for pagination. Use the endCursor from the previous response

Examples:

All positions for a user on Ethereum:

GET /v4/analytics/positions/0x1234.../1?includeHistory=true

Paginate through results:

GET /v4/analytics/positions/0x1234.../1?first=50&after=<endCursor>

A single opportunity, paginated (the filter is applied in the database, so every page is full):

GET /v4/analytics/positions/0x1234.../1?identifier=0xPoolAddress&includeHistory=true&first=50

Get Positions by Identifier

Fetch the latest position for every user in a given pool or token opportunity:

GET /v4/analytics/positions/by-identifier/{chainId}/{identifier}

Path Parameters:

  • chainId (required): Chain ID to query
  • identifier (required): Pool address, token address, market ID, or any opportunity identifier

Example:

GET /v4/analytics/positions/by-identifier/1/0xPoolAddress

Enrichment and global states

With includeDisplay=true, positions are decorated with global-state series (e.g. an AAVE multiplier, a CLAMM pool).

  • At the positionGroup level, globalStates holds series descriptors only: { type, indexingId } per series key.
  • The value applied to a snapshot lives on that snapshot: each latest (and each history entry) carries globalStates[key] = { blockTimestamp, value }, the series row at-or-before the snapshot's own timestamp (carry-forward).

So read the series descriptor from the group and the applied value from each snapshot under the same key:

"globalStates": { "multiplier": { "type": "rebasing_multiplier", "indexingId": "…:multiplier" } },
"positions": {
  "0x…": {
    "latest": {
      "blockTimestamp": 1782180671,
      "state": { "balance": "…", "rebasedBalance": "…" },
      "globalStates": { "multiplier": { "blockTimestamp": 1782178019, "value": { "multiplier": "1069…" } } }
    }
  }
}