> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ekiden.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Conventions

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:

* **Mainnet**: `(Coming Soon)`
* **Testnet Beta**: [https://api.cnt.ekiden.fi/api/v1](https://api.cnt.ekiden.fi/api/v1)
* **Devnet**: [https://api.canton.ekiden.fi/api/v1](https://api.canton.ekiden.fi/api/v1)

> All API calls must use **HTTPS**.

***

## 2. Versioning

We use URI-based versioning:

* **Format**: `/v1/`
* **Example**: `GET /v1/market/tickers`

Backward-incompatible changes will trigger a new version (e.g., `/v2/`).

***

## 3. RESTful Design

| Method   | Description                                                               |
| -------- | ------------------------------------------------------------------------- |
| `GET`    | Fetch resources (e.g., market data)                                       |
| `POST`   | Create resources or perform actions (e.g., place or amend an order)       |
| `DELETE` | Cancel or remove resources                                                |
| `PUT`    | Replace or update resources where applicable (e.g., whitelist management) |

* Endpoints are organized by resource

***

## 4. WebSocket Protocol

Endpoints:

* Mainnet: `(Coming Soon)`
* Testnet Beta:
  * Public data: `wss://api.cnt.ekiden.fi/ws/public`
  * Private data: `wss://api.cnt.ekiden.fi/ws/private`
* Devnet:
  * Public data: `wss://api.canton.ekiden.fi/ws/public`
  * Private data: `wss://api.canton.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.BTC-USDC`)
  * `trade.<symbol>`
  * `ticker.<symbol>`
  * `kline.<interval>.<symbol>`
* Private (User-scoped, only over `/ws/private` after auth):
  * `order`
  * `position`
  * `execution`
  * `account_balance`

### Subscribe

Client → Server

```json theme={null}
{
  "op": "subscribe",
  "args": ["orderbook.1.BTC-USDC", "ticker.BTC-USDC"],
  "req_id": "optional-id"
}
```

Server → Client

```json theme={null}
{
  "op": "subscribed",
  "args": ["orderbook.1.BTC-USDC", "ticker.BTC-USDC"],
  "req_id": "optional-id"
}
```

### Unsubscribe

```json theme={null}
{
  "op": "unsubscribe",
  "args": ["orderbook.1.BTC-USDC"]
}
```

### Event delivery

```json theme={null}
{
  "op": "event",
  "topic": "ticker.BTC-USDC",
  "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

```json theme={null}
{ "op": "auth", "bearer": "<jwt>", "req_id": "optional-id" }
```

Server → Client

```json theme={null}
{ "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`

```json theme={null}
{
  "public_key": "<Canton Party ID>",
  "signature": "",
  "timestamp_ms": 1731541800000,
  "nonce": "random-unique-string"
}
```

Response:

```json theme={null}
{ "token": "<jwt>", "user_id": "<user_id>" }
```

2. Use the token with Bearer auth for private endpoints:

```http theme={null}
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

```json theme={null}
"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

```json theme={null}
{
  "code": "UNAUTHORIZED",
  "message": "Unauthorized"
}
```

### Common Error Codes

| Code                  | Meaning                                |
| --------------------- | -------------------------------------- |
| `BAD_REQUEST`         | Invalid request parameters             |
| `UNAUTHORIZED`        | Authentication failed or token expired |
| `FORBIDDEN`           | Insufficient permissions (scopes)      |
| `RateLimitExceeded`   | Too many requests                      |
| `NOT_FOUND`           | Resource not found                     |
| `SERVICE_UNAVAILABLE` | Backend service down or lagging        |
| `INTERNAL`            | Unexpected 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

```json theme={null}
{
  "code": "RateLimitExceeded",
  "message": "Rate limit exceeded"
}
```

***

## 10. Pagination

Offset-style pagination with page counters:

* Query params: `page` (default 1), `per_page` (default 20)

```http theme={null}
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:

```json theme={null}
{ "op": "ping", "req_id": "optional-id", "ts": 1718000000000 }
```

* Server replies:

```json theme={null}
{ "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.
