What you'll build

Two tiny endpoints — rollDie(sides) and flipCoin() — that anyone can independently audit. The API does the heavy lifting; your code is mostly glue.

Roll an N-sided die

A die roll is just a uniform random integer in [1, sides]. One call:

curl "https://api.provable.io/api/ints?clientSeed=player_42&count=1&min=1&max=6"

From Node.js:

async function rollDie(playerSeed, sides = 6) {
  const url = new URL("https://api.provable.io/api/ints");
  url.searchParams.set("clientSeed", playerSeed);
  url.searchParams.set("count", "1");
  url.searchParams.set("min", "1");
  url.searchParams.set("max", String(sides));

  const res = await fetch(url, {
    headers: { "x-api-key": process.env.PROVABLE_KEY }
  });
  const { outcome } = await res.json();
  return outcome[0];
}

console.log(await rollDie("player_42", 20)); // d20

Flip a coin

A coin is a 2-sided die. Map 1 → heads, 2 → tails.

async function flipCoin(playerSeed) {
  const n = await rollDie(playerSeed, 2);
  return n === 1 ? "heads" : "tails";
}

Roll several dice at once

Use count to grab a batch in one request — cheaper and faster than looping.

// 4d6 for a D&D stat roll
const url = "https://api.provable.io/api/ints?clientSeed=player_42&count=4&min=1&max=6";
const { outcome } = await fetch(url).then(r => r.json());
const total = outcome.reduce((a, b) => a + b, 0);

Make it verifiable

The response includes a serverHash. Show it to the player along with the clientSeed and roll result. They can paste all three into /verify to confirm you didn't cherry-pick the outcome.

For maximum trust, commit the serverHash before the roll happens — publish it on a public timeline (X, Discord) so the player knows the server couldn't have changed it after seeing their seed.

Next steps