API docs
Getting started
One REST API serves every Liquidity Lens product. Every answer is JSON, computed on one block, with integer amounts as decimal strings.
Base URL
https://llens.abanchev.com/api/v1. The free endpoints live under /public/oracle, the keyed ones under /ext.
Authentication
Send an API key in the x-api-key header on every keyed call. Get one on /account: sign in with your wallet, and your first sign-in creates a personal organization. Create, rotate and revoke keys there; a key is shown once, when it is created or rotated. Up to 25 keys per organization.
A key has scopes: public (the keyed public endpoints, every new key), oracle, market and traffic. A call outside the key's scopes answers 403 before anything is metered.
Stable ALM users can also get a key with their wallet: sign in with Ethereum (/api/auth/siwe/nonce, then /api/auth/siwe/verify), then call POST /api/v1/ext/oracle/keys with the session and x-admin-intent: 1. One key per wallet; calling again rotates it. Other teams: request a key.
Deadlines
Compute-backed calls (quote, price, depth, batch, assets, health, pair pools) need a deadline. Send x-compute-budget-ms, an integer from 1 to 5000, counted from when we receive the call, so your clock does not matter. Or send x-compute-deadline, an absolute epoch in milliseconds; up to 2 s of clock skew is tolerated and it never grants more than 5 s. With both, the earlier wins.
Metering
Every keyed call costs compute units (CU): a base cost per route plus a cost per item (a quote, a pool, a token × size). By default a call costs 50 CU and each quote 1 CU, so a quote is 51 CU and a 100-quote batch 150 CU; stored reads (history, pool hours, traffic) cost 50 CU. Each endpoint lists its cost. Costs can change without a deploy; the X-CU-Cost header always states what a call cost.
Your plan gives a monthly CU allowance (UTC calendar month), sometimes a daily one, and a per-minute rate with a burst. Organizations can also have a cap over all their keys. Every metered answer carries X-CU-Cost, X-CU-Limit, X-CU-Remaining (of the tightest quota) and X-CU-Reset (epoch seconds when that quota resets).
Metering happens before the work, and a call that fails on our side (no price engine ready, a compute error, a deadline missed at compute, a batch that could not be queued) is refunded in full. Errors caused by the request itself are not. GET /ext/usage shows this month's and today's CU for the key and its organization and CU per route; it costs 0 CU.
Plans
Public, every new organization: the public scope, 300,000 CU a month, 3,000 CU a minute with a burst of 50 (one 50 CU call a second, like the free per-IP tier). Builder, Pro and Enterprise add the oracle, market and traffic scopes; their allowances are announced later. Stable ALM keeps exactly the limits it had: 30,000 CU a day and 930,000 a month per key, 15,000 CU a minute with a burst of 500.
Requesting access
On /account ask for a scope or a plan, for one key or your whole organization, with an optional note. A self-serve scope is enabled at once. Others go to an operator, who approves (possibly with a monthly CU quota) or denies with a reason; the page shows the decision. A closed scope cannot be requested. The 403 of a missing scope links straight to the form with the scope and key filled in. You can send up to 5 requests at once and about 10 a day.
Units
Amounts are raw integer token units as decimal strings. Prices and percentages are decimal strings. USD means the chain's quote token: USDC on Base and on Sonic. sell is the bid, buy the ask.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | ORACLE_CALLER_DEADLINE_REQUIRED | A compute-backed call without x-compute-budget-ms or x-compute-deadline. |
| 400 | ORACLE_COMPUTE_BUDGET_INVALID | x-compute-budget-ms is not an integer from 1 to 5000. |
| 401 | — | Missing, unknown, rotated or revoked key. |
| 403 | API_SCOPE_NOT_ENABLED, API_SCOPE_APPROVAL_REQUIRED, API_SCOPE_CLOSED | The key lacks the route's scope. data.access names the scope, its mode and requestUrl, the link to request it: self-serve (enable it yourself), approval (an operator reviews it) or closed (not requestable). |
| 403 | CU_PLAN_NOT_CONFIGURED | The key's plan has no quotas yet (a placeholder plan); nothing is metered. |
| 409 | — | Our indexed state has not reached the minBlock you asked for yet, or a Rangefinder task is already running (LP_ORG_CONCURRENCY_CAP). |
| 429 | CU_QUOTA_EXHAUSTED | A CU quota (key or organization, month or day) cannot cover the call. data.cu gives the subject, period, limit, used, cost and resetAt; Retry-After the seconds to the reset. |
| 429 | RATE_LIMITED, LP_ORG_DAILY_CAP | The per-minute CU rate (or a Rangefinder daily task cap) is reached; Retry-After gives the seconds to wait. Nothing was charged. |
| 503 | ORACLE_NO_READY_REPLICA, ORACLE_CALLER_DEADLINE_EXPIRED | No price engine could answer in time. Calls that fail on our side are refunded. |
Keys and usage
/api/v1/ext/usageCU usage and remaining quota
This key's compute units (CU) this UTC month and day, what remains for the key and its organization, and CU per route this month. /ext/oracle/usage answers the same. Costs 0 CU.
- Cost
- 0 CU
- Headers
- Send your key in x-api-key.
curl -s "https://llens.abanchev.com/api/v1/ext/usage" \
-H "x-api-key: $LL_API_KEY"{
"apiKeyId": "k_9TnQ2r8WcLx4",
"orgId": "stable-alm",
"month": "2026-10-01",
"day": "2026-10-19",
"plan": {
"id": "stable-alm",
"name": "Stable ALM",
"placeholder": false
},
"scopes": [
"market",
"oracle",
"public",
"traffic"
],
"key": {
"month": {
"used": "402130",
"limit": "930000",
"remaining": "527870",
"resetAt": "2026-11-01T00:00:00.000Z"
},
"day": {
"used": "20080",
"limit": "30000",
"remaining": "9920",
"resetAt": "2026-10-20T00:00:00.000Z"
},
"failures": "1",
"refunded": "130"
},
"org": {
"month": {
"used": "3911400",
"limit": null,
"remaining": null,
"resetAt": "2026-11-01T00:00:00.000Z"
},
"day": {
"used": "151300",
"limit": "300000",
"remaining": "148700",
"resetAt": "2026-10-20T00:00:00.000Z"
}
},
"rate": {
"cuPerMinute": "15000",
"cuBurst": "500"
},
"routes": [
{
"route": "ext.oracle.batch",
"calls": "1904",
"cu": "331400",
"refunds": "1"
},
{
"route": "ext.oracle.quote",
"calls": "1210",
"cu": "61710",
"refunds": "0"
},
{
"route": "ext.market.pairPools",
"calls": "180",
"cu": "9020",
"refunds": "0"
}
]
}/api/v1/ext/oracle/keysIssue or rotate a wallet key
After signing in with your wallet (SIWE), get one API key for that wallet. Calling it again rotates the key. The key appears in this answer only.
- Cost
- session, no key
- Headers
- Authenticated with a wallet (SIWE) session, not an API key.
curl -s -X POST "https://llens.abanchev.com/api/v1/ext/oracle/keys" \
-H "authorization: Bearer $LL_SESSION_TOKEN" \
-H "x-admin-intent: 1"{
"apiKeyId": "k_9TnQ2r8WcLx4",
"key": "ll_<shown once: 64 characters>",
"orgId": "stable-alm",
"wallet": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984",
"rotated": false,
"access": {
"planId": "stable-alm",
"planName": "Stable ALM",
"placeholder": false,
"scopes": [
"market",
"oracle",
"public",
"traffic"
],
"limits": {
"monthlyCu": "930000",
"dailyCu": "30000",
"cuPerMinute": "15000",
"cuBurst": "500",
"orgMonthlyCu": null,
"orgDailyCu": "300000"
}
}
}/api/v1/ext/oracle/keysRevoke a wallet key
Revokes the signed-in wallet's key. A revoked key gets 401 at once.
- Cost
- session, no key
- Headers
- Authenticated with a wallet (SIWE) session, not an API key.
curl -s -X DELETE "https://llens.abanchev.com/api/v1/ext/oracle/keys" \
-H "authorization: Bearer $LL_SESSION_TOKEN" \
-H "x-admin-intent: 1"{
"apiKeyId": "k_9TnQ2r8WcLx4"
}Every endpoint, field and schema is also in the generated API reference.