Skip to main content

K-Line API User Guide

Version: 1.0.0
Audience: integrator developers, market-data clients, and operations engineers

This guide explains how to use the K-Line API to manage collection pools, query historical OHLCV data, subscribe to real-time K-line updates, and call market proxy and operational debugging APIs.


Table of contents


1. Quick start

1.1 Service overview

The K-Line API is a K-line data service. It provides these core capabilities:

  • Manage on-chain liquidity pools that need OHLCV collection
  • Query historical OHLCV candlestick data for a pool
  • Dynamically subscribe to real-time K-line updates through WebSocket
  • Proxy CoinGecko market data, top holders, and token metadata queries
  • Inspect the ingester and KlineHub Durable Object runtime status

All HTTP APIs are mounted under the /api/v1 prefix. Public endpoints use the X-API-Key request header for API authentication and billing identification. Headers used internally by the forwarding layer are not required for external integration.


1.2 Base URL

Use the following production host as the root path for all API requests:

https://api.gelabs.org

Example:

curl -H "X-API-Key: $API_KEY" "https://api.gelabs.org/api/v1/health"

1.3 Unified response shape

Most successful HTTP APIs return:

{
"code": 0,
"message": "ok",
"data": {}
}
FieldTypeAlways returnedDescription
codeintegerYesBusiness status code. 0 means success.
messagestringYesResponse message. Successful responses use ok.
dataobject / array / stringYesBusiness payload. Shape depends on the endpoint.

Failed responses usually look like:

{
"code": 10001,
"message": "Invalid query params",
"error": {
"type": "ValidationError",
"details": {
"fieldErrors": {
"chain_type": ["String must contain at least 1 character(s)"]
}
}
}
}

Note: Operational debugging endpoints do not always use the unified JSON wrapper. /api/v1/admin/debug/ingester/ensure returns plain text ok, while status endpoints return raw Durable Object JSON.


1.4 Error codes

CodeMeaningCommon trigger
0SuccessNormal response
10001Validation failedInvalid query, path, or body fields
10002Invalid argumentValue violates business rules
10003Resource not foundUnknown route or upstream resource
10004Resource conflictCreating a duplicate pool
10005Bad requestWebSocket preflight or malformed request
20001UnauthenticatedReserved, currently not enabled
20002ForbiddenReserved, currently not enabled
60001K-line resource not foundQuerying a missing pool
60002K-line sync failedReserved
60003Invalid symbolReserved
60004Invalid intervalReserved
99001Internal server errorUncaught exception, upstream error, or rate limit
99002Database errorReserved
99003Cache errorReserved

1.5 Common conventions

ItemDescription
Common request headerAll public endpoints require X-API-Key for API authentication and billing identification.
Content-TypePOST bodies use application/json; WebSocket messages use JSON text frames.
TimestampsHTTP query parameters from and to accept Unix seconds or milliseconds. Values greater than 10000000000 are treated as milliseconds.
Chain typechain_type is normalized to lowercase. Common aliases include eth/ethereumevm, sol/solanasvm, trx/trontvm, btc/bitcoinutxo, atomcosmos, and sui/aptos/aptmove.
Token sidetoken supports base and quote; default is base.
K-line intervalsSupported intervals are 1s, 1m, 15m, 1h, 4h, 1d, 1w, 1M, and 1Y. 1w, 1M, and 1Y are aggregated from 1d data.
PaginationRequest fields use page and page_size; response pagination uses page, pageSize, total, and totalPages.
CacheHTTP query APIs do not currently promise a fixed Cache-Control policy. After a WebSocket subscription succeeds, the server may send the latest in-memory snapshot.

Note: 1w, 1M, and 1Y are queried by aggregating persisted 1d candles. They do not imply direct upstream subscriptions at those granularities.


1.6 Integration flow

Recommended integration steps:

  1. Call GET /api/v1/health to verify service availability.
  2. Call POST /api/v1/admin/pools to create the liquidity pool to collect.
  3. Call PATCH /api/v1/admin/pools/{id}/activate to activate the pool and notify the ingester.
  4. Call GET /api/v1/kline/ohlcv to query historical K-line data.
  5. Connect to GET /api/v1/kline/ws and subscribe to real-time updates.

2. Pool management APIs

Pools describe the on-chain liquidity pools whose K-line data should be collected. A newly created pool has is_active: false; activate it before expecting the ingester to subscribe to upstream real-time data.

