What it is
A purpose-built giveaway picker on top of /api/pick. POST (or GET) the entrant list — comment usernames, retweet handles, newsletter emails, Discord IDs — and the endpoint returns one winner plus a serverHash that anyone can re-derive against the same list.
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_launch_2026_05_25",
"nonce": 0,
"serverHash": "7fcc22faaa0d29b92b4a1bda3948d7400ac3f47ba8502013bc6631f42ca4c665",
"outcome": "@heidi",
"index": 7
}- 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) = 7fcc22faaa0d29b92b4a1bda3948d7400ac3f47ba8502013bc6631f42ca4c665 - The draw is a pure function of both seeds
HMAC-SHA256(serverSeed, "giveaway_launch_2026_05_25:0:0") → index 7 of 8 = @heidi - After the draw, the seed is revealed and anyone can replay it
serverSeed = 9f45a4e884e13962116b93e4ffbab002a8a3dd4c5c7625a3c36edf900ab83ace
Try it live — one winner from a list of usernames
curl "https://api.provable.io/api/pick?clientSeed=giveaway_launch_2026_05_25&items=@alice,@bob,@carol,@dave,@erin,@frank,@grace,@heidi"
Pick multiple winners (1st place, 2nd place, 3rd place) using sequential nonces — the cursor auto-advances:
curl "https://api.provable.io/api/pick?clientSeed=giveaway_launch_2026_05_25_top3&items=@alice,@bob,@carol,@dave,@erin,@frank,@grace,@heidi"
Integration snippet
// 1. When entries close, snapshot and dedupe the eligible entries.
const entries = await collectCommentsFromPost(postId);
const usernames = [...new Set(entries.map((c) => c.author))];
// 2. Commit, and pin a post with the serverHash and the username list.
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.
// The post URL + the next block hash is a clean default.
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: `gw_${postId}_${blockHash}`,
endpoint: "ints",
params: { count: 1, min: 1, max: usernames.length }
})
}).then((r) => r.json());
// 4. Announce: "Winner is @X", with the serverHash, serverSeed and clientSeed.
console.log(usernames[draw.outcome[0] - 1], draw.serverSeed);
Common patterns
- Multi-platform giveaways. Concatenate the eligible-entry lists from X, Discord, and Instagram into one
itemsarray, publish the combined snapshot alongside the draw. - Bonus entries. Use the
weightsparameter — newsletter subscribers getweight=2, paid users getweight=3, and the math is published. - "Sticky" winners. If your community draws daily from the same pool, use a time-based
clientSeed(gw_daily_2026-05-25) so today's draw is reproducible. - Auto-redraw rules. If the winner doesn't claim in 48h, bump the nonce and pick again — published in the rules upfront.
Why this is fair
- The
serverHashis pinned before the client seed exists, and the username list is frozen before the commit, so the operator can't pick a seed that targets a specific user. - The
clientSeedis chosen from a public unguessable value (block hash, future tweet ID) so entrants can't grind their handles against it either. - The picker math (a uniform integer in
[0, N)or a weighted bucket lookup) is implemented in the open-source provable-core library and re-runs identically on every machine.
Where it fits
- Social media giveaways on X, Instagram, TikTok, LinkedIn, YouTube.
- Newsletter or community drops — pick a winner from a Mailchimp list export.
- Twitch / Kick stream giveaways picked live from chat.
- SaaS onboarding contests drawing from sign-ups during a launch window.