Developers

API

The public routes behind the site. JSON unless noted.

BROWSERSERVERrun, 30 s or moreworker, WebGPUvalidate, insertone transactionnothing storedPOST /api/ticket200 { ticket, issuedAt }POST /api/runs { ticket, operatorKey, result, env }201 { id, status, seq, percentile, rewards }The Stack page then picks the new die up from the cell stream.
A run is two requests. Everything between them happens in the browser.

Runs

RouteParamsReturnsCDN cacheErrors
POST /api/ticketnone{ ticket, issuedAt }no-store429 rate-limited
POST /api/runsSubmission, JSON, 256 KB max201 SubmitResponseno-store400 invalid-json, invalid-submission; 409 ticket-used; 413 too-large; 422 bad-ticket, too-fast, ticket-expired, duration-mismatch; 429 rate-limited
GET /api/runslimit, 1 to 100, default 20Newest dies, by seq5 s, swr 30 snone
GET /api/runs/{id}run idRun with detail: phases, traces, adapter60 s, swr 600 s404 not-found, also for rejected runs

Submission

{
  ticket: string,                  // from POST /api/ticket
  operatorKey: string,             // 32 to 64 hex; stored only as a 16 hex SHA-256 prefix
  result: BenchResult,             // engine output: phases, metrics, adapter, timing
  env: {
    renderer: string | null,       // WebGL renderer string
    glVendor: string | null,
    userAgent: string,             // reduced to browser and OS
    declaredFormFactor?: "laptop" | "desktop" | null,
    hiddenDuringRun: boolean
  }
}

SubmitResponse

{
  id: string,
  status: "verified" | "unranked" | "rejected",
  flags: string[],
  seq, layer, cell: number | null, // null when rejected
  score: number,
  memprint: string,
  deviceClass: { id, name, vendor, source },
  percentile: {                    // top is null below 5 runs
    class: { top, n },
    global: { top, n }
  },
  rewards: { kind, points, note }[]
}

The Stack

RouteParamsReturnsCDN cacheErrors
GET /api/stacknone{ totals, recent }, 12 newest dies5 s, swr 30 snone
GET /api/stack/cellsfrom, a seqapplication/octet-stream10 s, swr 60 snone
GET /api/stack/dieseq{ id, seq, t, class_name, vendor, read_gbps, score, status, memprint, synthetic }300 s, swr 1 h400 seq required; 404 not-found

The cell stream is a 16-byte header then 8 bytes per die; The Stack has the byte layout. The Stack page polls it every 20 s with from set to the dies it already holds; the home page polls /api/stack at the same rate.

Boards

RouteParamsReturnsCDN cacheErrors
GET /api/leaderboardboard: class (needs class), daily (default), weekly, efficiencyUp to 50 rows, best run per operator10 s, swr 60 s400 class required, unknown board
GET /api/classesnonePer class: runs, operators, median score and read, best, published peak20 s, swr 120 snone
GET /api/rewardsoperator, 16 hex, optional{ season, standings }; with operator also { summary, standing }10 s, swr 60 s; no-store with operator400 invalid operator

Token

RouteParamsReturnsCDN cacheErrors
GET /api/tokennonePhase, token, launch, market, holders, 24 h volume10 s, swr 60 s503 unavailable
GET /api/token/tradeslimit, 1 to 100, default 30Newest trades: side, amounts, trader, time5 s, swr 30 snone
GET /api/token/chartrange: 1h, 24h, 7d or allOHLC candles of execution price, with volume15 s, swr 60 snone
GET /api/token/holdersnone{ count, top }, labelled protocol addresses30 s, swr 120 snone
GET /api/walletoperator, 16 hex{ wallet } linked to the operator, with its balanceno-store400 bad-operator
POST /api/wallet{ key, address, issuedAt, signature }{ wallet }no-store400 bad input or expired; 401 signature-mismatch; 429 rate-limited

Network and claims

