OREStats API v1
Paid endpoints under /api/v1/*. All require Authorization: Bearer ore_…. Subscribe at /pricing.
Subscribing via API
- POST /api/v1/subscribe with
{ ownerPubkey }— server returns a unique nonce + ORE amount. - Send the priceOre amount of ORE from step 1 to the treasury address (returned in the same response), attaching the nonce as an SPL Memo instruction.
- PUT /api/v1/subscribe with
{ nonce, txSig, ownerPubkey }— server verifies on-chain, activates subscription, returns your API key. - Use
Authorization: Bearer ore_…header on all /api/v1/* calls.
Payment details
A9HLwE6wCm7Hedo7771nwsX8TyArv7rgdVQMo9dgDGZForeoU2P8bN6jkk3jbaiVxYnG1dCXcYxwhwyK9jSybcp/api/v1/pricingpublicpurpose: Current price (in ORE) for one month of access. Price ladders up as more subs join — the response also tells you the next threshold and the price beyond it.
{
"activeSubs": 17,
"oreNow": 0.1,
"nextThreshold": 100,
"oreAtNextThreshold": 0.2,
"treasury": "...",
"oreMint": "..."
}/api/v1/subscribepublicpurpose: Step 1 of subscribing. Returns a one-shot SPL transfer instruction (memo + amount) you must sign with the owner wallet and broadcast on Solana.
ownerPubkey— base58 Solana pubkey that will own the API key
{ "ownerPubkey": "..." }{
"nonce": "ore-pay-...",
"priceOre": 0.1,
"instructions": { "to": "...", "memo": "ore-pay-...", "amountBaseUnits": "10000000000", "mint": "..." },
"expiresAt": "..."
}/api/v1/subscribepublicpurpose: Step 2 of subscribing. After the SPL transfer confirms, submit the tx signature to mint your API key. The plaintext key is shown ONCE.
nonce— value returned from POST /subscribetxSig— confirmed SPL transfer signature carrying the memo from step 1ownerPubkey— must match the wallet that paid (and was passed to POST)
{ "nonce": "...", "txSig": "...", "ownerPubkey": "..." }{
"apiKey": "ore_xxx (shown ONCE)",
"subscriberId": "sub_...",
"paidUntil": "..."
}/api/v1/livepaid (Bearer)purpose: Current round snapshot — what every square holds right now, seconds remaining, and last round's result. Cheap; safe to poll every 1-2 s.
current round snapshot (deployed, count, secondsLeft, prevRound)
/api/v1/streampaid (Bearer)purpose: SSE feed of /live. Pushes a fresh snapshot whenever the on-chain board or round account changes. Reconnect any time — the next event is always the latest state.
server-sent events; pushes a snapshot on every on-chain board / round account change
/api/v1/statspaid (Bearer)purpose: Aggregated grid statistics: chi-squared on cumulative hits, per-square hit count & deployed SOL, total SOL ever deployed, effective house edge.
aggregate (chi-squared, perGrid, totalDeployedSol, effectiveHouseEdge)
/api/v1/rounds?limit=100paid (Bearer)purpose: Last N indexed rounds, newest first. Use this for batch ingest; for low-latency new-round alerts use /events/stream.
limit— number of rounds to return; default 100, max 10000
last N indexed rounds (id, deployed[25], count[25], winningSquare, totalDeployed, totalWinnings)
/api/v1/rounds/{id}paid (Bearer)purpose: Single round detail with prev/next ids for cursor traversal of history.
id— round id (path segment)
single round + prev/next ids
/api/v1/grid/{n}?limit=200paid (Bearer)purpose: Per-square stats plus the recent hit/miss series (1 = hit, 0 = miss) for chart rendering.
n— square index 0..24 (path segment)limit— series length; default 200
per-grid stat + recent hit/miss series (1 ≤ n ≤ 25)
/api/v1/events?since=N&limit=M&kind=Xpaid (Bearer)purpose: Polled event log. Includes drought-broken, big-round, tier-crossing, milestones, subscription changes. Pull events newer than the `since` cursor.
since— id cursor; only events with id > since are returnedlimit— max events per call; default 100kind— optional filter: drought_broken | big_round | tier | milestone | subscription
{
"count": 12,
"lastId": 47,
"events": [
{ "id": 47, "ts": "...", "kind": "drought_broken", "grid": 8, "drought": 91, "roundId": 247101 },
{ "id": 48, "ts": "...", "kind": "big_round", "roundId": 247155, "deployedSol": 8.94, "thresholdSol": 8.15, "multiplier": 1.10, "winningSquare": 12, "totalMiners": 209 },
...
]
}/api/v1/events/stream?since=N&kind=Xpaid (Bearer)purpose: SSE feed of the same event log as /events. Replays last 50 events (or events since cursor) on connect, then pushes each new event live.
since— optional replay cursor; if omitted, replays last 50kind— optional filter (same set as /events)
server-sent events; replays last 50 (or events since cursor) on connect, then pushes each new event as it fires (drought / streak / big round / tier / milestone / subscription).
/api/v1/dump?from=X&to=Y&limit=10000paid (Bearer)purpose: Bulk historical export — page through all indexed rounds via `from` / `nextFrom` cursors. Use this to bootstrap your own database, then switch to /events/stream for incremental updates.
from— starting round id (inclusive)to— optional ending round id (inclusive)limit— page size; default 5000, max 10000
{
"count": 5000,
"from": 228237,
"to": 233236,
"hasMore": true,
"nextFrom": 233237,
"rounds": [ { id, deployed[25], count[25], winningSquare, totalDeployed, totalWinnings }, ... ]
}/api/v1/reissuepublicpurpose: Step 1 of rotating an API key. Returns a message you must sign with the wallet that owns the active subscription.
ownerPubkey— wallet that originally subscribed
{ "ownerPubkey": "..." }{ "nonce": "ore-reissue-...", "message": "OREStats reissue ... @ ...", "expiresAt": "..." }/api/v1/reissuepublicpurpose: Step 2 of rotation. Submit the wallet signature; old key is revoked immediately and a new key is returned (also shown ONCE).
nonce— value returned from POST /reissueownerPubkey— same wallet as POSTsignatureBase64— base64-encoded ed25519 signature of the message string
{ "nonce": "...", "ownerPubkey": "...", "signatureBase64": "..." }{ "apiKey": "ore_xxx (NEW, old key revoked)", "subscriberId": "sub_...", "paidUntil": "..." }Strategy Lab
Build, backtest, and forward-test parameterized strategies. The create / backtest / analytics endpoints share one DSL shape — see the values reference at the bottom of this section.
/api/v1/lab/strategiespaid (Bearer)purpose: Create a strategy. Once active, OREStats automatically records a paper-trading prediction for every new round and surfaces forward-test stats.
name— display label, non-empty stringdsl— full Strategy DSL — base_strategy, params, optional filters[]. See values reference below.
{
"name": "my cold-5",
"dsl": {
"base_strategy": "cold",
"params": {
"bet_size_lamports": 200000,
"num_squares": 5,
"sizing_mode": "flat",
"max_bet_per_square_lamports": 5000000,
"tx_fee_lamports": 10000
},
"filters": [
{ "metric": "current_drought_min", "op": ">=", "value": 30 }
]
}
}{
"strategy": {
"id": "...", "owner": "...", "name": "...",
"dsl": { "base_strategy": "...", "params": { ... }, "filters": [ ... ] },
"createdAt": "...", "updatedAt": "...", "active": true
}
}/api/v1/lab/strategiespaid (Bearer)purpose: List your owned strategies with live forward-test stats (rounds settled, win count, ROI on real round outcomes).
{
"count": 3,
"strategies": [
{
"id": "...", "name": "...", "dsl": { ... }, "active": true,
"stats": { "roundsSettled": 412, "roundsWon": 88, "netProfitSol": 0.123, "roiPercent": 4.7 }
},
...
]
}/api/v1/lab/strategies/{id}paid (Bearer)purpose: Fetch a single strategy you own, with its prediction count.
id— strategy id (path segment)
{ "strategy": { ... }, "predictionCount": 412 }/api/v1/lab/strategies/{id}paid (Bearer)purpose: Rename a strategy or toggle its active flag. Inactive strategies stop being predicted on new rounds but their history is preserved.
name— new display name (optional)active— true to resume predictions, false to pause (optional)
{ "name": "renamed", "active": false }{ "strategy": { ... } }/api/v1/lab/strategies/{id}paid (Bearer)purpose: Hard delete a strategy you own. All linked predictions are removed; the leaderboard entry (if any) disappears.
id— strategy id (path segment)
{ "ok": true }/api/v1/lab/strategies/{id}/forwardpaid (Bearer)purpose: Forward-test stats for one strategy: net SOL, ROI, win rate, equity curve, max drawdown, max losing streak, pending unsettled rounds.
id— strategy id (path segment)
{
"strategyId": "...",
"roundsObserved": 432,
"roundsBet": 412, "roundsWon": 88,
"squaresBet": 2060, "squaresWon": 92,
"netProfitSol": 0.12, "totalStakeSol": 2.6,
"roiPercent": 4.7, "winRate": 0.21, "perSquareWinRate": 0.045,
"maxDrawdownSol": 0.08, "maxStreak": 12,
"equityCurve": [{ "round": 247001, "balanceLamports": 0 }, ...],
"pendingCount": 1
}/api/v1/lab/backtestpaid (Bearer)purpose: Replay a DSL against the indexed historical rounds. Returns full BacktestResult including per-round PnL, per-square contribution, equity curve, and early-exit reason.
dsl— Strategy DSL (same shape as create)fromRoundId— optional inclusive lower bound of replay windowtoRoundId— optional inclusive upper bound
{
"dsl": { "base_strategy": "...", "params": { ... }, "filters": [ ... ] },
"fromRoundId": 200000,
"toRoundId": 247000
}{
"result": {
"totalRounds": 47000, "roundsBet": 9200, "roundsWon": 1800,
"squaresBet": 46000, "squaresWonOn": 1900,
"netProfitLamports": ..., "netProfitSol": ...,
"totalStakeLamports": ..., "totalStakeSol": ...,
"totalRecoveryLamports": ..., "totalRecoverySol": ...,
"roiPercent": ..., "winRate": ..., "perSquareWinRate": ...,
"maxStreak": ..., "capHits": ..., "totalCapLossSol": ...,
"minWalletSol": ..., "maxDrawdownSol": ...,
"rangeMin": 200000, "rangeMax": 247000,
"exitedEarly": null,
"exitRoundId": 0,
"equityCurve": [{ "round": ..., "balanceLamports": ... }, ...],
"perSquare": [{ "square": 0, "betCount": ..., "winCount": ..., "netLamports": ... }, ...],
"perRoundPnlLamports": [...],
"streakRunLengths": [...]
}
}/api/v1/lab/analyticspaid (Bearer)purpose: Heavy analytics bundle — Monte-Carlo confidence intervals plus four nested backtests across parameter sweeps. Expect 3-6 s on first call, sub-second on warm cache. Cache key is the DSL.
dsl— Strategy DSL (same shape as backtest)
{ "dsl": { ... } }{ "analytics": { ... } }/api/v1/lab/leaderboardpublicpurpose: Public top-strategies list. Only ROI / sample size is exposed; the DSL is hidden until a subscriber views the detail endpoint.
{
"generatedAt": "...",
"minRoundsToQualify": 1000,
"count": 14,
"entries": [
{ "id": "...", "name": "...", "ownerShort": "abcd...wxyz", "roiPercent": ..., "roundsSettled": ... },
...
]
}/api/v1/lab/leaderboard/{id}paid (Bearer)purpose: Full DSL of a single leaderboard entry, plus its forward-test summary and equity curve. Gated to subscribers — public users only see the top-line ROI.
id— strategy id (path segment)
{
"strategy": {
"id": "...", "name": "...", "ownerShort": "abcd...wxyz",
"dsl": { ... },
"createdAt": "..."
},
"forwardTest": {
"roundsSettled": ...,
"netProfitSol": ...,
"equityCurve": [{ "round": ..., "balanceLamports": ... }, ...]
}
}Strategy DSL — accepted values
base_strategy — cold, spread, drought, custom_squares, hot, top_hit_rate, bottom_hit_rate, recent_winners, anti_spread, min_miners, corners, edges, center_block, diagonal_main, diagonal_anti, row, column, checkerboard, all_25
params.sizing_mode — flat, martingale, reverse_martingale, fibonacci, dalembert, kelly
filters[].metric — rounds_since_last_big, consecutive_losses, current_drought_min, current_drought_max, total_deployed_pctile, total_miners, rounds_since_big_round, chi_square_p_recent
filters[].op — < , <= , > , >= , ==
params.* numeric ranges (server clamps out-of-range values): bet_size_lamports required, (0, 1e8] num_squares 1..25 drought_threshold 1..1000 custom_squares int[] in 0..24 hit_rate_lookback 50..20000 row_index, column_index 0..4 martingale_multiplier 1..10 loss_streak_threshold 1..100 dalembert_step_lamports 1..1e6 kelly_fraction 0.0001..1 kelly_bankroll_lamports >= 1 max_bet_per_square_lamports 1..1e8 tx_fee_lamports 0..1e7 stop_loss_streak 1..1000 cooldown_after_loss_rounds 0..500 take_profit_lamports >= 0 session_stop_loss_lamports >= 0 quotas: max 100 strategies per account
Limits & fair use
- Per API key: 5 req/sec (burst 60). 429 with
Retry-Afteron overflow. - API key in header is single-use plaintext: store it — only the hash is kept.
- Sharing keys is detectable (concurrent IPs) and may trigger revocation.
- Dashboard endpoints (
/api/live*) require browser session + Origin match — they are not for programmatic use.