BitRaffleDocs

Draw service

Draw service

Pick winners from any list (giveaway entrants, prize-draw tickets, a jury pool) and get a proof that anyone can check without trusting you or us.

Picking at random is easy. Proving you did not re-run the draw until you liked the answer is not. The draw service fixes its own random seed before you supply yours, so neither side can steer the result, and it hands back everything needed to recompute it.

Your server BitRaffle POST /draws/commit seed chosen sha256(seed): the commitment you choose clientSeed POST /draws/{id}/reveal · clientSeed + candidates winners + proof (seed revealed)
We are bound to our seed before you pick yours, and you pick yours knowing only its hash, so neither side can steer the result.
Price$0.01 per revealed draw, paid from a prepaid USDC balance. GET /draws/info always has the current price.
List sizeUp to 10,000 candidates of up to 512 characters each.
WinnersAny number up to the list size, distinct, in the order drawn (first place first).
ProofA JSON receipt. Check it on the verify page in a browser, or in a few lines of your own code.
AccessA key with the draws:create scope. Commit, reveal, deposit and key rotation also need a signed BitRaffle-Proof header.

Set up, once

  1. Get a key with the draws:create scope.
  2. Create an Ed25519 key pair and register its public half with POST /draws/register-key. See Signed requests.
  3. Fund your balance with USDC. See Funding your balance.

Run a draw

Assuming the proof() signing helper from Signed requests:

Node.js
const API = "https://www.bitraffle.io/api/v1";
const auth = { Authorization: `Bearer ${process.env.BITRAFFLE_SECRET_KEY}` };

async function call(method, path, body) {
  const url = API + path;
  const res = await fetch(url, {
    method,
    headers: { ...auth, "BitRaffle-Proof": proof({ method, url }), "Content-Type": "application/json" },
    body: body && JSON.stringify(body),
  });
  if (!res.ok) throw new Error(`${res.status} ${JSON.stringify(await res.json())}`);
  return res.json();
}

// 1. Commit: we publish a hash of our secret seed. Save it.
const { drawId, serverSeedHash } = await call("POST", "/draws/commit");

// 2. Only now choose your seed: anything we could not have predicted.
const clientSeed = `weekly-giveaway-${new Date().toISOString()}`;

// 3. Reveal: your seed + the list -> winners and a proof.
const { result, proof: drawProof } = await call("POST", `/draws/${drawId}/reveal`, {
  clientSeed,
  candidates: ["alice@example.com", "bob@example.com", "carol@example.com"],
  pick: 1,
});

console.log(result.winners);                              // ["bob@example.com"]
console.log(drawProof.serverSeedHash === serverSeedHash); // true: the seed was fixed first

Rules worth knowing

  • Choose clientSeed after you receive the commitment. A seed chosen first, or one we could predict, weakens the proof.
  • Keep your list in a fixed order and publish it, or its hash, with the result. The proof binds the exact list.
  • Revealing again with identical inputs returns the same result at no charge. Different inputs on an already revealed draw are refused with 409.
  • A draw belongs to your organisation. Another organisation's key cannot reveal or read it.