proof: the provably fair record of how it was drawn. You can ask us to replay it with one request that needs no key, or replay it yourself from the published algorithm. It is the same check the Verify button in our app runs. How the draw works: Provably Fair.
The proof
Each entry in a Buy packs response’spulls has a proof object, or null for a guaranteed pull, which no roll chose:
number
The number the draw started from. For a card, or a consolation pull, it is the first 8 hex digits of
pull_id read as an integer. For the Starter or a sealed mystery pack, it is a random seed recorded with the result.string | null
The result hash: SHA-256, in hex, of the draw’s inputs and its result. For a card,
sha256("result:<seed>:<bucket index>:<card index>:<card id>"). null for a consolation pull.string | null
sha256("seed_commit:<seed>:<timestamp>"), recorded with the pull. Card pulls only.string | null
When the pull was drawn (ISO 8601). It is part of
seed_commit_hash, and of a sealed pack’s result hash.string | null
The check that replays this pull, on
https://catchbackcards.com. null for a pull from the Steph Curry pack, which this check doesn’t cover.proof with the pull: Get an order doesn’t return it. The verification_hash you were sent at purchase lets you show later that the seed, bucket, place and card haven’t changed. It doesn’t cover the odds or the card list, and a passing check can be cached for up to a day.
Ask us to check it
Send aGET to verify_path. It needs no key.
verify_path as it is. The check takes only transaction_id, card_source and pack_type, and answers any other parameter with a 400. If you no longer have the proof, /api/verify-pull?transaction_id=<pull_id> works too: without the card_source hint, it looks in every catalog.
The response replays the draw step by step. Trimmed to the fields this guide uses, a card pull looks like this:
200 (trimmed)
verification_type first, then verified: verification_type says what was checked.
algorithm names the draw: shuffle-scaled-v3 is the current one, and older pulls name the version they were drawn with.
For a consolation pull, the check confirms only that the seed’s draw falls under the recorded consolation odds. It has no result hash.
We don’t record whether a consolation roll or an armed chase came before the bucket roll, so the check infers it from the pack’s history. A pull on a pack whose consolation was removed can come back verified: false. Contact us if yours does.
Check it yourself
For a card pull drawn withshuffle-scaled-v3:
1
Derive the seed
Take the first 8 hex digits of
pull_id and read them as an integer: fe04349b is 4261688475. It equals proof.seed.2
Generate the draws
The draws come from a linear congruential generator:
state = (0x41C64E6D × state + 0x6073) mod 2^32, starting from the seed, one draw per step. Compute it in IEEE-754 double precision, as JavaScript does. 0x41C64E6D × state can exceed 2^53 and is rounded, every pull was drawn with that rounding, and exact integer arithmetic gives different draws.3
Take them in order
One draw for a chase card, when one is armed on the pack; one for the consolation roll, when the pack has one; the bucket roll;
n − 1 shuffle draws for a bucket of n cards; then the card draw. draws_before_bucket.count says how many came before the bucket roll.4
Pick the bucket
draw / 2^32 × (sum of the bucket odds) lands in one bucket’s slice of the cumulative odds, taken in the order of step3_bucket_selection.probabilities.5
Pick the card
The shuffle draws reorder the bucket (
for i = n−1 down to 1: j = floor(draw / 2^32 × (i + 1)), swap(i, j)), and the card draw picks place floor(draw / 2^32 × n) in the shuffled list, step4_card_selection.available_cards.6
Recompute the result hash
sha256("result:<seed>:<bucket index>:<card index>:<card id>") in hex, with the card you received, equals the verification_hash you were sent.step5_result_verification.delivered_by: chase when the chase draw won the pack’s chase card, and collision_reroll when another pull claimed the selected card a moment earlier, so you got the next available card. The result hash always binds the card you received.
What the check shows
It shows that the seed lands on this bucket and this place in the recorded list, and that the card you received is at that place. The list’s order is only confirmed whenstep4_card_selection.shuffle.restores_card_id_order is true. Against the verification_hash you were sent, it also shows that the seed, bucket, place and card haven’t changed since. The seed is the pull id, which CatchBack generates when the pull is made.