This module is used to:

  • Register pools for OHLCV collection
  • Control whether the ingester subscribes to a pool
  • Query pool metadata and activation status

2.1 Create a pool

Request

POST /api/v1/admin/pools

Request body

FieldTypeRequiredDescription
chain_typestringYesChain type, 1-50 characters, normalized by the server.
chain_idintegerYesPositive chain ID.
network_idstringYesCoinGecko network identifier, such as eth.
pool_addressstringYesPool contract address.
tokenstringNobase or quote; default is base.
dex_idstringNoDEX identifier.
labelstringNoHuman-readable label.

curl example

curl -X POST "https://api.gelabs.org/api/v1/admin/pools" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chain_type": "evm",
"chain_id": 1,
"network_id": "eth",
"pool_address": "0xabc123def456",
"token": "base",
"dex_id": "uniswap_v3",
"label": "ETH/USDC"
}'

Successful response

{
"code": 0,
"message": "ok",
"data": {
"id": 42,
"chain_type": "evm",
"chain_id": 1,
"network_id": "eth",
"pool_address": "0xabc123def456",
"token": "base",
"dex_id": "uniswap_v3",
"label": "ETH/USDC",
"is_active": false,
"created_at": "2026-04-16T08:00:00.000Z",
"updated_at": "2026-04-16T08:00:00.000Z"
}
}

Pool object fields

FieldTypeAlways returnedDescription
idintegerYesInternal pool ID.
chain_typestringYesNormalized chain type.
chain_idintegerYesChain ID.
network_idstringYesCoinGecko network identifier.
pool_addressstringYesPool contract address.
tokenstringYesCollected token side, base or quote.
dex_idstring / nullNoDEX identifier.
labelstring / nullNoHuman-readable label.
is_activebooleanYesWhether collection is active.
created_atstringYesISO 8601 creation time.
updated_atstringYesISO 8601 update time.

Common error response

Creating a duplicate pool usually returns HTTP 409:

{
"code": 10004,
"message": "Pool already exists",
"error": { "type": "ConflictError" }
}

2.2 List pools

Request

GET /api/v1/admin/pools

Query parameters

ParameterTypeRequiredDefaultDescription
pageintegerNo1Page number, starting from 1.
page_sizeintegerNo20Page size, from 1 to 100.

curl example

curl -H "X-API-Key: $API_KEY" "https://api.gelabs.org/api/v1/admin/pools?page=1&page_size=20"

Cache notes

Pool management APIs read database state directly and do not promise a fixed HTTP cache policy. Refresh local caches after creating, activating, or deactivating a pool.


2.3 Get pool details

Request

GET /api/v1/admin/pools/{id}
Path parameterTypeRequiredDescription
idintegerYesInternal pool ID.

curl example

curl -H "X-API-Key: $API_KEY" "https://api.gelabs.org/api/v1/admin/pools/42"

The response data is a single pool object. If the pool does not exist, the API returns HTTP 404 and usually uses business code 60001.

Common error response

{
"code": 60001,
"message": "Pool not found",
"error": { "type": "NotFoundError" }
}

2.4 Activate a pool

Request

PATCH /api/v1/admin/pools/{id}/activate

After activation, the service makes a best-effort attempt to notify OhlcvIngester to subscribe to upstream real-time data. Notification failure does not roll back the database state.

curl -X PATCH "https://api.gelabs.org/api/v1/admin/pools/42/activate" \
-H "X-API-Key: $API_KEY"

Successful responses return the updated pool object with is_active: true.


2.5 Deactivate a pool

Request

PATCH /api/v1/admin/pools/{id}/deactivate

After deactivation, the service makes a best-effort attempt to notify OhlcvIngester to unsubscribe from upstream real-time data. Notification failure does not roll back the database state.

curl -X PATCH "https://api.gelabs.org/api/v1/admin/pools/42/deactivate" \
-H "X-API-Key: $API_KEY"

Successful responses return the updated pool object with is_active: false.


3. Historical K-line query

This module queries persisted OHLCV candlestick data. It is suitable for chart initialization, filling gaps after client disconnects, and loading historical data before subscribing to real-time updates.

3.1 Query OHLCV data

Request

GET /api/v1/kline/ohlcv

Query parameters

