Flux

API Reference

REST API documentation

Status: implemented local HTTP API plus production PostgreSQL/JWT mode.

Implemented app:

apps/api

Run:

bun run apps/api/src/index.ts

The 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/register

Request:

{
  "email": "trader@example.com",
  "password": "long-password"
}

Response:

{
  "userId": "user_123"
}

Login

POST /auth/login

Response:

{
  "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/:marketId

Market 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 /deposits

Request:

{
  "asset": "USDC",
  "amount": "10000"
}

Expected behavior:

  1. Insert ledger entry with type DEPOSIT.
  2. Increase balances.total.
  3. Return the updated balance.

Orders

Submit Order

POST /orders

Request:

{
  "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:

  1. Validate request.
  2. Run risk pre-check through packages/risk.
  3. Insert orders row with status PENDING.
  4. Insert an order.created outbox event in the same database transaction.
  5. The outbox publisher later appends the command to engine.commands.{market}.
  6. Return 202 Accepted.

Response:

{
  "orderId": "order_123",
  "status": "PENDING"
}

Cancel Order

DELETE /orders/:orderId

Expected behavior:

  1. Verify ownership.
  2. Insert cancellation outbox event with type order.cancelled.
  3. Return 202 Accepted.

Queries

GET /balances
GET /positions
GET /orders
GET /orders/:orderId
GET /fills

These 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/drain

Runs 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

On this page