For developers & power users

SpinBloom URL API

Everything in SpinBloom is controllable by URL — no backend, no API keys, no rate limits. Build links that open a preloaded wheel, jump to a mode, share a ladder, reveal a Secret Santa match, or verify a fair draw. All state lives in the URL itself.

Query parameters

paramwhat it doesexample
modeOpens a tab: wheel · slots · ladder · bracket · teams · number · dice · santa · bingo/?mode=bingo
langUI language: en ko ja zh es fr de/?lang=ko
tLoads a wheel template: yesno · food · nums · letters · consonants · truthdare/?t=yesno&lang=en
wPreloads wheel entries — URL-safe base64 of a JSON array of {"n":name,"w":weight}/?w=W3sibiI6IlllcyIsInciOjF9…
lA shared ladder (amidakuji): participants, results and the exact rung layout, restored maskedgenerated by the ladder's Share link button
ssA Secret Santa personal reveal: {"n":giver,"r":receiver} — shows a tap-to-reveal card for one persongenerated by the Secret Santa draw
proofA self-verifying fair-draw proof: entries, seed, SHA-256 commitment and winners. The page recomputes everything and shows ✓/✗generated by fair mode's Copy proof link
overlay1 = streamer mode: transparent background, wheel only, space-bar spins — for OBS browser sources/?overlay=1

Parameters combine: /?overlay=1&w=… pins a specific wheel in a stream overlay; /?t=food&lang=ko opens the Korean food wheel.

Building a ?w= payload

The wheel payload is standard JSON, base64-encoded with URL-safe characters (+-, /_, padding stripped):

const entries = [
  { n: "Alice", w: 1 },
  { n: "Bob",   w: 2 },   // weight 2 = twice the slice
  { n: "Carol", w: 1 }
];
const payload = btoa(unescape(encodeURIComponent(JSON.stringify(entries))))
  .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
const url = "https://spin.inblooms.net/?w=" + payload;

The same payload format drives the embeddable widget:

<iframe src="https://spin.inblooms.net/embed?w=PAYLOAD"
  width="420" height="540" style="border:0;border-radius:12px"
  loading="lazy" title="SpinBloom wheel"></iframe>

Verifying a ?proof= draw yourself

Fair-mode proofs are deliberately reproducible outside SpinBloom. The rule: picki = the first 8 bytes of SHA-256(seed + ":" + i) as a big-endian integer, mod the total weight of remaining entries, walked cumulatively over remaining entries in listed order (picked entries are removed between draws). In Python:

import hashlib, json, base64

payload = json.loads(base64.urlsafe_b64decode(PROOF_PARAM + "=="))
entries, seed = payload["e"], payload["s"]

assert hashlib.sha256(seed.encode()).hexdigest() == payload["c"]  # commitment

remaining = list(range(len(entries)))
winners = []
for k in range(len(payload["w"])):
    v = int(hashlib.sha256(f"{seed}:{k}".encode()).hexdigest()[:16], 16)
    r = v % sum(entries[i]["w"] for i in remaining)
    for j, i in enumerate(remaining):
        r -= entries[i]["w"]
        if r < 0:
            winners.append(entries[i]["n"]); remaining.pop(j); break

assert winners == payload["w"]  # reproduces the announced winners

Notes

All state is client-side — these URLs contain the data itself, nothing is fetched from a server, and opening them sends nothing back. Links have no expiry. The randomness behind every draw is crypto.getRandomValues. If you build something on top of this, we'd love to hear about it.

More

Fair giveaway picker · Wheel for streamers · Embed widget · All SpinBloom tools