ParameterTypeRequiredDefaultDescription
intervalstringYes-K-line interval: 1s, 1m, 15m, 1h, 4h, 1d, 1w, 1M, 1Y.
fromintegerYes-Query start time, Unix seconds or milliseconds.
tointegerYes-Query end time, Unix seconds or milliseconds.
limitintegerNo1000Maximum row count, from 1 to 5000.
chain_typestringYes-Chain type, normalized automatically.
chain_idintegerYes-Positive chain ID.
pool_addressstringYes-Pool contract address.
tokenstringNobasebase or quote.

curl example

curl -H "X-API-Key: $API_KEY" "https://api.gelabs.org/api/v1/kline/ohlcv?interval=1h&from=1776679200&to=1776765600&limit=500&chain_type=evm&chain_id=1&pool_address=0xabc123def456&token=base"

Successful response

data is an OHLCV array and is not wrapped in items:

{
"code": 0,
"message": "ok",
"data": [
{
"pool_id": 42,
"interval": "1h",
"open_time": 1776679200,
"open": 3500.12,
"high": 3520,
"low": 3480.5,
"close": 3510.88,
"volume": 1234567.89
}
]
}

Response fields

FieldTypeAlways returnedDescription
pool_idintegerYesInternal pool ID.
intervalstringYesK-line interval.
open_timeintegerYesCandle start time, Unix seconds.
opennumber / nullYesOpen price.
highnumber / nullYesHigh price.
lownumber / nullYesLow price.
closenumber / nullYesClose price.
volumenumber / nullYesVolume.

Cache notes

This endpoint does not declare a fixed HTTP cache header. For high-real-time scenarios, combine HTTP historical queries with WebSocket updates for the latest candle.

Common error response

{
"code": 10001,
"message": "Invalid query params",
"error": {
"type": "ValidationError",
"details": {
"fieldErrors": {
"interval": ["Required"],
"pool_address": ["Required"]
}
}
}
}

4. Market proxy APIs

Market APIs proxy CoinGecko APIs. The outer response still uses the K-Line unified success wrapper, while data contains the raw business structure returned by CoinGecko.

These APIs are useful for auxiliary display and debugging. They do not represent the internal K-Line collection state.

4.1 Get pool market details

GET /api/v1/market/pools/{network}/{address}
ParameterLocationTypeRequiredDescription
networkpathstringYesCoinGecko network identifier.
addresspathstringYesPool contract address.
includequerystringNoExtra included fields, comma-separated.
include_volume_breakdownquerystringNo"true" or "false".
include_compositionquerystringNo"true" or "false".
curl -H "X-API-Key: $API_KEY" "https://api.gelabs.org/api/v1/market/pools/eth/0xabc123def456?include=base_token,quote_token&include_volume_breakdown=true&include_composition=false"

4.2 Get token top holders

GET /api/v1/market/tokens/{network}/{address}/top-holders
ParameterLocationTypeRequiredDescription
networkpathstringYesCoinGecko network identifier.
addresspathstringYesToken contract address.
holdersquerystringNoPositive integer string or max.
include_pnl_detailsquerystringNo"true" or "false".
curl -H "X-API-Key: $API_KEY" "https://api.gelabs.org/api/v1/market/tokens/eth/0xabc123def456/top-holders?holders=10&include_pnl_details=false"

4.3 Get token metadata by contract address

GET /api/v1/market/coins/{network}/{address}
ParameterLocationTypeRequiredDescription
networkpathstringYesCoinGecko platform identifier.
addresspathstringYesToken contract address.
curl -H "X-API-Key: $API_KEY" "https://api.gelabs.org/api/v1/market/coins/ethereum/0xabc123def456"

Common proxy error response

{
"code": 99001,
"message": "Internal server error",
"error": { "type": "InternalServerError" }
}

5. K-Line WebSocket

K-Line real-time push uses a single WebSocket entry point. After connecting, clients dynamically subscribe or unsubscribe to multiple pools with JSON messages.

Keep HTTP historical query support on the client side. On first load or after reconnecting, query historical data first, then use WebSocket updates for the latest candle.

5.1 Connection requirements

Connection URL

GET /api/v1/kline/ws

Required headers

HeaderRequiredDescription
Upgrade: websocketYesStandard WebSocket upgrade header.
Connection: UpgradeYesStandard WebSocket upgrade header.
X-API-KeyYesPublic API key for API authentication and billing identification.

