Skip to main content
Base URL: http://localhost:8081 (Fastify on SERVER_PORT). CORS: CORS_ORIGIN=* by default; tighten in production.

Health

GET /health
Returns { ok: true, ... }.

Oracles

GET /v1/oracles                       → [{ id, asset, expiryMs, active, lastUpdateMs, fillCount, … }]
GET /v1/oracles/:id                   → single oracle row
GET /v1/oracles/:id/strikes           → [{ strike, isUp, asks: {…} }]
GET /v1/oracles/:id/fills?limit=50    → recent fills tape for this oracle
List rows carry fillCount so the UI can rank parallel oracle ladders by liquidity.

Quotes

GET /v1/quotes/:oracle/:strike        → { yes_ask, no_ask, fairPerToken, asOf }
Served from Redis cache (QUOTE_CACHE_TTL_S, default 300s). Miss → quote-worker schedules a fresh poll.

Positions

GET /v1/positions/:address            → [{ oracle, expiryMs, strike, isUp, qty, cost, manager }]
GET /v1/users/:address/fills          → cross-oracle fills, powers /profile portfolio
GET /v1/users/:address/redemptions    → realized P&L: payout − avg-cost basis from fills; binary rows null basis
/v1/users/:address/redemptions returns one row per redemption (predict + binary settlement::Redeemed), with realized P&L computed at read time as payout − qty × avg_fill_cost per (oracle, strike, side). Binary rows have null basis (pair mints are cost-neutral; basis lives in future V3 fills).

Agents

GET /v1/agents                        → [{ id, name, owner, agentAddress, isActive, … }]
Reads the indexed agents table (populated by darkpool::agent::AgentRegistered events). Note: paused field is stale. See agent module Warning.

Vaults

GET /v1/vaults                        → [{ id, label, binaryMarketId, expiryMs, state, totalShares, balance, … }]
GET /v1/vaults/:id                    → single vault row
GET /v1/vaults/:id/deposits           → [{ depositor, shares, ts, txDigest }]
GET /v1/users/:address/deposits       → cross-vault deposits for one address

Binary markets

GET /v1/binary-markets                → [{ slug, label, packageId, settlementId, yesType, noType, yesPoolId, noPoolId, finalOutcome, expiryMs, ooMarketLinkId }]
GET /v1/binary-markets/:id            → single market
Reads .binary-markets/registry.json from disk + merges live Settlement state (finalOutcome, expiryMs) with a 4s LRU. New markets show up immediately, no migration needed.

Optimistic Oracle

GET /v1/oo/proposals?marketLinkId=0x…   → [{ id, state, proposer, disputer, proposedOutcome, finalOutcome, challengeDeadlineMs, voteDeadlineMs, yesWeight, noWeight }]
GET /v1/oo/proposals/:id                → single proposal

Trades fast-path

POST /v1/trades/confirm               → acks a freshly-signed trade so the indexer re-delivery is a no-op
  body: { txDigest, oracle, strike, isUp, qty, cost, address, manager }
Writes the row directly into the fills table so the UI can refresh activity without waiting for the indexer poll.

Self-sponsorship

GET  /v1/sponsor                       → { enabled, sponsorAddress, perUserDailyCapSui, globalDailyCapSui, maxGasBudgetSui }
POST /v1/sponsor
  body: { txKindBytes: base64, sender: 0x… }
  → { txBytes: base64, sponsorSig: base64 }
See Self-Sponsorship for the full protocol.

WebSocket

See WebSocket API.

Files

Every route lives under packages/server/src/routes/:
routes/
├── health.ts
├── oracles.ts
├── quotes.ts
├── positions.ts
├── fills.ts
├── agents.ts
├── vaults.ts
├── binary-markets.ts
├── oo.ts
├── trades.ts
└── sponsor.ts
All registered in packages/server/src/entrypoints/api.ts.