API Reference
REST API documentation
Status: implemented local HTTP API plus production PostgreSQL/JWT mode.
Implemented app:
apps/apiRun:
bun run apps/api/src/index.tsThe local API uses Bun's HTTP server because Express is not installed in the
workspace. The route contract remains the same REST contract described here.
Workers run in-process by default so orders are matched and persisted after
submission. With RUNTIME_MODE=production, the same routes use PostgreSQL,
JWT authentication, and outbox-backed Redis command publication.
Authentication
Register
POST /auth/registerRequest:
{
"email": "trader@example.com",
"password": "long-password"
}Response:
{
"userId": "user_123"
}Login
POST /auth/loginResponse:
{
"token": "jwt",
"userId": "user_123"
}Production mode hashes passwords with Bun.password and signs JWTs with
JWT_SECRET. Local mode keeps the lightweight in-memory token flow used by
tests.
Markets
GET /markets
GET /markets/:marketIdMarket fields come from prisma/schema.prisma:
{
"id": "BTC-PERP",
"symbol": "BTC-PERP",
"baseAsset": "BTC",
"quoteAsset": "USDC",
"maxLeverage": 20,
"initialMarginRate": "0.05",
"maintenanceMarginRate": "0.005",
"makerFeeRate": "0.0002",
"takerFeeRate": "0.0005",
"fundingIntervalHours": 8,
"fundingRateCap": "0.00375",
"status": "ACTIVE"
}Deposits
POST /depositsRequest:
{
"asset": "USDC",
"amount": "10000"
}Expected behavior:
- Insert ledger entry with type
DEPOSIT. - Increase
balances.total. - Return the updated balance.
Orders
Submit Order
POST /ordersRequest:
{
"marketId": "BTC-PERP",
"side": "BUY",
"type": "LIMIT",
"quantity": "1.25",
"price": "65000",
"timeInForce": "GTC",
"reduceOnly": false,
"postOnly": true,
"clientOrderId": "client-123",
"leverage": 10
}Expected behavior:
- Validate request.
- Run risk pre-check through
packages/risk. - Insert
ordersrow with statusPENDING. - Insert an
order.createdoutbox event in the same database transaction. - The outbox publisher later appends the command to
engine.commands.{market}. - Return
202 Accepted.
Response:
{
"orderId": "order_123",
"status": "PENDING"
}Cancel Order
DELETE /orders/:orderIdExpected behavior:
- Verify ownership.
- Insert cancellation outbox event with type
order.cancelled. - Return
202 Accepted.
Queries
GET /balances
GET /positions
GET /orders
GET /orders/:orderId
GET /fillsThese endpoints read PostgreSQL projections persisted by packages/db.
In the local runtime they read the in-memory runtime store, which follows the
same order/fill/position shapes.
Admin
POST /admin/drainRuns matching and persistence workers until local streams are caught up. The API
server also runs this worker loop automatically, but this endpoint is useful in
tests. In production mode this endpoint is a no-op; run apps/workers for
outbox, matching, persistence, snapshots, and Redis acknowledgements.
Errors
Use stable error codes:
{
"error": {
"code": "INSUFFICIENT_MARGIN",
"message": "Available margin is below required margin"
}
}Recommended codes:
UNAUTHENTICATED
FORBIDDEN
MARKET_NOT_FOUND
INVALID_ORDER
INSUFFICIENT_MARGIN
DUPLICATE_CLIENT_ORDER_ID
ORDER_NOT_FOUND
ORDER_NOT_OPEN
INTERNAL_ERROR