Note: X-API-Key is the only required business request header for external integration. Forwarding-layer internal headers are not required from integrators.

5.2 Protocol constants

ConstantString valueDirectionDescription
WS_TYPE_PINGpingClient → serverApplication heartbeat.
WS_TYPE_PONGpongServer → clientHeartbeat response.
WS_TYPE_SUBSCRIBEsubscribeClient → serverSubscribe to a pool.
WS_TYPE_UNSUBSCRIBEunsubscribeClient → serverUnsubscribe from a pool.
WS_TYPE_SUBSCRIBEDsubscribedServer → clientSubscription acknowledgement.
WS_TYPE_UNSUBSCRIBEDunsubscribedServer → clientUnsubscription acknowledgement.
WS_TYPE_OHLCVohlcvServer → clientReal-time or snapshot K-line push.
WebSocket codeDescription
0Success
4001Invalid message, such as invalid JSON or missing fields
4002Unknown command
4500Internal error, currently reserved

5.3 Client message format

{
"id": "req-001",
"type": "subscribe",
"data": {}
}
FieldTypeRequiredDescription
idstringYesRequest correlation ID.
typestringYesping, subscribe, or unsubscribe.
dataobjectDepends on commandCommand payload.

subscribe.data

FieldTypeRequiredDescription
chain_typestringYesChain type, normalized automatically.
chain_idnumberYesChain ID.
pool_addressstringYesPool address; internal pool key is lowercased.
tokenstringNobase or quote; default is base.
intervalsstring[]NoValid intervals. Missing or empty array means all intervals. Invalid values are silently ignored.

Note: intervals must be a JSON array, not a comma-separated string.

unsubscribe.data

FieldTypeRequiredDescription
chain_typestringYesChain type, normalized automatically.
chain_idnumberYesChain ID.
pool_addressstringYesPool address.
tokenstringNobase or quote; default is base.

5.4 Server message format

{
"id": "req-001",
"time": 1776682800000,
"type": "subscribed",
"code": 0,
"data": {},
"msg": "ok"
}
FieldTypeAlways returnedDescription
idstringYesRequest ID for command responses; active pushes use "".
timenumberYesServer Unix millisecond timestamp.
typestringYespong, subscribed, unsubscribed, ohlcv, or error.
codenumberYesWebSocket business code.
dataobject / nullYesPayload.
msgstringYesHuman-readable message; real-time pushes use ok, snapshots use snapshot.

5.5 Subscribe and unsubscribe examples

Heartbeat

{ "id": "hb-001", "type": "ping", "data": {} }

Subscribe

{
"id": "sub-001",
"type": "subscribe",
"data": {
"chain_type": "evm",
"chain_id": 1,
"pool_address": "0xabc123def456",
"token": "base",
"intervals": ["1m", "1h", "4h"]
}
}

Successful response:

{
"id": "sub-001",
"time": 1776682800000,
"type": "subscribed",
"code": 0,
"data": {
"key": "evm:1:0xabc123def456:base",
"intervals": ["1m", "1h", "4h"]
},
"msg": "ok"
}

If the server already has a latest tick for the pool in memory, it may immediately push an additional ohlcv snapshot.

Unsubscribe

{
"id": "unsub-001",
"type": "unsubscribe",
"data": {
"chain_type": "evm",
"chain_id": 1,
"pool_address": "0xabc123def456",
"token": "base"
}
}

5.6 Push data fields

Real-time and snapshot pushes both use type: "ohlcv":

{
"id": "",
"time": 1776682800000,
"type": "ohlcv",
"code": 0,
"data": {
"chain_type": "evm",
"chain_id": 1,
"pool_address": "0xabc123def456",
"token": "base",
"interval": "1h",
"open_time": 1776679200,
"open": 3500.12,
"high": 3520,
"low": 3480.5,
"close": 3510.88,
"volume": 1234567.89
},
"msg": "ok"
}
FieldTypeAlways returnedDescription
chain_typestring / nullYesChain type.
chain_idnumber / nullYesChain ID.
pool_addressstringYesPool address.
tokenstringYesToken side.
intervalstringYesK-line interval.
open_timenumberYesCandle start time, Unix seconds.
opennumber / nullYesOpen price.
highnumber / nullYesHigh price.
lownumber / nullYesLow price.
closenumber / nullYesClose price.
volumenumber / nullYesVolume.

