What it is
A drop-in randomizer for NFT projects built on /api/shuffle (for token ID assignment and reveal order) and /api/pick (for trait selection from weighted layers). Off-chain, so no LINK token, no gas, no oracle delay — but every assignment is backed by a serverHash committed before mint opens, which a holder can paste into /verify later.
A reveal order 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 shuffle right here, without calling Provable.
{
"clientSeed": "mint_collection_abc_reveal_order",
"nonce": 0,
"serverHash": "b11435bb484995cc67fe250afa1254920fb9a29a7a29454556cef7672ce551ac",
"outcome": ["16", "15", "13", "1", "2", "4", "8", "11", "14", "9", "7", "3", "6", "12", "10", "20", "5", "18", "17", "19"]
}- Before the shuffle, the server commits to a seedPublish this hash before the shuffle, so the seed can't be swapped afterwards.
serverHash = sha256(serverSeed) = b11435bb484995cc67fe250afa1254920fb9a29a7a29454556cef7672ce551ac - The shuffle is a pure function of both seeds
HMAC-SHA256(serverSeed, "mint_collection_abc_reveal_order:0:0") → Fisher-Yates order of 20 items = [16, 15, 13, 1, 2, 4, 8, 11, 14, 9, … 10 more] - After the shuffle, the seed is revealed and anyone can replay it
serverSeed = 21bac4ab78790b7fa80d65720e2e279b81bea5902e03e40935ee403fe9156780
Try it live — shuffle a 100-token reveal order
curl "https://api.provable.io/api/ints?clientSeed=mint_collection_abc_reveal_order&count=10&min=1&max=100"
Or assign a trait per layer for a single token (background, body, eyes, accessory) with published rarity weights:
curl "https://api.provable.io/api/pick?clientSeed=token_42_background&items=sky,sunset,void,rainbow&weights=60,25,10,5"
Integration snippet
// 1. Before mint opens: pin a single commitment for the whole drop.
const { commitId, serverHash } = await fetch(
"https://api.provable.io/api/commit",
{ method: "POST", headers: { "x-api-key": process.env.PROVABLE_KEY } }
).then((r) => r.json());
publishCollectionMetadata({ serverHash, mintRules: "..." });
// 2. After mint closes: reveal the seed and run the metadata shuffle.
const { serverSeed } = await fetch(
"https://api.provable.io/api/reveal",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.PROVABLE_KEY,
},
body: JSON.stringify({ commitId, clientSeed: `mint_${dropId}` }),
}
).then((r) => r.json());
// 3. Run the trait shuffle for each token. Each token uses a deterministic
// sub-seed derived from the revealed seed + tokenId, so the assignment
// is reproducible by any holder.
async function assignTraits(tokenId, layers) {
const out = {};
for (const [layer, options] of Object.entries(layers)) {
const url = new URL("https://api.provable.io/api/pick");
url.searchParams.set("clientSeed", `${serverSeed}:${tokenId}:${layer}`);
url.searchParams.set("items", options.map((o) => o.id).join(","));
url.searchParams.set("weights", options.map((o) => o.weight).join(","));
out[layer] = (await fetch(url).then((r) => r.json())).outcome;
}
return out;
}
Why this is fair
- Pre-mint commitment. The
serverHashis published in the collection metadata before the mint window opens. The team cannot pick a seed that puts their wallets on the rare tokens. - Public reveal seed. After mint closes, the
serverSeedgoes on-chain (or on IPFS) alongside the assignment script. Anyone re-runs the deterministic shuffle and confirms the trait map. - Off-chain, but auditable. No gas costs, no oracle dependency, but the verification story is just as strong as a published VRF proof.
Common patterns
- Hidden metadata. Show a placeholder image until reveal; flip to the real
tokenURIonly after the seed is published. - Token-ID shuffle. Mint sequentially, then shuffle the mapping
mintIndex → tokenIdin one call so even sniped mint indices land on random tokens. - Layered traits. One
/api/pickcall per layer with published weights — players can replay the chain of pulls for any token. - Bonus / 1-of-1s. Reserve a fixed list of token IDs for special pieces, then shuffle the remainder — the reserved list and shuffle script are both public.
Where it fits
- PFP projects with layered trait rarities.
- Generative art drops where the seed seeds the renderer.
- Gaming NFT mints with stat distributions.
- Music / collectible drops with edition-number reveals.