Idempotency in a betting API, and why the key is yours
The safest design gives the caller the idempotency key rather than generating one. If you mint the transaction id, a retry after a timeout is unambiguous — and a timeout is the one failure every integration eventually meets.
The failure everybody meets
You send a bet. The connection times out. You do not know whether it landed.
Without idempotency you have two bad options: retry and risk charging twice, or do not retry and risk a player who lost money on a round that never opened. Both happen, and both generate the kind of support ticket that takes a week.
Who mints the key
Some APIs generate an id and return it. That is fine until the response is the thing that goes missing, at which point you cannot retry safely because you never learned the id.
So the transaction id is yours. You generate it, you send it, and it is the key the movement is recorded under on both sides. A retry is the same request byte for byte, and it is safe by construction rather than by convention.
What a correct replay does
A replayed transaction returns the same result as the first one and moves no money. Not an error, not a duplicate record, not a 409 the caller has to interpret — the same answer.
That property has to hold in both directions. We hold it for calls you make to us, and we require it of your wallet for the calls we make to you, because a chain is only as idempotent as its least careful link.
The three cases to test
- Immediate replay. Same id twice in a row, one movement.
- Delayed replay. Same id an hour later, after the round has settled. Still one movement.
- Concurrent replay. The same id twice at once, which is what an aggressive retry actually looks like. Still one movement — this is the one that catches implementations relying on a read-then-write instead of a unique constraint.
The third is the one most integrations fail, and it fails only under load, which is to say in production.
Try it against a real API
Sandbox keys are issued instantly, with play money and every game enabled. No card, no call, and the documentation is public whether or not you sign up.
More notes
- How a provably fair crash round is actually generatedA crash multiplier is derived from a hash of a server seed the operator committed to before the round, combined with a client seed the player controls. Publish the commitment first and anyone can check afterwards that the result was not chosen.
- What a casino wallet integration actually has to doFive endpoints: balance, debit, credit, refund and rollback. The only hard requirement is that debit and credit are idempotent on the transaction id you are given — everything else is detail.
- RTP, house edge and the number operators should actually checkRTP is the long-run share of stakes returned to players; the house edge is what is left. The number worth checking is not the advertised RTP but whether the running game reproduces it — which requires the operator to be able to see their own round history.