KlineHub silently ignores binary frames. Clients receive no ohlcv pushes when they have no active pool subscriptions. Repeated subscribe for the same pool overwrites the pool's intervals setting.

5.7 WebSocket error messages

{
"id": "sub-001",
"time": 1776682800000,
"type": "error",
"code": 4001,
"data": null,
"msg": "subscribe: missing required fields"
}
ScenariocodeExample msg
JSON parsing failed4001Invalid JSON
Missing id or type4001Missing id or type
subscribe missing fields4001subscribe: missing required fields
unsubscribe missing fields4001unsubscribe: missing required fields
Unknown command4002Unknown command: xxx

6. Generic WebSocket

The generic WebSocket path is:

GET /api/v1/ws/{topic}

topic is used as the Durable Object instance name. The currently exposed capability only supports application-level ping/pong.

Generic WebSocket is suitable for connectivity or basic message-channel validation only. Use /api/v1/kline/ws for K-line real-time market data.


7. Operational debugging APIs (appendix)

These APIs directly inspect Durable Object internal state. They currently have no built-in authentication and should only be used in controlled networks or debugging environments.

Note: Operational debugging APIs do not always follow the unified JSON response shape. Handle text/plain or raw Durable Object JSON according to each endpoint.

7.1 Ensure the ingester is running

POST /api/v1/admin/debug/ingester/ensure
curl -X POST "https://api.gelabs.org/api/v1/admin/debug/ingester/ensure" \
-H "X-API-Key: $API_KEY"

Successful response:

ok

7.2 Get ingester status

GET /api/v1/admin/debug/ingester/status

Key response fields:

FieldTypeAlways returnedDescription
connectedbooleanYesWhether the upstream CoinGecko WebSocket is connected.
channelConfirmedbooleanYesWhether the upstream Action Cable channel is confirmed.
lastTickAtstring / nullYesLast tick time.
poolCountintegerYesNumber of subscribed pools in memory.
poolsarrayYesPool subscriptions held by the ingester.

7.3 Get KlineHub status

GET /api/v1/admin/debug/hub/status

Key response fields:

FieldTypeAlways returnedDescription
wsCountintegerYesNumber of WebSocket clients connected to KlineHub.
poolCountintegerYesNumber of pool keys with subscribed clients.
pools[].keystringYesPool subscription key: chain_type:chain_id:pool_address:token.
pools[].clientCountintegerYesNumber of clients subscribed to the pool key.
lastIngestAtstring / nullYesLast ingester push time.
lastIngestKeystring / nullYesPool key of the latest ingested tick.

8. Health check (appendix)

GET /api/v1/health
curl -H "X-API-Key: $API_KEY" "https://api.gelabs.org/api/v1/health"

Successful response:

{
"code": 0,
"message": "ok",
"data": {
"status": "ok",
"timestamp": "2026-04-16T08:00:00.000Z"
}
}

9. Error handling and best practices

9.1 Common HTTP errors

HTTPCommon business codeDescription
40010001 / 10002 / 10005Missing or invalid parameters, or WebSocket preflight error.
40410003 / 60001Route, pool, or upstream resource not found.
40910004Resource conflict, such as duplicate pool creation.
50099001 / 99002 / 99003Internal service, database, or cache error.

Clients should check both the HTTP status code and response body code. Business success is represented by code: 0.

9.2 WebSocket integration recommendations

ItemRecommendation
HeartbeatPeriodically send { "id": "hb-001", "type": "ping", "data": {} } and verify pong.
ReconnectUse exponential backoff after disconnects and re-send subscriptions after reconnecting.
Gap fillingAfter reconnecting, call GET /api/v1/kline/ohlcv to fill missing historical data.
IdempotencyTreat the same pool, interval, and open_time as an upsert key.
Subscription stateRepeated subscribe overwrites the pool's intervals; maintain local subscription state.

9.3 Timestamp handling

  • HTTP from and to accept Unix seconds or milliseconds.
  • OHLCV open_time uses Unix seconds; WebSocket envelope time uses Unix milliseconds.
  • Store timestamps in UTC and convert time zones only in the presentation layer.

9.4 Price and volume precision

  • open, high, low, close, and volume may be null.
  • Use high-precision decimal types or string storage for prices, volume, and market values when precision matters.
  • Market proxy data is passed through from CoinGecko and may use different field types from K-Line OHLCV data.

Document version: v1.0.0 | Last updated: 2026-04-28