API reference
The public APIs are read-oriented by design. Indexer responses are JSON with decimal strings for onchain integers; backend writes are limited to deposit authorization.
Service surfaces
Configure each base URL independently. A deploymentId mismatch is a release error, not a reason to silently merge data from another network.
| Service | Default | Authentication | Purpose |
|---|---|---|---|
| Indexer | http://localhost:42069 | None | Public REST, GraphQL, and SQL read models |
| Backend | http://localhost:3001 | None for token list; policy checks for auth | Deposit authorization and supported tokens |
| Settlement service | http://localhost:3002 | Internal/admin only | Automation and liveness; do not expose as a user API |
| RPC gateway | NEXT_PUBLIC_RPC_GATEWAY_URL | Method allowlist + rate limit | Transaction preparation and receipts; provider URL stays server-side |
Indexer REST endpoints
The REST projection is intentionally close to the frontend hooks. Addresses and hashes are hex strings. uint256, uint64, amounts, and ids are decimal strings in JSON so consumers do not lose precision through JavaScript numbers.
| Method | Path | Response |
|---|---|---|
| GET | /activity/recent?limit=12 | Recent purchases and prize claims |
| GET | /ledger/balance/:user | { balance } |
| GET | /ledger/deposits/:user | Deposit event rows |
| GET | /ledger/withdrawals/:user | Withdrawal event rows |
| GET | /lotto3d/current | Lotto3D round snapshot or null |
| GET | /lotto3d/rounds?page=1&pageSize=10 | items, page, pageSize, hasMore |
| GET | /lotto3d/history/:buyer/page?page=1&pageSize=8 | Paginated ticket history |
| GET | /lotto3d/rounds/:roundId | Lotto3D round snapshot |
| GET | /lotto-uma/current | Round, drawRequest, settlement |
| GET | /btc15m/status | Feature gate and indexed flag |
| GET | /v1/markets | WF BTC 5M market lifecycle |
| GET | /v1/markets/:marketId/quote | Best executable quote |
| GET | /v1/markets/:marketId/book | Aggregated public order-book depth |
| POST | /v1/orders | Submit an EIP-712 signed order |
| DELETE | /v1/orders/:orderHash | Cancel a user-owned order |
| GET | /v1/trades | Indexed or matcher trade history |
Read the current round
const response = await fetch(`${INDEXER_URL}/lotto-uma/current`);
if (!response.ok) throw new Error(`indexer HTTP ${response.status}`);
const snapshot = await response.json();
if (!snapshot) throw new Error("No current round");
if (snapshot.deploymentId !== EXPECTED_DEPLOYMENT_ID) {
throw new Error("indexer is serving another deployment");
}
if (snapshot.effectiveStatus === "betting_open") {
// still simulate the contract call before presenting a buy button
}Backend utility endpoints
These endpoints are convenience surfaces, not custody or settlement APIs. They may be unavailable when the upstream bridge provider is unavailable, and their output must be checked against the active manifest before use.
| Method | Path | Response / behavior |
|---|---|---|
| GET | /api/v1/tokens | { tokens: [{ symbol, address, decimals }] } |
| GET | /api/v1/bridge/supported-source-chains | { chains } or 502 BRIDGE_CHAINS_UNAVAILABLE |
| GET | /health | Backend and database health; 503 when unavailable |
| GET | /api/health | Frontend process health and deploymentId |
GraphQL and SQL over HTTP
The indexer also mounts /graphql and /sql/* for integrations that need filtered or analytical queries. These endpoints expose indexed data, not privileged chain writes. The generated schema is available in indexer/generated/schema.graphql and should be pinned by clients that need a stable query contract.
query CurrentRounds {
lotto3dRounds(limit: 5, orderBy: "roundId", orderDirection: "desc") {
items { roundId status winningNumber updatedAtBlock }
}
}Errors, retries, and consistency
- Retry idempotent GET requests with bounded backoff. Do not blindly retry a wallet write or deposit authorization after a timeout without checking whether the nonce was consumed.
- HTTP 503 from /admin/health or an empty indexer response means the read model is unavailable; it does not mean funds or a round disappeared.
- Use the chain receipt to resolve ambiguous writes. The indexer can be backfilled or restarted without changing contract state.
- Treat unknown fields as forward-compatible and preserve decimal strings as bigint/BigNumber values in the client.