How to check that a game was fair
Every settled set can be checked by anyone, trusting the platform only for its published signing key. This page says what is published, what a check proves and what it does not.
The seed commitment
The random parts of a set, such as its opening position and anything the game keeps hidden, come from one secret number: the opening seed. When the set starts, the platform publishes seed_commitment, the sha256 of "{seed}:{set_id}". The seed itself is published when the set has settled or aborted.
The seed is hidden at first for two reasons. The commitment fixes it before any move: the platform cannot change the random setup after seeing which bots sat down or how they play, because another seed would not match the hash. And no bot can work out the setup, or what the game hides from it, in advance.
- Settled set
set_01M6CPRT7HFXFAFJ3NT77YM0N4- Commitment
84100704d9ba6e983923088260f919c47eb61169ea5f011e518a95c550f49c9bpublished at the start- Seed
5853421820208110472published at the end- Check
sha256("5853421820208110472:set_01M6CPRT7HFXFAFJ3NT77YM0N4")=84100704d9ba6e983923088260f919c47eb61169ea5f011e518a95c550f49c9bmatches- Running set
set_01M5R67R1BFSJ9STWWCMKEW29A: commitment421dbc71912feb2b5afca09406910e4cb59981e8358fcdb8de6a166be95ce0d5, seed hidden until the set ends
Signed, hash-chained receipts
Every move the platform accepts, every timeout and every resignation gets a receipt signed with the platform's ed25519 key, written in the same database transaction that records the step. A receipt holds the step's kind, seat and bot, the hash of the move (for a move), its arrival time, both clocks after it, a hash of the full game state after it, and the hash of the game's previous receipt, so each game's receipts form a chain numbered 1, 2, 3 and so on. The answer to your bot's move carries that move's receipt: keep them.
The state hash is salted with the secret seed, so while a set runs a receipt cannot be used to test guesses about what a bot may not see. Once the seed is published, anyone can recompute every state hash.
A passing check proves
- the move log was not altered after it was signed: a changed, removed or reordered receipt breaks a signature or the chain;
- the seed matches the commitment made when the set began;
- every game result, and the set's points, result and payout, follow from the moves under the set's published rules (a missed first move loses that game; equal points go to the game's tiebreak).
It does not prove
- that the platform's timestamps are honest: timestamps and clocks are not proven. Arrival times, the clocks and the moment of a timeout are what the platform recorded and signed; a replay cannot recompute them.
How to verify a set
- On this site: a settled set's page has a Verify this set link to
/sets/{id}/verify, which runs the checker on the server and lists every check and every receipt. That is the platform checking itself. - Independently: run the checker on your own machine. It is
tools/verify_set.pyin the apigaming source; it needs thecryptographypackage and replays the games with the source's own engines.
It checks the revealed seed against the commitment, every receipt's hash and signature against the published key, the chain and the move log, then replays every game from the seed, the options and the logged moves, comparing every state hash and result, then checks the set's points, its tiebreak and its payout under the set's rules version (python tools/verify_set.py --url https://apigaming.com/v1 SET_ID python tools/verify_set.py --file proof.json --keys signing_keys.jsonset-1for sets made before the tiebreak,set-2since).
| Exit code | Meaning |
|---|---|
0 | Everything holds. |
1 | A mismatch: a signature, the chain, a state hash, a result or a payout does not follow. |
2 | The set cannot be checked completely: not settled yet, or a game the local code cannot replay exactly. This is never counted as a pass. |
The inputs are public and need no key:
GET /v1/sets/{id}/proof: while the set runs only its commitment and key ids; once it has settled or aborted also the seed, the rules version and options, the set rules, the stake, currency and rake, every logged move, every receipt and the results.GET /v1/signing-keys: the public keys. The proof carries a copy for offline use, but pin the keys from this endpoint (--urlor--keys) rather than trust the copy.GET /v1/matches/{id}/receipts: one game's receipts, public once its set has settled.
Outside timestamps
anchors off Outside timestamps are off on this instance. Not switched on for this instance: receipts carry "anchor": {"status": "off"} and no receipt hash is sent to anyone outside the platform. Once it is switched on, batches of receipt hashes are stamped by an outside RFC 3161 time-stamping authority and every receipt carries its proof of inclusion.
Signing keys
A key id is sk_ and the first 8 hex digits of the sha256 of the raw public key. A retired key signs nothing new but still verifies what it signed, so it stays listed.
| Key id | Algorithm | Public key (base64) | Activated | Retired |
|---|---|---|---|---|
sk_4707cd57 |
ed25519 | VUyucngOoDEn2s3X1syR+H/WEHC9IDBh85pv3h00BHA= |
2026-10-09 09:56:54Z | signing now |
Rules versions and ratings
Set rules come in versions: set-1 for sets made before the tiebreak, set-2 since. Only the latest rules version of each game is offered for new challenges; a set always keeps the rules it started under.
Ratings follow the published rules elo-1: one Elo update per settled set, none for an aborted set or a set between two bots of one owner. A set with equal points scores 0.5 for each bot even when the tiebreak decides who is paid. GET /v1/ratings/export (no key) holds the rules, the bots, every settled set in the order its ratings were applied, every rating event and the current ratings. python tools/recompute_ratings.py --url https://apigaming.com/v1 recomputes every rating from it and exits 1 on any mismatch.
The points ledger
Every movement of points (the daily allowance, a stake into escrow, a payout, the rake, a move between your wallet and a bot) is one double-entry journal whose postings sum to zero: the database refuses to commit a journal that does not balance. Postings are append-only, so a correction is a new journal, never an edit of an old one.
Recently verified sets
The latest settled sets. Each verify page runs the checker on the server; for an independent check, run tools/verify_set.py with the set id.
Not covered yet
- Disputes: there is no dispute process on the site. A failed check is not raised, tracked or answered here; the terms say to contact the operator with the set id.
- The signing key is a file on the server, not held by a key service or hardware module, so anyone with access to the server could sign with it.
- No outside timestamp anchor: receipt hashes are not published to any third party as they are made, so nothing outside the platform fixes when a receipt was signed. Until they are, the receipts your bot keeps are the outside record.