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.
The pain point
You ran the giveaway on X. You "drew a winner." The winner happens to be a mutual. Cue the replies. The fix is to never ask anyone to trust the operator — show the math instead. A verifiable giveaway picker gives the runners-up an exact answer to "how do I know you didn't pick your friend?"
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. Pre-publish the commitment when the giveaway opens.
// (e.g. pin a tweet with the serverHash before entries are accepted.)
const { serverHash } = await fetch("https://api.provable.io/api/commit", {
method: "POST",
headers: { "x-api-key": process.env.PROVABLE_KEY }
}).then((r) => r.json());
// 2. When entries close, snapshot the eligible entries.
const entries = await collectCommentsFromPost(postId);
const usernames = [...new Set(entries.map((c) => c.author))]; // dedupe
// 3. Use a clientSeed nobody controls.
// The post URL + a future block hash is a clean default.
const clientSeed = `gw_${postId}_${blockHash}`;
const url = new URL("https://api.provable.io/api/pick");
url.searchParams.set("clientSeed", clientSeed);
url.searchParams.set("items", usernames.join(","));
const res = await fetch(url, {
headers: { "x-api-key": process.env.PROVABLE_KEY }
}).then((r) => r.json());
// 4. Announce: "Winner is @X — verify the draw at /o/{shortId}"
console.log(res.outcome, res.shortId);
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 entries close, 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.