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/orders
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/orders, /v1/fills

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:
    • orderbook/{market_addr}
    • trade/{market_addr}
    • ticker/{market_addr}
  • Private (only over /ws/private after auth):
    • order
    • position
    • fill

Subscribe

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

Unsubscribe

{
  "op": "unsubscribe",
  "args": ["orderbook/{market_addr}"]
}

Event delivery

{
  "op": "event",
  "topic": "ticker/{market_addr}",
  "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": "<account_id>", "req_id": "optional-id" }

5. Authentication (REST)

Private REST and private WebSocket use a short-lived JWT issued by the gateway.
  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>" }
  1. Use the token with Bearer auth for private endpoints:
Authorization: Bearer <jwt>

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): Unix milliseconds since epoch (int). Example: 1718000000000.
  • 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 ts/client_ts/server_ts: Unix nanoseconds since epoch (int). Example: 1718000000000000000.
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

{
  "error_code": 2001,
  "error_message": "Invalid signature"
}

Error codes

CodeMeaning
2000Invalid request
2001Authentication failed
2002Signature expired
2003Rate limit exceeded
2004Resource not found
HTTP status codes (400, 401, 429, etc.) 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

{
  "error_code": 2003,
  "error_message": "Rate limit exceeded"
}

10. Pagination

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

11. Response Structure

All responses are JSON objects.

Success

{
  "success": true,
  "data": { ... }
}

Error

{
  "error_code": 2001,
  "error_message": "Invalid signature"
}

12. Field Naming

  • All JSON keys use snake_case
  • All numeric values are strings
  • Timestamps are always strings in ISO 8601

13. WebSocket Heartbeats

There are two heartbeat layers:
  1. Application-level ping/pong (for latency measurement)
  • Client may send:
{ "op": "ping", "req_id": "optional-id", "ts": 1718000000000000000 }
  • Server replies:
{ "op": "pong", "req_id": "optional-id", "client_ts": 1718000000000000000, "server_ts": 1718000001000000000 }
Timestamps are Unix nanoseconds. Use these to compute RTT and clock deltas.
  1. 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.