What it is
A raffle picker built on the /api/pick and /api/ints endpoints. You hand it the list of entries (or a count of numbered entries); it returns the winner, a deterministic seed trail, and a serverHash that anyone can paste into /verify to confirm the draw wasn't reshuffled after the fact.
Optional weights let you run weighted raffles (e.g. extra entries for paid tiers, loyalty multipliers) without inventing your own RNG or asking entrants to trust your math.
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": "giveaway_2026_05_24",
"nonce": 0,
"serverHash": "ee3e978fc90626daf263100bd956cc02463028090364cf779bf4cffe8e4ae921",
"outcome": "frank",
"index": 5
}- 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) = ee3e978fc90626daf263100bd956cc02463028090364cf779bf4cffe8e4ae921 - The draw is a pure function of both seeds
HMAC-SHA256(serverSeed, "giveaway_2026_05_24:0:0") → index 5 of 6 = frank - After the draw, the seed is revealed and anyone can replay it
serverSeed = 01ec7bf6c421877d8b234c9880c4346ac86e18fe5fe22aea0bed072b99eba06b
Try it live — pick a winner from a list
curl "https://api.provable.io/api/pick?clientSeed=giveaway_2026_05_24&items=alice,bob,carol,dave,eve,frank"
Same call with weighted entries (paid tier gets 3× the odds):
curl "https://api.provable.io/api/pick?clientSeed=giveaway_2026_05_24_weighted&items=free_user,free_user_2,paid_user&weights=1,1,3"
Or pick by entry number
If you have thousands of entries, don't ship the whole list — number them 1..N and draw an integer:
curl "https://api.provable.io/api/ints?clientSeed=giveaway_2026_05_24_by_number&count=1&min=1&max=1750"
Integration snippet
// 1. When entries close, freeze the entrant list and number it 1..N.
const entries = await db.entrants.findAll({ where: { campaignId }, order: ["id"] });
// 2. Commit. Post the serverHash (Discord, X, blog header) before the
// client seed exists.
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 (commits expire) with a client seed nobody
// controls and nobody knew at commit time, e.g. the next block hash.
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: `raffle_${campaignId}_${nextBlockHash}`,
endpoint: "ints",
params: { count: 1, min: 1, max: entries.length }
})
}).then((r) => r.json());
const winner = entries[draw.outcome[0] - 1];
// 4. Announce the winner with the serverHash, the revealed serverSeed and
// the clientSeed, so anyone can recompute the draw.
Why this is fair
- The
serverHashgoes out before the client seed exists, and the entrant list is frozen before the commit, so nobody can shop seeds against the list. - The
clientSeedis something nobody controls (a future block hash, a tweet ID at a future time, a Bitcoin block at a fixed height) — so entrants can't grind their own usernames against it. - The mapping (uniform integer in
[1, N]or weighted bucket lookup) is documented and re-derivable from the open-source provable-core library.
Common patterns
- Multi-prize draws. Iterate
/api/pickN times with the same seed (the API auto-advances the cursor) so the first call returns 1st place, the second returns 2nd, and so on. No duplicates required if you remove the winner from the list between calls. - Tie-breakers. Use the raffle picker as a tie-breaker by passing in the tied participants as
items. - Sponsored / VIP weighting. Use the
weightsparameter — odds are clearly published and auditable.
The full recipe
This page is the keyword-friendly intro to the raffle workflow. For the long-form walkthrough with commitment patterns, public-seed strategies, and post-draw publication tips, see the dedicated recipe: Building Fair Raffles.
Where it fits
- Community giveaways on X, Discord, Twitch, YouTube.
- Promotional draws for SaaS launches, ecommerce campaigns, and conferences.
- Sweepstakes platforms that need an auditable receipt for compliance.
- Internal drawings — bug bounty payouts, swag boxes, conference talk slots.
Related
- Recipe: Building Fair Raffles
- A/B Test Bucketing API
- How provably fair works
- Verify a published draw →
FAQ
How do I draw a verifiable winner with the raffle picker API?
Call /api/pick with the entrant list (or /api/ints with min=1, max=N if you numbered entries). The response includes the winner, a deterministic seed trail, and a serverHash anyone can paste into /verify to confirm the draw wasn't reshuffled.
Should I pass items or pick by entry number?
For small entrant lists, pass the items array directly to /api/pick. For thousands of entries, don't ship the whole list — number them 1..N and draw a single integer with /api/ints. Both paths are equally verifiable.
How do I run a weighted raffle?
Pass a weights array alongside items on /api/pick. For example, weights [1,1,3] gives the third entrant triple odds. The mapping is documented and reproducible, so weighted draws stay auditable.
How do I draw multiple prizes (1st, 2nd, 3rd)?
Iterate /api/pick N times with the same seed and remove the previous winner from the items list between calls. The cursor auto-advances, so each call returns the next place with no duplicates.