v0.4.0-beta · exchange infrastructure to build on

API reference

The frozen v1 contract: REST and gRPC into the OMS, order streams over WebSocket, and a separate market-data feed. This page is the tour; the repo holds the letter of the law.

Frozen contract
The v1 surface is frozen as of v0.3.0-beta. Breaking changes now require a major version (/api/v2) and a deprecation window. The machine-readable spec is openapi.yaml; the full prose contract is docs/API.md.

Wire surfaces

SurfaceTransportPortPurpose
Order APIREST8080Orders, balances, history, positions
Order APIgRPC9090Same domain, plus server-side streams
Order eventsWebSocket /ws8080Live order updates for your own orders
Market dataWebSocket /ws8081Books, trades, ticker, candles, for everyone
Admin opsREST8082Cluster lifecycle and operations

Money and ids

Two rules prevent a whole category of bugs:

  • Money is a decimal string. Prices, quantities, amounts, and balances cross the wire as strings with up to 8 decimal places: "110224.00000000". JSON numbers are IEEE doubles and silently corrupt exact values; strings round-trip bit-exactly. Responses always carry exactly 8 decimals.
  • Big ids are strings too. omsOrderId and tradeId are 64-bit ids serialized as JSON strings ("331884039403208704"): they exceed JavaScript's exact-integer range. Treat them as opaque. Small ids (userId, marketId) stay numbers.
json
{ "price": "110224.00000000", "quantity": "0.10000001", "omsOrderId": "331884039403208704" }

Authentication

Authorization: Bearer <token> on every call; identity always comes from the token, never from the body. Providers: api-key (default), jwt, dev (local only). Browser WebSockets pass the token as the second Sec-WebSocket-Protocol offer; query-string tokens are rejected. Details in security.

REST endpoints

Base: http://<oms>:8080. The ones you'll use daily:

MethodPathWhat it does
POST/api/v1/ordersCreate an order
PUT/api/v1/orders/{id}Cancel-and-replace price/quantity
DELETE/api/v1/orders/{id}Cancel
GET/api/v1/orders/{id}Fetch one order (terminal ones come from persistence)
GET/api/v1/orders?status=Your active orders
GET/api/v1/orders/historyOrder history, newest first
GET/api/v1/executionsYour fills, newest first
GET/api/v1/positionsNet position per market, from executions
GET/api/v1/accounts/{userId}Balances
POST/api/v1/accounts/{userId}/depositCredit a balance
POST/api/v1/accounts/{userId}/withdrawDebit; rejected if it exceeds available
GET/api/v1/marketsMarket list
GET/api/v1/healthLiveness (no auth)

Order lifecycle: PENDING_RISK → PENDING_HOLD → PENDING_NEW → NEW → PARTIALLY_FILLED → FILLED | CANCELLED | REJECTED (stop and trailing orders add PENDING_TRIGGER). filledQty always derives from the authoritative trade stream.

Order types: limit, market, post-only (limit-maker), stop-loss, stop-limit, trailing-stop, iceberg. Time-in-force: GTC, GTD, IOC, FOK.

Errors and rejections

Two different things, deliberately kept apart:

  • API errors are HTTP errors with a stable shape: { "error": "...", "code": "VALIDATION" }. Codes: VALIDATION, REJECTED, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, UNAVAILABLE, INTERNAL.
  • Order rejections are business outcomes, not transport errors: a normal response with accepted: false and a rejectReason from a fixed vocabulary (INSUFFICIENT_BALANCE, PRICE_COLLAR_BREACH, RATE_LIMIT_EXCEEDED, MARKET_HALTED, and friends).

Idempotency

Pass a clientOrderId (up to 64 chars, your choice) when creating an order. Retrying the same request after a lost response returns the existing order with duplicate: true instead of creating a double. The dedupe window survives OMS restarts. Once the order is terminal, the id is free to reuse.

Streams: WebSocket and gRPC

Order events (/ws on 8080): subscribe with {"action":"subscribe","channel":"orders","userId":N} and receive the same order JSON as REST, pushed on every state change.

gRPC (9090): OrderService (create, cancel, get, history, trades, plus StreamOrders/StreamExecutions) and AccountService. Same money-as-strings rule; auth via the authorization metadata key. Proto lives in oms-api.

Market data plane

The market gateway (ws://:8081/ws) streams book snapshots and deltas, trades, ticker, candles, and cluster status to all comers. One caveat worth knowing: its money values are JSON numbers, display-grade by design. The OMS plane is the authoritative one for money.

Stability policy

Frozen since v0.3.0-beta: no removals, renames, or type changes without a major API version and a one-minor-release deprecation window. Additive changes (new fields, endpoints, enum values) can land in any minor release, so write clients that tolerate unknown fields. The precise policy text is at the bottom of API.md.

Open Exchange

The open-source core to launch your own exchange. Fast, fault-tolerant, built in public.

v0.4.0-beta

Apache 2.0 · Beta software: the public API is frozen, but it has not had an external security audit yet and should not hold production money until it does. Open Exchange is the infrastructure you build an exchange on; KYC/AML, custody, fiat, identity, and compliance are the integrator’s responsibility.