LP Intelligence Documentation
1. Overview
1.1 What is LP Intelligence
LP Intelligence is a structured data layer for DeFi liquidity protocols.
It provides indexed, queryable access to liquidity positions, swaps, pools, and fee state without requiring teams to build and maintain custom on-chain indexers.
The API abstracts raw on-chain events into protocol-aware data models designed for:
- DeFi dashboards and frontends
- Vault and strategy builders
- Analytics and research teams
- Internal data platforms
The goal is to reduce integration time from months of indexing and ETL work to days of API integration.
1.2 Supported Protocols
LP Intelligence currently supports:
- Uniswap v4 (initial integration)
The architecture is designed for multi-protocol expansion. Future integrations will follow the same structured data model principles to ensure consistency across protocols.
1.3 Current Beta Status
LP Intelligence is currently in Public Beta.
Current characteristics:
- Read-only API
- Historical indexing available
- Data freshness may lag (see Data Freshness section)
- API access granted via request
Uniswap v4 hooks (current limitation):
LP Intelligence currently indexes core Uniswap v4 protocol contracts (e.g., PoolManager) and does not yet interpret or model hook-specific logic.
If a pool uses hooks that alter swap or liquidity behavior, derived fields may not fully reflect hook-level custom semantics. The hooks address is exposed as metadata when available.
Near real-time ingestion, access tiers, and additional protocol coverage are planned in upcoming phases.
1.4 Design Principles
LP Intelligence is built with the following principles:
Deterministic indexing
All responses are derived from deterministic indexing pipelines. Data is processed in strict block order to ensure consistency and reproducibility.
Structured, protocol-aware models
Rather than exposing raw contract events, the API provides:
- Normalized pool objects
- Structured position models
- Canonical token metadata
- Computed fee state
This reduces client-side transformation logic and simplifies integration.
Transparent data freshness
Each response includes indexing metadata:
indexed_to_block— the highest block included in the datasetindexed_at— the timestamp when indexing completed
This allows clients to reason about freshness and build their own consistency guarantees.
Developer-first API design
- Predictable pagination (
limit,next_cursor) - Consistent response envelopes
- Clear error formats
- Versioned endpoints
The API is designed for integration into production systems.
2. Quickstart
This section demonstrates how to make your first request to the LP Intelligence API and understand the response structure.
The API is REST-based and returns JSON responses.
2.1 Base URL
All requests should be sent to:
https://api.blockforest.xyz
All endpoints are versioned. The current version is:
/api/v1
Example full URL:
https://api.blockforest.xyz/api/v1/pools
2.2 Authentication
During Public Beta, API access is granted via API key.
Requests must include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Example:
curl https://api.blockforest.xyz/api/v1/pools \
-H "Authorization: Bearer YOUR_API_KEY"
If authentication fails, the API will return 401 Unauthorized.
2.3 First Request Example
The following example retrieves a list of indexed pools on Ethereum mainnet (chain_id=1).
curl "https://api.blockforest.xyz/api/v1/pools?chain_id=1&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"
Query parameters:
chain_id— numeric chain identifier (e.g., 1 for Ethereum mainnet)limit— number of results to return (max value defined by rate limits)
2.4 Example Response
A successful response returns HTTP 200 OK and a JSON body:
{
"indexed_to_block": 21955247,
"indexed_at": "2025-03-01T23:16:47Z",
"items": [
{
"chain_id": 1,
"pool_id": "0xfa86f15833604c1ee16f0a2f7de9d04d244fd9248a3ffe71220f7718f21871fe",
"pool_manager": "0x000000000004444c5dc75cb358380d2e3de08a90",
"fee": 100,
"tick_spacing": 1,
"hooks": null,
"created_block": 21954731,
"created_timestamp": "2025-03-01T21:33:23+00:00",
"token0": {
"address": "0x6111f3e70fbe68c8d62c3340b32e978ddfd8b08a",
"symbol": "SETH",
"decimals": 18,
"name": "Sethereum"
},
"token1": {
"address": "0xdb99b0477574ac0b2d9c8cec56b42277da3fdb82",
"symbol": "DECT",
"decimals": 18,
"name": "DEC Token"
}
},
{
"chain_id": 1,
"pool_id": "0x08d3552d8874b93fdbd8947916c89a375b3c96c34fb49cdf5b8ca79aef020b5c",
"pool_manager": "0x000000000004444c5dc75cb358380d2e3de08a90",
"fee": 10000,
"tick_spacing": 200,
"hooks": null,
"created_block": 21954709,
"created_timestamp": "2025-03-01T21:28:59+00:00",
"token0": {
"address": "0x0000000000000000000000000000000000000000",
"symbol": "ETH",
"decimals": 18,
"name": "Ether"
},
"token1": {
"address": "0x940a2db1b7008b6c776d4faaca729d6d4a4aa551",
"symbol": "DUSK",
"decimals": 18,
"name": "Dusk Network"
}
},
...
{
"chain_id": 1,
"pool_id": "0xe16b9af685b248d4f3e54890353f6f5086a8608d05ed806c4876ce99d4e6c12a",
"pool_manager": "0x000000000004444c5dc75cb358380d2e3de08a90",
"fee": 3000,
"tick_spacing": 60,
"hooks": null,
"created_block": 21953412,
"created_timestamp": "2025-03-01T17:08:35+00:00",
"token0": {
"address": "0x0000000000000000000000000000000000000000",
"symbol": "ETH",
"decimals": 18,
"name": "Ether"
},
"token1": {
"address": "0xb9f599ce614feb2e1bbe58f180f370d05b39344e",
"symbol": "PORK",
"decimals": 18,
"name": "PepeFork"
}
},
{
"chain_id": 1,
"pool_id": "0x4a24fcf3c1cbebd80d09537c7aa15adf2d228aa1b9ba1b0e5fb82e66dc96c0d2",
"pool_manager": "0x000000000004444c5dc75cb358380d2e3de08a90",
"fee": 500,
"tick_spacing": 10,
"hooks": null,
"created_block": 21953133,
"created_timestamp": "2025-03-01T16:12:47+00:00",
"token0": {
"address": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
"symbol": "WBTC",
"decimals": 8,
"name": "Wrapped BTC"
},
"token1": {
"address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"symbol": "USDT",
"decimals": 6,
"name": "Tether USD"
}
}
],
"next_cursor": "eyJjYiI6MjE5NTMxMzMsInBpZCI6IjB4NGEyNGZjZjNjMWNiZWJkODBkMDk1MzdjN2FhMTVhZGYyZDIyOGFhMWI5YmExYjBlNWZiODJlNjZkYzk2YzBkMiJ9",
"limit": 10
}
Response envelope
All list endpoints return a consistent response envelope:
indexed_to_block— highest indexed block included in the datasetindexed_at— timestamp when indexing completeditems— array of result objectsnext_cursor— pagination cursor (if more results exist)limit— number of items requested
This structure is consistent across endpoints.
2.5 Pagination Basics
List endpoints support cursor-based pagination.
To retrieve additional results:
- Inspect the
next_cursorfield in the response. - If not
null, pass it as a query parameter in the next request.
Example:
curl "https://api.blockforest.xyz/api/v1/pools?chain_id=1&limit=10&cursor=eyJvZmZzZXQiOjEwfQ==" \
-H "Authorization: Bearer YOUR_API_KEY"
Pagination guarantees:
- Results are returned in deterministic order.
next_cursorensures no overlap between pages.- If
next_cursorisnull, no additional results are available.
3. Authentication
LP Intelligence uses API key–based authentication for all requests.
Authentication follows a server-to-server model designed for backend integration. Each request must include a valid API key in the Authorization header.
API keys are long-lived, revocable, and scoped to a single account.
3.1 API Keys
Access to LP Intelligence is granted via API key.
Each account is issued a unique secret key during onboarding.
Example key format:
bf_live_7f4c9a2e3d1b4f0c8a6d9e2f1b3c4d5e
API keys:
- Are account-scoped
- Can be revoked or rotated
- Should be kept secret
- Must never be exposed in client-side code
Security recommendations
- Store API keys in secure server-side environment variables.
- Do not embed keys in frontend applications.
- Rotate keys if you suspect compromise.
If a key is revoked, all subsequent requests using that key will return 401 Unauthorized.
3.2 Request Headers
All authenticated requests must include the Authorization header:
Authorization: Bearer YOUR_API_KEY
Example request:
curl https://api.blockforest.xyz/api/v1/pools \
-H "Authorization: Bearer bf_live_7f4c9a2e3d1b4f0c8a6d9e2f1b3c4d5e"
Requests without a valid API key will receive:
401 Unauthorized
If the key is valid but exceeds rate limits, the API will return:
429 Too Many Requests
3.3 Rate Limits
Rate limits are enforced per API key.
Limits are defined based on your access tier.
Rate limiting ensures:
- Fair resource allocation
- System stability
- Predictable performance
When a rate limit is exceeded, the API responds with:
429 Too Many Requests
Example response:
{
"error": "rate_limit_exceeded",
"message": "Request rate limit exceeded. Please retry later."
}
Future versions may include rate limit headers such as:
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-Reset
Rate limits may be adjusted during Public Beta.
3.4 Access Tiers (Beta / Future Plans)
LP Intelligence currently operates under a Public Beta tier.
Public Beta
- Read-only access
- Historical indexing
- Controlled rate limits
- Access granted via request
Planned Tiers
Future access tiers may include:
- Higher request limits
- Near real-time ingestion access
- Dedicated rate limits
- Priority support
- Advanced features (e.g., profitability layer, webhooks, batch endpoints)
Access tier and limits are determined at the account level.
Details on paid tiers will be published prior to general availability.
4. Core Concepts
This section defines the core data models used throughout LP Intelligence.
Rather than exposing raw contract events, the API provides structured, protocol-aware objects designed for integration into production systems.
4.1 Chains
A Chain represents a supported blockchain network.
Each chain is identified by a numeric chain_id, consistent with EVM standards.
Example:
- 1 — Ethereum mainnet
- (additional chains will be added in future phases)
Chain-level context determines:
- Address namespace
- Block height
- Indexing boundaries
- Protocol deployment addresses
All endpoints that return chain-specific data include a chain_id field.
4.2 Pools
A Pool represents a liquidity pool within a supported protocol.
Pools define:
pool_id— unique identifiertoken0andtoken1— assets paired in the poolfee— fee tiertick_spacing— discrete price granularity- Protocol-specific metadata (e.g., hooks in Uniswap v4)
Pools are canonicalized in the API to provide:
- Normalized token metadata
- Structured fee configuration
- Deterministic identification
Pools serve as the foundational market unit for swaps and positions.
Hooks Support (Uniswap v4)
- The
hooksaddress is exposed as metadata when available. - LP Intelligence does not currently decode or model hook callback logic.
- Indexed data reflects core protocol events and state; hook-driven behavioral adjustments are out of scope at this stage.
- Hook-aware indexing and enriched semantics are planned in a future release.
4.3 Positions
A Position represents a liquidity provider’s allocation within a pool.
Positions are defined by:
owner— current position ownerinitiator— address that created or modified the positionpool— associated pool objecttick_lower/tick_upper— price rangeliquidity— amount of active liquiditysalt— protocol-specific unique position discriminator
Positions are range-bound and active only when the current pool price falls within the specified tick range.
The API abstracts protocol-specific storage details into a consistent position model.
4.4 Swaps
A Swap represents a token exchange executed within a pool.
Swaps include:
- Associated pool
- Input and output tokens
- Amounts
- Block context
- Transaction metadata
Swaps are indexed in deterministic block order and can be queried:
- At the wallet level
- At the pool level
Swap data enables:
- Volume analytics
- Strategy logic
- Market activity monitoring
4.5 Fee State
Fee State represents accrued fees associated with a position.
For the current /api/v1/positions/{position_id}/fees endpoint, the response focuses on:
- Current liquidity
- Lifetime earned fee totals (
fees_earned0_total,fees_earned1_total)
Fee growth checkpoints are tracked internally but are not exposed by this endpoint.
The API exposes position-level fee information in a structured format to simplify:
- LP performance analysis
- Yield calculations
- Strategy evaluation
Fee state is derived from indexed on-chain state and reflects data up to the indexed block boundary.
4.6 Liquidity Ranges (tick_lower / tick_upper)
Liquidity in concentrated liquidity AMMs is allocated across a defined price range.
Each position specifies:
tick_lower— lower bound of price rangetick_upper— upper bound of price range
Liquidity is active only when the current pool price lies within this range.
Ticks are discrete price intervals determined by the pool’s tick_spacing.
Full-range positions span the minimum and maximum tick boundaries supported by the protocol.
Understanding liquidity ranges is critical for:
- LP profitability modeling
- Impermanent loss estimation
- Active liquidity calculations
4.7 Indexing Metadata
All list endpoints return indexing metadata to allow clients to reason about data freshness and completeness.
Each response includes:
indexed_to_block— the highest block included in the datasetindexed_at— timestamp when indexing completed
This metadata allows clients to:
- Detect indexing lag
- Build consistency guarantees
- Implement freshness thresholds
- Reconcile internal state with blockchain height
LP Intelligence prioritizes transparency in indexing boundaries rather than implying real-time guarantees.
5. Endpoints
All endpoints are versioned under:
/api/v1
All responses are returned as application/json.
List endpoints:
- Support cursor-based pagination
- Return deterministically ordered results
- Include indexing metadata where applicable
For full request/response schemas and parameter details, see the API Reference.
👉 Full API Reference (OpenAPI / ReDoc)
5.1 Address-Scoped Endpoints
Note: The
/wallets/{address}path accepts any valid EVM address (EOA or contract).
Important:
The {address} parameter is interpreted strictly as the transaction initiator (tx.from), not as a protocol-level owner field.
Returned objects may include both:
- initiator — the transaction sender (tx.from)
- sender — protocol-level address emitted in liquidity events
These values may differ in router, vault, multisig, or relayer-based interactions.
GET /api/v1/wallets/{address}/positions
Returns aggregated liquidity positions derived from ModifyLiquidity events initiated by the specified address.
Liquidity is calculated as the net sum of liquidity deltas across transactions where the address was the transaction initiator (tx.from).
This endpoint is filtered by transaction initiator (tx.from) and does not filter by the current position owner.
Use cases:
- Strategy monitoring
- Operator analytics
- Execution tracing
GET /api/v1/wallets/{address}/swaps
Returns swap activity executed in transactions initiated by the specified address.
Provides execution-level swap history enriched with pool context.
5.2 Pools
GET /api/v1/pools
Returns indexed liquidity pools for a given chain.
Pools represent canonical market units within the supported protocol and include normalized token metadata.
Supports filtering by:
- chain
- token address
Note — Hooks (Uniswap v4):
Thehooksfield is returned as metadata. Hook execution logic is not currently modeled in computed semantics.
GET /api/v1/pools/{pool_id}/swaps
Returns indexed swap activity for a specific pool.
Enables:
- Volume aggregation
- Liquidity utilization analysis
- Market activity monitoring
5.3 Positions
GET /api/v1/positions/{position_id}/fees
Returns lifetime cumulative fees earned by a liquidity position.
This endpoint is based on indexed liquidity modification checkpoints.
If swaps occurred after the last processed checkpoint, totals may temporarily lag until the next checkpoint is indexed.
5.4 Reference Data
GET /api/v1/tokens
Returns canonical token metadata for a given chain.
Supports basic search by symbol or name.
GET /api/v1/chains
Returns supported blockchain networks within LP Intelligence.
Enables programmatic discovery of:
- supported chain IDs
- human-readable names
- native currency metadata
- explorer URLs
6. Errors
LP Intelligence uses standard HTTP status codes to indicate success or failure of an API request.
Clients should always:
- Inspect the HTTP status code
- Parse the response body for structured error details
- Implement retry logic where appropriate
6.1 HTTP Status Codes
The API uses the following status codes:
200 — OK
The request was successful.
400 — Bad Request
The request is malformed or contains invalid parameters.
401 — Unauthorized
Authentication credentials are missing or invalid.
403 — Forbidden
Authentication succeeded but the request is not permitted for the current API key or access tier.
404 — Not Found
The requested resource does not exist.
422 — Validation Error
The request parameters failed schema validation.
429 — Too Many Requests
Rate limit exceeded.
500 — Internal Server Error
Unexpected server-side error.
6.2 Error Response Format
Error responses are returned in JSON format.
For validation errors, the API follows a structured schema:
{
"detail": [
{
"loc": ["query", "limit"],
"msg": "ensure this value is less than or equal to 500",
"type": "value_error.number.not_le"
}
]
}
Fields:
loc— location of the invalid field (path, query, body)msg— human-readable error messagetype— machine-readable error classification
Clients should rely on:
- HTTP status code for control flow
typefor programmatic handlingmsgfor logging or debugging
6.3 Validation Errors (422)
A 422 Unprocessable Entity response is returned when request parameters fail validation.
Common causes:
- Invalid address format
- Invalid position_id format (must be 0x-prefixed bytes32)
- Exceeding limit constraints
- Invalid enum value (e.g., unsupported protocol)
Example:
{
"detail": [
{
"loc": ["path", "position_id"],
"msg": "string does not match required pattern",
"type": "value_error.str.regex"
}
]
}
Clients should treat validation errors as non-retryable unless request parameters are corrected.
6.4 Auth Errors (401/403)
401 Unauthorized
Returned when:
- Authorization header is missing
- API key is invalid
- API key is revoked
{
"error": "invalid_api_key",
"message": "The provided API key is invalid."
}
403 Forbidden
Returned when:
- API key is valid but lacks permission
- Access tier does not allow requested resource
- Chain or protocol not enabled for the key
Example:
{
"error": "access_denied",
"message": "Your API key does not have access to this resource."
}
Clients should not retry 401 or 403 errors without changing credentials or upgrading access.
6.5 Rate Limit Errors (429)
If a client exceeds the allowed request rate, the API returns:
429 Too Many Requests
Example:
{
"error": "rate_limit_exceeded",
"message": "You have exceeded your request limit. Please retry later."
}
Clients should implement exponential backoff when receiving 429 responses.
Recommended retry strategy:
- Initial delay: 500–1000 ms
- Exponential backoff with jitter
- Maximum retry attempts: 3–5
Future versions may include rate limit headers such as:
X-RateLimit-LimitX-RateLimit-RemainingRetry-After
6.6 Idempotency / Retries guidance (even if you don’t support idempotency yet, retries matter)
All current endpoints are read-only (GET) and are therefore idempotent.
Safe to retry:
- 429 (rate limit)
- 500 (server error)
- Network timeouts
Do not retry without modification:
- 400 (bad request)
- 401 (unauthorized)
- 403 (forbidden)
- 422 (validation error)
Recommended retry pattern:
- Treat GET endpoints as safe to retry
- Implement exponential backoff
- Log request ID and error payload for diagnostics
- Avoid aggressive retry loops under sustained 429 responses
7. Pagination & Filtering
Most list endpoints return potentially large result sets. LP Intelligence provides cursor-based pagination to keep responses fast, stable, and safe for production workloads.
Supported list endpoints use:
limit(page size)cursor(opaque pointer to the next page)next_cursor(returned by the API when more results are available)
7.1 limit
limit controls the maximum number of items returned in a single response.
- Type: integer
- Typical default: 50
- Max values:
- Most list endpoints: up to 500
- Tokens search: up to 1000 (per your OpenAPI)
Guidance:
- Use smaller limit values for latency-sensitive UIs.
- Use larger values for backfills/batch jobs, but expect larger payload sizes.
Example:
GET /api/v1/pools?chain_id=1&limit=100
7.2 cursor / next_cursor
cursor (request)
cursor is an opaque string used to request the next page of results. You should treat it as a black box (do not parse or generate it).
- Type: string (nullable)
- Provided by:
next_cursorfrom the previous response
next_cursor (response)
If more results exist, the response includes a next_cursor. If you reached the end, next_cursor is null.
Example flow:
- First page (no cursor):
GET /api/v1/wallets/{address}/positions?chain_id=1&limit=50
- Response includes:
{
"items": [ /* ... */ ],
"next_cursor": "eyJ2Ijo...opaque...",
"limit": 50
}
- Next page:
GET /api/v1/wallets/{address}/positions?chain_id=1&limit=50&cursor=eyJ2Ijo...opaque...
Important rules:
- Always pass the same query parameters when paginating (same chain_id, filters, etc.).
- Don’t reuse a cursor across different endpoints.
- Don’t store cursors long-term for business logic; treat them as short-lived pagination pointers.
7.3 Ordering Guarantees
List endpoints return results in a consistent, deterministic order suitable for pagination.
What you can rely on:
- Ordering is stable within a given endpoint + parameter set.
cursorpagination is aligned with that ordering so you don’t miss or duplicate items while paging.
What you should not assume:
- The exact sort keys or internal ordering logic (it may evolve without breaking pagination).
- That “newest first” or “oldest first” is universally applied unless explicitly stated per endpoint.
Practical guidance:
- For UIs: assume “most relevant / most recent” unless the endpoint documentation states otherwise.
- For ingestion jobs: page until
next_cursor = null.
7.4 Deterministic Responses
LP Intelligence is an indexed data API, which means responses represent a snapshot at an indexing boundary, not necessarily the latest chain head.
To support deterministic integration behavior:
- Many responses include indexing metadata (e.g.,
indexed_to_block,indexed_at), allowing you to detect when the underlying dataset advanced. - Pagination is designed to be consistent within an indexing window.
Responses include indexed_to_block, which indicates the highest indexed block included in the dataset. Clients performing large historical backfills may use this value to ensure consistency across paginated requests.