Lowcap Connector
Lowcap Connector provides real-time and on-demand USD prices for low-cap tokens across EVM chains.
Use the API to:
- request token-level USD prices;
- inspect pool-level quotes and recent events;
- discover supported chains, tokens, and pools;
- consume live price, swap, and feed-health updates over WebSocket.
The public API base URL is:
https://lowcapsxyz.com
API requests require an operator-issued credential. This documentation site is public and does not require authentication.
Getting started
Authentication
Send an operator-issued API key as a bearer token:
Authorization: Bearer <your-api-key>
Never put a key in a URL. Browser clients may exchange a bearer credential through POST /v1/session; the response sets a secure, HTTP-only, same-origin session cookie for later API requests and WebSocket handshakes.
Keys are issued by the service operator. Contact the operator to request access; there is no self-service signup.
List supported chains
curl --fail-with-body \
-H 'Authorization: Bearer <your-api-key>' \
'https://lowcapsxyz.com/v1/chains'
Request a token quote
Replace the chain ID and token address with the asset you need:
curl --fail-with-body \
-H 'Authorization: Bearer <your-api-key>' \
-H 'Accept: application/json' \
'https://lowcapsxyz.com/v1/quote/token/8453/0x1111111111111111111111111111111111111111'
See Errors and response states before treating a successful HTTP response as a priced result.
API overview
All paths below are relative to https://lowcapsxyz.com.
For schemas, parameters, and executable requests, open the interactive OpenAPI reference.
Chains, tokens, and search
| Method | Path | Purpose |
|---|---|---|
GET | /v1/chains | List supported chains. |
GET | /v1/tokens?chain_id= | List known tokens for a chain. |
GET | /v1/search?address= | Find known chain, token, and pool records by address. |
Pools and events
| Method | Path | Purpose |
|---|---|---|
GET | /v1/pools | Read a keyset-paginated pool snapshot. |
GET | /v1/pools/{chain_id}/{pool_address} | Read one pool and its latest verified state. |
GET | /v1/pools/{chain_id}/{pool_address}/events | Read recent events for a pool. |
Quotes
| Method | Path | Purpose |
|---|---|---|
GET | /v1/quote/pool/{chain_id}/{pool_address} | Compute or retrieve a pool-level quote and evidence. |
GET | /v1/quote/token/{chain_id}/{token_address} | Compute or retrieve a routed USD token quote. |
Health
| Method | Path | Purpose |
|---|---|---|
GET | /v1/chains/{chain_id}/health | Read the latest feed-health snapshot for a chain. |
Session
| Method | Path | Purpose |
|---|---|---|
POST | /v1/session | Create a browser session and a resumable-stream cursor. |
POST /v1/session requires authentication (a bearer token, or an existing session cookie) and has no request body. Its optional query parameters select a chain and a snapshot boundary.
Admin endpoints also exist. They are allowlist-gated and are covered only in the interactive OpenAPI reference.
WebSocket streaming
Connect to:
wss://lowcapsxyz.com/v1/stream
Authenticate the WebSocket handshake with either Authorization: Bearer <your-api-key> or a valid same-origin session cookie. Then send exactly one JSON subscribe frame.
Subscribe
{
"filter": {
"chain_ids": [8453],
"pool_ids": [
"0x1111111111111111111111111111111111111111111111111111111111111111"
],
"token_ids": [
"0x2222222222222222222222222222222222222222222222222222222222222222"
]
},
"resume_cursor": null
}
Filter arrays must be strictly sorted and unique. Empty pool_ids and token_ids arrays select every routed message for the chosen chains. A null cursor starts live-only delivery.
Message envelope
Durable messages share this envelope:
{
"stream_sequence": 10842,
"routing": {
"chain_id": 8453,
"pool_ids": [],
"token_ids": []
},
"type": "PRICE_UPSERT",
"payload": {}
}
stream_sequence is monotonic, not necessarily contiguous. Use it for ordering and recovery. Message types are:
| Type | Meaning |
|---|---|
PRICE_UPSERT | Absolute current price state; safe to apply repeatedly. |
PRICE_RETRACT | Previously published evidence changed or was removed; recompute from the supplied post-change state. |
SWAP_OBSERVED | A decoded swap with exact amounts and event position. |
FEED_HEALTH | A chain feed-health update. |
RESET_REQUIRED | Replay cannot safely continue; rebuild state and reconnect. |
RESET_REQUIRED is a control message and has no stream_sequence.
Resume and replay
For snapshot-plus-delta consumption:
-
Read every page of
GET /v1/poolsand retain the minimumsnapshot_sequencereturned across the pages. -
Create a cursor after that boundary:
curl --fail-with-body -X POST \ -H 'Authorization: Bearer <your-api-key>' \ 'https://lowcapsxyz.com/v1/session?chain_id=8453&snapshot_sequence=<snapshot-sequence>' -
Reconnect and send the returned
resume_cursorin the subscribe frame. -
Apply replayed records, then continue with live records. Ignore overlap at or below the last applied sequence.
The current session cursor is chain-wide. A narrower pool or token filter with that cursor causes RESET_REQUIRED with FILTER_MISMATCH. For resumable delivery, subscribe chain-wide and filter locally.
Heartbeats and slow consumers
The server sends a WebSocket ping every 30 seconds and expects a pong before the next heartbeat. It also responds to client pings.
If a slow consumer falls behind, the connection closes with code 1013 and identifies the last delivered sequence. Create a new session cursor after that sequence and reconnect. If replay is no longer available, discard local state and take a fresh snapshot.
RESET_REQUIRED
{
"type": "RESET_REQUIRED",
"payload": {
"reason": "REPLAY_UNAVAILABLE",
"server_time_unix_ms": 1784217600000
}
}
Possible reasons are INVALID_CURSOR, EXPIRED_CURSOR, FILTER_MISMATCH, REPLAY_UNAVAILABLE, and SCHEMA_MISMATCH.
On receipt:
- stop applying stream messages;
- discard state whose consistency depends on the rejected cursor;
- fetch a fresh pool snapshot;
- create a new cursor at that snapshot boundary;
- reconnect chain-wide.
Errors and response states
Generic errors
Non-quote application errors use:
{
"error": "message"
}
Quote errors
Quote failures use a structured body. detail may be null.
{
"code": "NO_ROUTE",
"message": "no route",
"detail": "NO_QUALIFIED_ROUTE_WITHIN_HOP_LIMIT"
}
The following code strings map to HTTP status codes:
| Code | HTTP status |
|---|---|
INVALID_PARAMS | 400 |
INVALID_ADDRESS | 400 |
UNSUPPORTED_CHAIN | 404 |
NOT_A_POOL | 404 |
TOKEN_UNKNOWN | 404 |
NO_ROUTE | 422 |
NOT_SUPPORTED | 422 |
RPC_UNAVAILABLE | 503 |
BUDGET_EXCEEDED | 503 |
DEADLINE_EXCEEDED | 504 |
Authentication and authorization
401 Unauthorized: the credential is missing, invalid, expired, or revoked. The response body is empty and includesWWW-Authenticate: Bearer.403 Forbidden: the credential is valid but the consumer is not allowed to use the requested endpoint. The response body is empty.
Rate limiting
429 Too Many Requests has an empty body. The numeric Retry-After header gives the number of seconds to wait before retrying. Rate limiting is isolated per consumer; requests made with a session cookie use the same bucket as the bearer credential that created it.
Token-quote response states
GET /v1/quote/token/{chain_id}/{token_address} may return a non-error response without a price:
| HTTP status | State | Caller action |
|---|---|---|
202 Accepted | Enrollment was accepted, but discovery or initial evaluation is still pending. | Do not treat the token as priced. Retry later and observe normal rate-limit guidance. |
200 OK | UNPRICED: the token is known and the request completed, but no publishable USD price is currently available. | Treat the price as unavailable, not zero. Keep the response metadata and retry when newer evidence may exist. |
A 202 response means work is pending. A 200 UNPRICED response is a completed evaluation with no usable price at that time.
Chains and deployments
These tables record public EVM chain identities and on-chain deployment facts verified on 2026-07-17.
Chain identity
| Chain | Chain ID | Genesis hash | Configured block time |
|---|---|---|---|
| Ethereum | 1 | 0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3 | 12,048 ms |
| Arbitrum One | 42161 | 0x7ee576b35482195fc49205cec9af72ce14f003b9ae69f6ba0faef4514be8b442 | 250 ms |
| BNB Smart Chain | 56 | 0x0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b | 450 ms |
| Polygon PoS | 137 | 0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b | 1,500 ms |
| Avalanche C-Chain | 43114 | 0x31ced5b9beb7f8782b014660da0cb18cc409f121f408186886e1ca3e8eeca96b | 1,035 ms |
Factory deployments
| Chain | Family | Factory contract | Deployment block | Verification |
|---|---|---|---|---|
| Ethereum | uniswap_v3 | 0x1F98431c8aD98523631AE4a59f267346ea31F984 | 12,369,621 | Bytecode, canonical getPool, live PoolCreated and Swap events |
| Arbitrum One | uniswap_v3 | 0x1F98431c8aD98523631AE4a59f267346ea31F984 | 165 | Creation receipt, matching address, canonical pool, live events |
| BNB Smart Chain | uniswap_v2 | 0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73 | 6,809,737 | Bytecode, canonical getPair, compatible live Swap events |
| Polygon PoS | uniswap_v3 | 0x1F98431c8aD98523631AE4a59f267346ea31F984 | 22,757,547 | Bytecode transition, canonical wrapped-native/USDC pool, live Swap events |
| Avalanche C-Chain | uniswap_v3 | 0x740b1c1de25031C31FF4fC9A62f554A55cdC1baD | 27,832,972 | Bytecode transition, canonical wrapped-native/USDC pool, live Swap events |
The BNB Smart Chain deployment is admitted through the compatible V2 pair ABI. V3 compatibility is not assumed.
Known pool contracts
| Chain | Pool contract | Factory lookup |
|---|---|---|
| Ethereum | 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640 | getPool(USDC,WETH,500) |
| Arbitrum One | 0xC6962004f452Be9203591991D15f6b388e09E8D0 | getPool(WETH,USDC,500) |
| BNB Smart Chain | 0x16b9A82891338f9bA80e2D6970fDda79D1eb0dAE | getPair(WBNB,USDT) |
| BNB Smart Chain | 0xd99c7F6C65857AC913a8f880A4cb84032AB2FC5b | getPair(WBNB,USDC) |
| Polygon PoS | 0xB6e57ed85c4c9dbfEF2a68711e9d6f36c56e0FcB | getPool(WPOL,USDC,500) |
| Avalanche C-Chain | 0xfAe3f424a0a47706811521E3ee268f00cFb5c45E | getPool(WAVAX,USDC,500) |
Event-topic hashes
| Event | Topic hash |
|---|---|
Uniswap V3 PoolCreated | 0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118 |
Uniswap V3 Swap | 0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67 |
Uniswap/Pancake V2 Swap | 0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822 |
Routing confidence
Routing computes an exact token/USD value and a confidence score from chain-local pool evidence. Confidence is a weakest-link score, not a probability or permission to trade.
Invariants
- Graph operations are chain-local; asset identity is
(chain_id, opaque asset_id). - Authoritative prices are positive reduced rationals. Zero, NaN, infinity, and binary floats are invalid.
- A physical pool contributes capacity at most once.
- Path depth and confidence use weakest-link values.
- External coverage data may lower or cap confidence; it cannot create or delete an on-chain price.
- Routes expire without events. Every score exposes its components and active caps.
Exact price composition
q(X→Y) = (a × 10^dX) / (b × 10^dY)
Q(S/X₀) = (∏aᵢ × 10^dX₀) / (∏bᵢ × 10^dS)
P_USD(X₀) = Q(S/X₀) × U_S
a/b is the oriented atomic execution ratio. Reverse orientation is the exact reciprocal of observed evidence, not a reverse executable quote. Token decimals must be verified. U_S is an exact guarded stable/USD ratio.
Arithmetic cross-cancels by greatest common divisor, supports 4,096 bits per side, persists decimal strings, and rounds only the final display value to 18 significant digits using ties-to-even.
Common 2% depth
D↑ = USD input required to raise oriented marginal price by 2%
D↓ = USD input required to lower oriented marginal price by 2%
L = min(D↑, D↓)
L_eff = min(L_current, EWMA_30m(L))
Adapters simulate protocol-exact integer swaps and choose the greatest consumed gross input still within the boundary. Depth rounds down to microdollars. TVL, reserves, and active liquidity are diagnostics, not substitutes for the simulation. Incomplete state makes depth UNKNOWN.
Weighted median and outlier rejection
Sort prices before applying the weighted median:
weighted median: first k where 2 × Σ(i≤k) wᵢ ≥ Σwᵢ
dev_bps(p,q) = 10000 × (max(p/q, q/p) - 1)
MADw = weighted_median(dev_bps(pᵢ,m₀), Lᵢ_eff)
τ = clamp(ceil((22239/5000) × MADw), 200, 1000) bps
Outlier rejection is one-pass. Proposed outliers are removed only when survivors retain at least 67% of the weight and span at least two independent pools and deployments. Otherwise all observations remain, NO_INDEPENDENT_CONSENSUS applies, and confidence is capped at 2.
Shared edges are capacity-limited:
b_r = min edge capacity on route r
B_e = Σ b_r for routes using edge e
w_r = floor_microUSD(b_r × min_e(min(1, L_e/B_e)))
Invariant: Σ(r using e) w_r ≤ L_e
The published value is the selected weighted-median path’s exact rational. The support envelope spans accepted inlier prices; it is diagnostic, not a calibrated probability interval.
Confidence algebra
S_edge = min(S_depth, S_fresh, S_agreement, S_temporal,
S_feed, S_state, S_stable?)
S_anchor = min(S_edge, S_coverage)
S_route = min(all edge scores, routing-asset score)
S_published = min(S_path_agreement, material route scores,
S_aggregate_state)
| Component | Bands and rules |
|---|---|
| Coverage | 0 depth → 0; <0.3% → 1; <0.6% → 2; <1% → 3; <2% → 4; <3% → 5; <6% → 6; <10% → 7; <17.5% → 8; <25% → 9; ≥25% → 10 |
| Absolute depth | 0 → 0; $0–500 → 1; then $500, $1k, $2.5k, $5k, $10k, $25k, $50k, $100k, and $250k boundaries through 10 |
| Freshness | Worst normalized price/liquidity age ≤0.1 → 10; ≤0.2 → 9; ≤0.4 → 8; ≤0.6 → 7; ≤0.8 → 6; <1 → 5; expired → 0 and disqualified |
| Agreement | Minimum of source count, spread, and retained support; one pool is usable but capped; unresolved split caps at 2 |
| Temporal | Deviation from five-minute duration-weighted median: ≤1% → 10; ≤2% → 8; ≤5% → 5; >5% → 2; insufficient history → 5 |
| Feed/state | Unverified, GAP, or UNAVAILABLE → 0; DEGRADED → 3; canonical → 8; all causal state finalized → 10 |
| Stable | Within cap → 10; moderate depeg applies a cap; beyond suspension → 0; stale or nominal fallback is capped and labeled |
| Score | Label | Consumer posture |
|---|---|---|
| 0 | Unusable | Retract or ignore. |
| 1–3 | Low | Candidate only; require deeper independent evidence and a dry run. |
| 4–6 | Medium | Require an independent source and a dry run. |
| 7–8 | High | May flag promptly; a dry run remains mandatory. |
| 9–10 | Very high | Consider as a primary source only after rolling promotion gates. |
State and ordering
- Recompute on price, liquidity, retraction, health, finality, timer, policy, and external-anchor changes.
PRICE_RETRACTrecomputes from final post-reorganization state; it is not a blind tombstone.- Sequence causal pool records before one coalesced token record.
- When no route survives, timer expiry retracts the price with
ROUTE_EXPIRED.
No score authorizes liquidation. Independent flag-then-confirm policy remains mandatory, especially when one party controls most effective depth, the sole venue, the ingestion cursor, or the sole stable source.