Merkl Developer Portal logo
get

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

Get positions by opportunity identifier

Fetch the latest position for every user in a given opportunity.

Response:
- data[indexingId]: Wrapped positions keyed by indexingId. Each positionGroup carries shared metadata (protocol, action, stateType, globalStates, tokens) and a positions map keyed by positionId. Each position entry carries its user field; multiple users may share the same indexingId positionGroup.
- latest is reported as of the indexing checkpoint: its (blockNumber, blockTimestamp) are advanced to how far indexing has completed (state unchanged through there), never beyond it — so the state is never presented as more current than what's indexed.
- globalStates: at the positionGroup level it holds series descriptors only (type, indexingId) — fetch the values from GET /v4/analytics/global-states. This route returns raw states; it runs no global-state enrichment.
- display.unpricedReason (when valueUsd is absent): which step gave up — no_price (the token mapped but has no daily close at or before that day), no_token_mapped (no declared token denominates the amount, e.g. a market-keyed identifier), unresolved_amount (global-state enrichment produced none), unsupported_state (no valuation rule for the stateType). A price gap and an unsupported shape both read as "no value" without it.
- debt: present and true when the group's amounts are owed, not held (a borrow) — sum values across groups by subtracting these. Set once per group: it follows from the processor.
- positions[positionId].params: position-invariant fields hoisted out of the snapshots, emitted once per position. Shape follows stateType; CLAMM carries tickLower/tickUpper (and salt when the persisted state has one), which is why they are no longer inside each snapshot's state. poolId and tokenId are not emitted at all: poolId is the positionGroup's identifier, and tokenId is the last segment of the positionId key.
- pagination.positionCount: Total number of position entries returned
- pagination.recipientsCount: Number of distinct user addresses across all positions

- Confidential sets are withheld. A storing set whose state is a decrypted confidential amount (Zama ERC-7984 plaintext balances) is not served here: the chain publishes the ciphertext only, and the plaintext exists because the holder delegated decryption to Merkl. The public sibling series (confidential_transfer ciphertext handles, delegation ACL expiries) are returned as usual.

Examples:
- Latest positions: GET /v4/analytics/positions/by-identifier/1/0xPoolAddress

Path parameters

chainIdnumber | string
required

Chain ID to query

identifierstring
required

Pool address, token address, market ID, or any opportunity identifier

Query parameters

includeDisplayboolean
required
default: false

Decorate each snapshot with the same self-describing display block as the by-user route (per-token id/symbol/decimals/amount plus valueUsd). Enriches the states it needs on its own.

Responses

200
Response for status 200
Schema
object
dataobject
required
Wrapped positions keyed by indexingId
paginationobject
required
positionCountnumber
required
Total number of position entries returned
recipientsCountnumber
required
Number of distinct user addresses in the response
Example
{
  "data": {},
  "pagination": {
    "positionCount": 0,
    "recipientsCount": 0
  }
}