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.