Skip to main content
This document outlines Ekiden’s API design conventions and standards. These ensure consistency, developer-friendliness, and compatibility across all REST and WebSocket interfaces.

1. Base URLs and Environments

Ekiden provides separate base URLs for each environment:
All API calls must use HTTPS.

2. Versioning

We use URI-based versioning:
  • Format: /v1/
  • Example: GET /v1/market/instruments
Backward-incompatible changes will trigger a new version (e.g., /v2/).

3. RESTful Design

MethodDescription
GETFetch resources (e.g., market data)
POSTCreate resources (e.g., place an order)
DELETECancel or remove resources
PATCHUpdate partial resources
  • Resources are nouns, pluralized when appropriate
    • Example: /v1/trade/orders, /v1/trade/executions

4. WebSocket Protocol

Endpoints:
  • Mainnet: (Coming Soon)
  • Testnet Beta:
    • Public data: wss://api.ekiden.fi/ws/public
    • Private data: wss://api.ekiden.fi/ws/private
  • Testnet Staging:
    • Public data: wss://api.staging.ekiden.fi/ws/public
    • Private data: wss://api.staging.ekiden.fi/ws/private
Messages use an op field with snake_case values. Optional req_id lets you correlate requests/responses.

Topics

  • Public (Market-scoped):
    • orderbook.<depth>.<symbol> (e.g., orderbook.1.BTCUSDC)
    • trade.<symbol>
    • ticker.<symbol>
    • kline.<interval>.<symbol>
  • Private (User-scoped, only over /ws/private after auth):
    • order
    • position
    • execution
    • account_balance

Subscribe

Client → Server
{
  "op": "subscribe",
  "args": ["orderbook.1.BTCUSDC", "ticker.BTCUSDC"],
  "req_id": "optional-id"
}
Server → Client
{
  "op": "subscribed",
  "args": ["orderbook.1.BTCUSDC", "ticker.BTCUSDC"],
  "req_id": "optional-id"
}

Unsubscribe

{
  "op": "unsubscribe",
  "args": ["orderbook.1.BTCUSDC"]
}

Event delivery

{
  "op": "event",
  "topic": "ticker.BTCUSDC",
  "server_ts_ms": 1731541800000,
  "data": { /* snapshot or update payload */ }
}

Authenticate (private WS only)

Send your JWT (see REST auth below) over /ws/private: Client → Server
{ "op": "auth", "bearer": "<jwt>", "req_id": "optional-id" }
Server → Client
{ "op": "auth", "success": true, "user_id": "<user_id>", "req_id": "optional-id" }

5. Authentication (REST)

Private REST and private WebSocket use a short-lived JWT issued by the gateway, or API Key authentication.

JWT Authentication

  1. Request a token via POST /api/v1/authorize by signing the message:
AUTHORIZE|{timestamp_ms}|{nonce}
with Ed25519. Body:
{
  "public_key": "0x...",
  "signature": "0x...",
  "timestamp_ms": 1731541800000,
  "nonce": "random-unique-string"
}
Response:
{ "token": "<jwt>", "user_id": "<user_id>" }
  1. Use the token with Bearer auth for private endpoints:
Authorization: Bearer <jwt>

API Key Authentication

Gateway supports API-key auth via headers:
  • X-API-KEY: Your API public key
  • X-SIGNATURE: Ed25519 signature over EKIDEN_API|{method}|{uri}|{timestamp_ms}|{nonce}
  • X-TIMESTAMP-MS: Current Unix timestamp in milliseconds
  • X-NONCE: Random unique string

6. Numerical Precision

  • All token quantities and prices are strings
  • Up to 18 decimal places
  • Use big number or decimal libraries — avoid floats
"2.000000000000000000"

7. Timestamps

We use explicit units depending on the field name and context:
  • timestamp (REST resources like orders, fills, positions): Unix seconds since epoch (int). Example: 1718000000.
  • timestamp_ms (REST authorize flow, API Key headers): Unix milliseconds since epoch (int). Example: 1718000000000.
  • server_ts_ms (WebSocket event envelope): Unix milliseconds since epoch (int).
  • ts (WebSocket ticker snapshots and ping/pong client_ts/server_ts):
    • For ticker ts: Unix milliseconds since epoch (int). Example: 1718000000000.
    • For WS ping/pong client_ts/server_ts: Unix milliseconds since epoch (int). Example: 1718000000000.
When an ISO 8601 string appears (e.g., funding endpoints), it is explicitly documented in the schema, e.g. "2025-05-10T12:34:56Z".

8. Error Handling

Error response format

{
  "code": "UNAUTHORIZED",
  "message": "Unauthorized"
}

Common Error Codes

CodeMeaning
BAD_REQUESTInvalid request parameters
UNAUTHORIZEDAuthentication failed or token expired
FORBIDDENInsufficient permissions (scopes)
RateLimitExceededToo many requests
NOT_FOUNDResource not found
SERVICE_UNAVAILABLEBackend service down or lagging
INTERNALUnexpected server error
HTTP status codes (400, 401, 403, 404, 429, 500, 503) are used appropriately.

9. Rate Limits

  • Public REST endpoints: 60 requests/minute
  • Private REST endpoints: 30 requests/minute per token

Example response on limit exceeded

{
  "code": "RateLimitExceeded",
  "message": "Rate limit exceeded"
}

10. Pagination

Offset-style pagination with page counters:
  • Query params: page (default 1), per_page (default 20)
GET /api/v1/trade/executions?symbol=BTCUSDC&page=1&per_page=20
Responses generally return arrays for list endpoints (see schema in the API reference).

11. Field Naming

  • All JSON keys use snake_case
  • All numeric values are strings (except timestamps and page counters)

12. WebSocket Heartbeats

Application-level ping/pong

  • Client may send:
{ "op": "ping", "req_id": "optional-id", "ts": 1718000000000 }
  • Server replies:
{ "op": "pong", "req_id": "optional-id", "client_ts": 1718000000000, "server_ts": 1718000001000 }
Timestamps are Unix milliseconds.

WebSocket-level ping/pong (keepalive)

  • The server periodically sends WebSocket-level pings and expects pongs.
  • If the server does not see a pong within the timeout window (~30s by default), it will close the connection.
Clients should automatically answer WS-level pings and may also send periodic app-level ping messages if desired.
For detailed endpoint specifications and integration examples, continue to the API reference.