The problem
Picking a raffle winner with Math.random() on your server is asking your community to trust you. Even if you're honest, you can't prove it.
The recipe
- Commit ahead of time. Call
POST /api/commitno more than 10 minutes before the draw (commits expire) and publish theserverHash. Most teams pin it in a Discord or X post with a timestamp. - Collect entries. Lock the list when the draw closes. Number each entry 1..N.
- Use a public client seed. Use something deterministic and observable — for example, the SHA-256 of the next Bitcoin block at a known height, or a tweet ID from your account at a fixed time.
- Reveal the winner. Send the
commitIdand the public client seed to/api/reveal. The response carries the winning entry number and the revealedserverSeed.curl -X POST https://api.provable.io/api/reveal \ -H "content-type: application/json" \ -d '{"commitId":"COMMIT_ID","clientSeed":"PUBLIC_SEED","endpoint":"ints","params":{"count":1,"min":1,"max":250}}' - Publish the proof. Share the
clientSeed, theserverHash, and the outcome. Anyone can hit /verify to confirm the result.
Why this works
Because the serverHash was committed before entries closed and the clientSeed couldn't be known in advance, you couldn't have steered the outcome. Independent verification turns the raffle from "trust me" to "check for yourself."
Next steps
FAQ
How do I run a provably fair raffle?
Commit a serverHash with /api/commit shortly before entries close, freeze the entrant list at the close time, then call /api/reveal within 10 minutes with a public deterministic clientSeed (a future block hash or tweet ID). Publish the serverHash, revealed serverSeed and clientSeed so anyone can re-derive the result.
When should I publish the serverHash?
Before entries close and no more than 10 minutes before the draw, since commits expire. Publishing the hash before the clientSeed exists means the server cannot shop seeds against the entrant list.
What should I use as the clientSeed?
Something nobody controls and that becomes known after entries close: a future block hash, a Bitcoin block at a fixed height, a tweet ID scheduled for a specific time. That prevents both server-side seed shopping and entrant-side input grinding.
How do entrants verify the winner?
They check that the revealed serverSeed hashes to the published serverHash, then recompute the draw from the serverSeed, clientSeed and nonce with the provably fair calculator or the open-source provable-core library. The same inputs always produce the same winner.