RouteParamsReturnsCDN cacheErrors
GET /api/networknone{ totals, proof, instant, epochs, contracts, rules }: live network state, as on /network15 s, swr 60 s503 unavailable
GET /api/rewards/instantrun, a run id; or operator, 16 hex; or none{ perRunUsd, walletDailyUsd, dailyBudgetUsd, payout | payouts | today }: status (pending_wallet, queued, sending, sent, failed, expired, skipped), reason, usd, amount, address, txno-store; 10 s without parameters400 bad-run or bad-operator; 429 rate-limited; 503 unavailable
GET /api/claimsaddress, 0x wallet{ contract, rwa, items }: per epoch amount, symbol, state, expiry and, when claimable, the Merkle proofno-store400 bad-address; 429 rate-limited; 503 unavailable
POST /api/claims/relay{ address, epochId }{ ok, tx, url, status }: an earlier daily pool claim, sent gas-free by the relayer to the wallet itselfno-store403 region or attest; 404 not-found; 409 not-claimable, not-relayable, below-minimum; 429 daily-limit, wallet-limit, rate-limited; 503 relay-off, low-balance. Refusals carry fallback: true when the wallet can still claim itself
POST /api/claims/attest{ address, issuedAt, signature }{ attested }no-store400 bad input or expired; 401 signature-mismatch; 403 region; 429 rate-limited
GET /api/proofnoneRecent daily roots: day, leaves, root, transaction60 s, swr 600 s503 unavailable
GET /api/proof/{runId}run idLeaf, sibling path, day root and transaction; or { status: pending | ineligible }60 s; 1 h once anchored404 not-found; 503 unavailable

A claim item's state is claimable, claimed, pending (the epoch waits for funding), expired, or attest. Stock Token items, including the daily pool, are left out for requests from the United States, and carry a proof only after the wallet has signed the attestation once. To claim, call claim(id, account, amount, proof) on the rewards contract; a weekly epoch id is uint256(keccak256(abi.encode(season, token))) and a daily one is uint256(keccak256(abi.encode("daily", dayIndex, token))), with dayIndex in whole UTC days since 1970. Items marked relay can be sent gas-free with POST /api/claims/relay.

// The message a wallet signs for POST /api/claims/attest (issuedAt within 10 minutes)
HBM: Stock Token rewards attestation

I am not a US person, and I will not claim Stock Token rewards from the United States.

Wallet: 0x…
Chain: Robinhood Chain (4663)
Issued: 2026-09-28T09:00:00.000Z

Signing is free and does not send a transaction.

Inference

RouteParamsReturnsCDN cacheErrors
GET /api/v1/inference/estimatemodel, gpu (class id or name), quant (default q4), ctx (default 4096), batch (default 1), gpus (1 to 8), vram (GB per GPU, optional)Fit, VRAM needed against available, decode tokens/s from measured and published bandwidth, best GPUs60 s, swr 300 s400 invalid-model, invalid-quant, invalid-gpu, invalid-ctx, invalid-batch, invalid-gpus, invalid-vram, each with valid values; 429 rate-limited
GET /api/v1/inference/modelsnoneModels with parameters, active parameters, layers, max context, source; weight formats60 s, swr 300 s429 rate-limited
GET /api/v1/inference/gpusnoneGPU classes with memory, published and measured bandwidth, verified runs60 s, swr 300 s429 rate-limited

Versioned, keyless and open to any origin (Access-Control-Allow-Origin: *). Names match loosely: gpu=4090, gpu="RTX 4090" and gpu=nvidia-rtx-4090 are the same class. Memory is in binary GB. The method is on the Inference page.

GET /api/v1/inference/estimate?model=llama-3.1-70b&quant=q4&gpu=rtx-4090

{
  "fits": false,
  "vram_needed_gb": 43.9,
  "vram_available_gb": 24,
  "memory": { "weights_gb": 39.9, "kv_cache_gb": 1.25, "overhead_gb": 2.81 },
  "decode_tok_s": { "measured": null, "spec": 22.8 },  // per stream; measured once the class has verified runs
  "batch_tok_s": 22.8,                                 // all streams, from the bandwidth named in source
  "source": "Published peak bandwidth",                // or "HBM verified runs, class median"
  "runs": 0,
  "best_gpus": ["Instinct MI300X", "H200 SXM", "H100 SXM", "A100 SXM 80GB", "H100 PCIe"],
  "best": [{ "id", "name", "vram_gb", "decode_tok_s", "source", "runs" }, …],
  "model": { … }, "quant": { … }, "gpu": { … }, "ctx": 4096, "batch": 1
}

Operations

RouteParamsReturnsCDN cacheErrors
GET /api/healthnone{ ok, db, ms }no-store503 database unavailable

Rate limits count per instance, in memory: 40 tickets and 24 submissions per hour per client address, 60 submissions per day per operator, 30 claim lookups per minute per client address, 120 inference requests per minute per client address.