> ## Documentation Index
> Fetch the complete documentation index at: https://docs.exponent.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# CLMM APY-range exposure

> Retrieve CLMM exposure at a chosen timestamp, including each position's APY range status.

export const ApiResponse = ({children, errors = {}}) => {
  const [status, setStatus] = useState("200");
  const statuses = ["200", ...Object.keys(errors)];
  return <section className="api-response" aria-label="Response">
      <div className="api-response-header not-prose">
        <h2>Response</h2>
        <div className="api-response-format">
          {statuses.length > 1 ? <select aria-label="Response status" value={status} onChange={event => setStatus(event.target.value)}>
              {statuses.map(code => <option key={code} value={code}>{code}</option>)}
            </select> : <span>200</span>}
          <span className="api-response-mime">application/json</span>
        </div>
      </div>
      <div hidden={status !== "200"}>{children}</div>
      {status !== "200" && <div aria-live="polite">
          {Object.entries(errors[status]).map(([name, value]) => <ResponseField key={name} name={name} type={value === null ? "null" : Array.isArray(value) ? "array" : typeof value}>
              {name === "error" ? "Error message describing why the request failed." : "Additional error details."}
            </ResponseField>)}
        </div>}
    </section>;
};

<RequestExample dropdown>
  ```bash cURL theme={null}
  curl https://api.exponent.finance/in-range/clmm/vault/Cmry6B5824MGAKrtL2u7YG9PiLZLoTBWs8hVaCJeUFaH
  ```

  ```python Python theme={null}
  import requests

  response = requests.get("https://api.exponent.finance/in-range/clmm/vault/Cmry6B5824MGAKrtL2u7YG9PiLZLoTBWs8hVaCJeUFaH", timeout=30)
  response.raise_for_status()
  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.exponent.finance/in-range/clmm/vault/Cmry6B5824MGAKrtL2u7YG9PiLZLoTBWs8hVaCJeUFaH");
  if (!response.ok) {
    throw new Error(`Request failed: ${response.status}`);
  }
  const data = await response.json();
  console.log(data);
  ```
</RequestExample>

## Path parameters

<ParamField path="vaultAddress" type="string" required>
  Base58 Solana vault public key.
</ParamField>

## Query parameters

<ParamField query="at" type="string">
  Past or present ISO 8601 timestamp with an explicit timezone and up to three fractional-second digits. Defaults to request time. Use the same explicit timestamp for both snapshot endpoints to align results. URL-encode `+` in timezone offsets or use UTC (`Z`).
</ParamField>

<ParamField query="bufferApyPercentagePoints" type="number" default="1">
  Inclusive APY buffer, from `0` to `100`. A value of `1` means one percentage point, not a 1% relative change.
</ParamField>

No maximum reference age is enforced. Range checks use the latest available market observation at or before `at`, regardless of age.

## Common response fields

<ApiResponse errors={{}}>
  | Field | Type | Description |
  | - | - | - |
  | `vaultAddress` | string | Requested vault. |
  | `at` | string | Effective inclusive snapshot timestamp. |
  | `bufferApyPercentagePoints` | number | Applied APY buffer. |
  | `syMint` | string | Vault's SY token mint. |
  | `tokenDecimals` | number | Decimals for the vault token amounts. Divide raw balances by `10^tokenDecimals` to obtain token units. |
  | `vaultEndTimestamp` | string | Vault maturity timestamp. |
  | `isExpired` | boolean | Whether maturity has been reached at `at`. Proximity alone does not establish reward eligibility after maturity. |
</ApiResponse>

## CLMM response

The common fields are accompanied by a `positions` array. Closed positions with zero LP balance are excluded. Positions outside the buffer are retained.

