A lottery API for verifiable number draws
Provable.io is a lottery RNG provider for the draw step of your integration. Use the REST API for scheduled jackpots, daily games, bingo, or high-frequency lottery draws where each result needs its own timestamped, replayable proof. Ticketing, payouts, licensing, and jurisdiction-specific controls stay in your lottery platform.
Lottery API integration for high-frequency draws
Give every round a unique clientSeed and idempotency key, publish its commitment before that round closes, and record the returned outcome permalink. Your integration should schedule rounds, enforce ticket cutoffs, handle retries, and retain each receipt. See the API reference for authentication, idempotency, and rate limits.
What it is
A lottery-grade RNG built on /api/shuffle. You pick the range (1–49 for a classic 6/49, 1–69 for Powerball-style main balls, 1–90 for bingo), the API returns a verifiable draw, and every player can re-derive the numbers from the published seed pair.
No more "the wheel sometimes lands on 7" conspiracy threads. Every ball is a deterministic function of HMAC_SHA256(serverSeed, clientSeed + ":" + nonce + ":" + round).
A draw and its proof
This is what anyone can check. The three values in the steps are all a verifier needs, and the replay button recomputes the draw right here, without calling Provable.
{
"clientSeed": "lottery_draw_2026_05_25",
"nonce": 0,
"serverHash": "c472d822ddbfb6d5d0e7c7c713ec61ebfd01616fd4effadd9ecbf4f0799d34fd",
"outcome": ["34", "33", "10", "44", "9", "4", "3", "17", "23", "1", "18", "27", "21", "25", "19", "14", "46", "29", "37", "28", "42", "48", "38", "40", "24", "32", "39", "30", "43", "35", "41", "5", "6", "16", "13", "45", "11", "47", "20", "2", "26", "49", "15", "12", "36", "31", "8", "7", "22"]
}- Before the draw, the server commits to a seedPublish this hash before the draw, so the seed can't be swapped afterwards.
serverHash = sha256(serverSeed) = c472d822ddbfb6d5d0e7c7c713ec61ebfd01616fd4effadd9ecbf4f0799d34fd - The draw is a pure function of both seeds
HMAC-SHA256(serverSeed, "lottery_draw_2026_05_25:0:0") → Fisher-Yates shuffle of 49 balls, first 6 drawn = [34, 33, 10, 44, 9, 4] - After the draw, the seed is revealed and anyone can replay it
serverSeed = 938ce8c85b55cfaec8af00fbea24281f8116a6039a67beb483a67efbc7c29a59
Try it live — draw 6 numbers from 1–49
Shuffle the drum and read the first six balls. A ball can't come out twice, exactly like a real draw.
curl "https://api.provable.io/api/shuffle?clientSeed=lottery_draw_2026_05_25&items=1,2,3,...,49"
Powerball-style: 5 main balls from a drum of 69, plus one bonus ball from a separate drum of 26:
curl "https://api.provable.io/api/shuffle?clientSeed=powerball_2026_05_25_main&items=1,2,3,...,69"
curl "https://api.provable.io/api/ints?clientSeed=powerball_2026_05_25_bonus&count=1&min=1&max=26"
Integration snippet
// 1. When ticket sales close, freeze the ticket list.
// 2. Commit, and publish the serverHash on the draw page header.
const commit = await fetch("https://api.provable.io/api/commit", {
method: "POST",
headers: { "x-api-key": process.env.PROVABLE_KEY }
}).then((r) => r.json());
// 3. Reveal within 10 minutes with a clientSeed nobody knew at commit time,
// e.g. a block hash produced after the commit. Commit-reveal returns
// integers, so over-draw and keep the first 6 distinct balls. The chance
// that 20 draws from 1-49 hold fewer than 6 distinct is about 1 in 37 trillion.
const draw = await fetch("https://api.provable.io/api/reveal", {
method: "POST",
headers: { "x-api-key": process.env.PROVABLE_KEY, "content-type": "application/json" },
body: JSON.stringify({
commitId: commit.commitId,
clientSeed: `lottery_${drawId}_block_${blockHash}`,
endpoint: "ints",
params: { count: 20, min: 1, max: 49 }
})
}).then((r) => r.json());
const numbers = [...new Set(draw.outcome)].slice(0, 6);
// 4. Publish: numbers, the dedupe rule, serverHash, serverSeed and clientSeed.
Drawing without replacement
Real lotteries don't draw the same ball twice, and independent random integers can repeat: six draws from 1–49 share a number about 27% of the time. The live example above avoids that with a Fisher-Yates shuffle. The integration snippet uses option 2, because commit-reveal returns integers.
- Shuffle the drum with
/api/shuffle. Pass every ball, keep the first k. Each set of k balls is equally likely, and each ball has the same odds as pulling it from a physical drum without putting balls back. One call, and the replay covers the whole drum. - Over-draw and dedupe. Request more integers than you need and keep the first k distinct values. Also fair, but publish the dedupe rule and how many you requested, or the result can't be replayed.
Why this is fair
- Commit when sales close. The
serverHashis published once the ticket list is frozen and before theclientSeedexists, so the operator can't pick a seed that favors any specific entry. - Public
clientSeed. Anchor it to a future block hash or a verifiable public event — neither operator nor player can grind it. - Open algorithm. The mapping is documented in the open-source provable-core library, so anyone can replay the draw locally.
Where it fits
- Community lotteries and DAO treasury draws that want public auditability.
- Bingo halls and bingo apps — ball draws with a verifiable trail.
- Charity raffle-lotteries where donors expect proof their numbers were drawn fairly.
- Promotional lotteries attached to product launches or loyalty programs.