What it is

A weighted prize wheel built on /api/pick. Pass the segment labels (10% off, free shipping, $5 credit, grand prize) and segment weights (their angular share of the wheel), and the API returns the winning segment plus a serverHash a player can verify after the spin.

The wheel animation in the UI is purely visual; the segment that lands under the pointer is whichever segment the API selected.

A spin 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 spin right here, without calling Provable.

GET /api/pick?clientSeed=spin_user_42_2026_05_25_001&items=10pct_off,…,grand_prize&weights=35,15,25,15,9.5,0.5Example record
{
  "clientSeed": "spin_user_42_2026_05_25_001",
  "nonce": 0,
  "serverHash": "73eb5cde635e51b9199551f31f7c20bb446127e4db282c188f82f33f6d597011",
  "outcome": "10pct_off",
  "index": 0
}
  1. Before the spin, the server commits to a seedPublish this hash before the spin, so the seed can't be swapped afterwards.serverHash = sha256(serverSeed) = 73eb5cde635e51b9199551f31f7c20bb446127e4db282c188f82f33f6d597011
  2. The spin is a pure function of both seedsHMAC-SHA256(serverSeed, "spin_user_42_2026_05_25_001:0:0") → u × 100 lands in weight bucket 0 = 10pct_off
  3. After the spin, the seed is revealed and anyone can replay itserverSeed = d9fbf7b336eea5a4714be2173adb870ce7c488de944f5b3fd7b3295c6c7c4c71

Try it live — one spin on a 6-segment wheel

curl "https://api.provable.io/api/pick?clientSeed=spin_user_42_2026_05_25_001&items=10pct_off,20pct_off,free_ship,5_credit,try_again,grand_prize&weights=35,15,25,15,9.5,0.5"

A second spin (different nonce → independent outcome):

curl "https://api.provable.io/api/pick?clientSeed=spin_user_42_2026_05_25_002&items=10pct_off,20pct_off,free_ship,5_credit,try_again,grand_prize&weights=35,15,25,15,9.5,0.5"

Integration snippet

// 1. Publish the wheel segments + weights on a public /wheel-rates page.
const WHEEL = [
  { id: "10pct_off",   weight: 35.0 },
  { id: "20pct_off",   weight: 15.0 },
  { id: "free_ship",   weight: 25.0 },
  { id: "5_credit",    weight: 15.0 },
  { id: "try_again",   weight:  9.5 },
  { id: "grand_prize", weight:  0.5 },
];

async function spin(userId, spinIndex) {
  const url = new URL("https://api.provable.io/api/pick");
  url.searchParams.set("clientSeed", `spin_${userId}_${spinIndex}`);
  url.searchParams.set("items",   WHEEL.map((s) => s.id).join(","));
  url.searchParams.set("weights", WHEEL.map((s) => s.weight).join(","));

  const res = await fetch(url, {
    headers: { "x-api-key": process.env.PROVABLE_KEY }
  });
  const { outcome: segmentId, index, serverHash, shortId } = await res.json();

  // 2. Drive the wheel animation toward segmentId at index `index`.
  //    The UI rotation is cosmetic — the result is already decided.
  return { segmentId, serverHash, permalink: `/o/${shortId}` };
}

Why this is fair

Common patterns

Where it fits

Related