Math.random() leaves no receipt.
Fine for particles, useless in a dispute. Nothing records what the numbers were or how they were made.
Provably fair RNG API · open source
A free, open-source API for random numbers, dice rolls, winner picks and shuffles. Every result comes with a server hash and a proof anyone can check.
{
"outcome": [],
"message": "Click 'Generate' to try the API"
}Try a draw, then check it with the outcome verifier or read the API reference.
Open by default
The generator, the spec and the audit trail are all open, so nothing about a draw depends on taking our word for it. Check any of it.
provable-coreThe generator the API runs. MIT licensed.@provableio/sdkTyped TypeScript client on npm.openapi.jsonOpenAPI 3.0 spec for every endpoint.HMAC-SHA256Seeded bytes, mapped without modulo bias./api/commitHash published before you send a seed./api/merkleA daily Merkle root over every outcome./verifyCheck any outcome by its short ID.pk_test_Test keys that never touch live seeds.The problem
A fair draw needs a commitment before the result and a way to check it after. Most random sources give you neither.
How to generate provably fair random numbersFine for particles, useless in a dispute. Nothing records what the numbers were or how they were made.
You get a number and a promise. With no commitment made before the draw, there is nothing to check after it.
Every draw is a transaction: a fee per request and a wait for block confirmations. Worth it for contracts, heavy for everything else.
Audit trail
Each outcome is stored with its client seed, nonce and server hash. Once the seed rotates, the server seed is revealed and anyone can re-run the draw. Pick a record and replay it.
How verification works| shortId | clientSeed | range | outcome | serverHash | time (UTC) |
|---|---|---|---|---|---|
| raffle-2026-09 | 1–2400 | 284 | eb39f6e8… | 14:02:11 | |
| loot-box-7781 | 1–100 | 87 | e16699a3… | 14:02:48 | |
| tournament-seat-12 | 1–64 | 36 | 9299991b… | 14:03:05 | |
| dice-room-3 | 1–6 | 2, 6 | cbc4bc81… | 14:03:19 | |
| giveaway-oct | 1–5000 | 2033, 741, 137 | 931edfa0… | 14:04:02 | |
| mint-reveal-0419 | 1–10000 | 8310 | 190dffe9… | 14:04:37 |
Unbiased mapping
The usual shortcut maps random bytes onto a range with %, which quietly favours some numbers. provable-core throws away the few values that would tilt the odds, so every outcome is exactly as likely.
MethodSkew, log scaleMost likely outcome vs fair
provable-core ints()exactMath.random() * n+1.6e-11%uint32 % n+0.000016%byte % nmisses 2,144 outcomesMath.random() assumes a 52-bit float, as in V8. Skew is the worst-case extra chance of the most favoured outcome.
SDK
@provableio/sdk covers every endpoint with types generated from the OpenAPI spec. It runs on Node 18+, Deno, Bun, browsers and Workers, and returns errors as values instead of throwing.
import { ProvableClient } from "@provableio/sdk";
const client = new ProvableClient({ apiKey: process.env.PROVABLE_KEY });
const { data, error } = await client.getInts({
clientSeed: "raffle-2026-09",
count: 1, min: 1, max: 2400,
});
if (error) throw new Error(error.error);
// publish the hash with the winner so anyone can check it later
const { data: ok } = await client.verifyServerHash({
clientSeed: data.clientSeed,
serverHash: data.serverHash,
});Commit-reveal
For draws that must be sealed in advance, POST /api/commit returns a server hash before you choose your client seed. POST /api/reveal then returns the outcome and the seed, so the server could not have steered the result.
POST /api/commitserverHash eb39f6e84e957e12… publishedyou chooseclientSeed "raffle-2026-09"POST /api/revealoutcome returned, serverSeed aed996bd82c48a54… revealedsha256(serverSeed)equals the hash published at 14:02:07Public proof
Every outcome gets a short ID and a permalink anyone can open. Post it next to a raffle result and let people check it themselves.
Verify an outcome$ curl -s "https://api.provable.io/api/pick?clientSeed=standup-rota-oct&items=ana,ben,cy,dee"
{
"outcome": "cy",
"index": 2,
"clientSeed": "standup-rota-oct",
"serverHash": "de9f309861c8d6e6…",
"shortId": "6bqsyaI07a",
"permalink": "https://api.provable.io/o/6bqsyaI07a"
}
$ curl -s "https://api.provable.io/api/verifyShortId?shortId=6bqsyaI07a" | jq .verified
trueUse cases
Standard NdM notation, verifiable per-roll outcomes.
Draw a winner from a list, publish proof anyone can verify.
A verifiable Fisher-Yates shuffle in one HTTP call.
Pre-committed lottery draws anyone can replay.
Compliance-ready winner selection with a paper trail.
Gas-free, off-chain trait and reveal-order randomness.
FAQ
A provably fair random number is an outcome that anyone can independently verify was not chosen on purpose. The server publishes a cryptographic hash of its secret seed before you ask for a number; once your client seed is mixed in and the server seed is revealed, anyone can recompute the result and prove it matches the original hash.
Yes. Anonymous calls are free and rate-limited by IP. Signing up gives you an API key for usage attribution and a daily quota of 10,000 requests at no cost.
Go to the /verify page or call GET /api/verifyServerHash with the original clientSeed and serverHash. The endpoint returns true if the values match our records, confirming the outcome was generated as claimed.
Provable.io is a general-purpose verifiable RNG suitable for game mechanics, raffles, NFT trait reveals, and similar use cases. It is not itself a gaming licence — operators in regulated jurisdictions are responsible for their own compliance, but the cryptographic transparency the API provides is exactly the kind of evidence regulators and players ask for.
Call POST /api/commit to receive a commitment id and a hash of an outcome that has been generated but not yet shown to you. Later, call POST /api/reveal with the commitment id to receive the outcome itself. Because the hash was issued before reveal, neither party could have changed the result after the fact.
Free API key, no credit card. 10,000 requests a day.