Provably Fair Random Winner Picker for Livestream Giveaways
Pick giveaway winners from a list or a number range with a commit-reveal proof: publish the seed hash first, draw with a public salt, let anyone verify.
Result
Press “Run” to see the result.
A draw viewers can check, for livestream minigames, comment giveaways and lucky draws. 1) action=commit creates a secret seed (or takes yours) and returns its SHA-256 commitment: publish the commitment before the event and freeze the entry list. 2) action=draw with the seed, the entries (one per line, or [{"name","weight"}]) or a number range min / max, and a public salt chosen at draw time (the number of comments, a lottery result…) returns the winners and reserves. 3) Publish the seed: action=verify lets anyone recompute the draw and check SHA-256(seed) against the commitment.
Winners are drawn with HMAC-SHA256 keyed by the seed over the salt and the hash of the entry list, rejection sampling (no modulo bias) and a partial Fisher-Yates shuffle, so nobody can change the result after the commitment and the organiser cannot steer it once the salt is public. Duplicated entries are removed by default (unique_entries=false keeps them, as extra chances), weights give proportional chances, reserve draws backup winners.
The full algorithm is returned with every draw so it can be reimplemented independently. Prize promotions in Vietnam must still follow the trade promotion rules (registration / notification): this API is only the drawing tool.
Use this in your code
curl -X POST "https://apibox.io.vn/v1/random-draw/draw" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"seed":"a3f1c9e07b5d2486a3f1c9e07b5d2486","entries":"Nguyễn An\nTrần Bình\nLê Chi\nPhạm Dũng\nHoàng Em","salt":"1532","winners":2,"reserve":1}'const res = await fetch('https://apibox.io.vn/v1/random-draw/draw', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"seed": "a3f1c9e07b5d2486a3f1c9e07b5d2486",
"entries": "Nguyễn An\nTrần Bình\nLê Chi\nPhạm Dũng\nHoàng Em",
"salt": "1532",
"winners": 2,
"reserve": 1
}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://apibox.io.vn/v1/random-draw/draw",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"seed": "a3f1c9e07b5d2486a3f1c9e07b5d2486", "entries": "Nguyễn An\nTrần Bình\nLê Chi\nPhạm Dũng\nHoàng Em", "salt": "1532", "winners": 2, "reserve": 1},
timeout=30,
)
print(res.json())<?php
$ch = curl_init('https://apibox.io.vn/v1/random-draw/draw');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => '{"seed":"a3f1c9e07b5d2486a3f1c9e07b5d2486","entries":"Nguyễn An\\nTrần Bình\\nLê Chi\\nPhạm Dũng\\nHoàng Em","salt":"1532","winners":2,"reserve":1}',
]);
$response = curl_exec($ch);
print_r(json_decode($response, true));API documentation → Get a free API key
FAQ
Why is it provably fair?
The seed is fixed by the published commitment before entries close, and the public salt is unknown until draw time, so neither side can choose the result; anyone can recompute it from the revealed seed.
Is the seed stored on the server?
No. The API is stateless: keep the seed secret until the draw, then publish it. Without the seed the commitment reveals nothing.
Can people have more chances?
Yes: send entries as [{"name":"An","weight":3}], or set unique_entries=false so repeated lines count as several tickets.