| Field | Type | Description |
| - | - | - |
| `userAddress` | string | Position owner. |
| `positionAddress` | string | Position identity. |
| `marketAddress` | string | CLMM market identity. |
| `lpBalance` | string | Latest indexed LP balance at or before `at`. |
| `syBalance`, `ptBalance` | string | Latest indexed withdrawable principal balances. Accrued fees and rewards are excluded. |
| `balanceTimestamp` | string | Balance observation time; balances are sampled, not continuously reconstructed from swaps. |
| `needsRecalculation` | boolean | Whether indexed principal balances are awaiting recalculation. |
| `lowerApyPercent`, `upperApyPercent` | number or null | Position's APY bounds. |
| `marketApyPercent` | number or null | APY from this market's latest snapshot at or before `at`. |
| `marketApyTimestamp` | string or null | Market snapshot observation time. |
| `marketApySource` | string | `clmm_snapshot`. |
| `referenceStatus` | string | `available`, `missing_reference`, or `missing_bounds`. |
| `isWithinBuffer` | boolean or null | Inclusive buffered range check. `null` means the reference or bounds are unavailable. |

For a 6–10% position and a one-percentage-point buffer, market APY from 5% through 11% is within the buffer.

## Using snapshots for rewards

Select positions with `isWithinBuffer=true` when your rewards policy requires proximity to market APY. Apply your own valuation, points, and multipliers; check balance timestamps, `needsRecalculation`, vault maturity, and campaign dates separately.

`isWithinBuffer` has three possible values:

| Value | Meaning |
| - | - |
| `true` | Within the requested APY buffer. |
| `false` | Outside the requested APY buffer. |
| `null` | Insufficient reference data to determine range status. Retry later or handle this as unavailable data. |

Snapshot responses do not calculate time-weighted balances; repeated snapshots or a separate integration are needed for interval rewards.

<ResponseExample>
  ```json 200 theme={null}
  {
    "at": "2026-10-14T15:52:05.174+00:00",
    "syMint": "kCYkdbTRqnXhr1JqVWJTMCRmztcBwpeJiPPvqfDrYLp",
    "isExpired": false,
    "positions": [
      {
        "lpBalance": "443805699101",
        "ptBalance": "2293656345",
        "syBalance": "1835725903",
        "userAddress": "DgVZj9wh1tUuD1nHrpjE2aEHgu5qRCpS6G59ZmFwnquc",
        "marketAddress": "6CFxKYZkRUDBcJSHo3PBHJ7iBiCmEXePrCFT26mZx1id",
        "isWithinBuffer": true,
        "lowerApyPercent": 11.75,
        "marketApySource": "clmm_snapshot",
        "positionAddress": "2ftjRRWfQfBdqCU5ZsbswjQ5fuvuYyrDBTAcD2nbYc2v",
        "referenceStatus": "available",
        "upperApyPercent": 12.75,
        "balanceTimestamp": "2026-10-14T12:30:45+00:00",
        "marketApyPercent": 12.251209352072,
        "marketApyTimestamp": "2026-10-14T15:20:03.11+00:00",
        "needsRecalculation": false
      },
      {
        "lpBalance": "4193199919776",
        "ptBalance": "13283222126",
        "syBalance": "6578709803",
        "userAddress": "EeD5qkphoyGVmkfXLi3e1Rq3Hg2zdi7asMjVgXj1kdRq",
        "marketAddress": "6CFxKYZkRUDBcJSHo3PBHJ7iBiCmEXePrCFT26mZx1id",
        "isWithinBuffer": true,
        "lowerApyPercent": 12,
        "marketApySource": "clmm_snapshot",
        "positionAddress": "5YJBj2g74JSxC5xDf1cTZvCtugpVYhX9VA5BNzwPfbFe",
        "referenceStatus": "available",
        "upperApyPercent": 12.5,
        "balanceTimestamp": "2026-10-14T00:09:40+00:00",
        "marketApyPercent": 12.251209352072,
        "marketApyTimestamp": "2026-10-14T15:20:03.11+00:00",
        "needsRecalculation": false
      }
    ],
    "vaultAddress": "Cmry6B5824MGAKrtL2u7YG9PiLZLoTBWs8hVaCJeUFaH",
    "tokenDecimals": 6,
    "vaultEndTimestamp": "2027-02-25T10:00:00+00:00",
    "bufferApyPercentagePoints": 1
  }
  ```
</ResponseExample>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.