Data model & enums
The field-level rules behind the wire types used across the Operator API and the Wallet callback API. This page is the semantics; the two API references have the exact request/response shapes for each endpoint.
Amounts & currency
- Amounts are always integers in the currency's minor unit (e.g. cents for
USD) — never floats.500means $5.00. This applies everywhere an amount appears:TransactionRequest.amount,TransactionResponse.balance, the balance callback'sbalance, and everybetAmountMinor/amountMinor/balanceMinorfield across both APIs and the shell bridge. currencymust be an uppercase, 3-letter ISO-4217 code (e.g."USD", not"usd") — the platform's validator is case-sensitive. A malformed or lowercase code is rejected with400.
TransactionType
type TransactionType = 'BET' | 'WIN' | 'ROLLBACK' | 'ADJUSTMENT'BET, WIN, and ROLLBACK are what you'll see in practice — submitted by a game studio's server and forwarded to your wallet callback API. ADJUSTMENT exists in the platform's canonical model for a rare, platform-internal admin action (a manual balance correction); handle it the same way as any other type (apply amount in the direction given by direction).
TransactionRequest
The body your POST /v1/wallet/transaction implementation receives:
| Field | Type | Notes |
|---|---|---|
transactionId | string | Generated by the provider. Reused verbatim on retry — this is the idempotency anchor your implementation must key off. |
sessionToken | string | Opaque to you — identifies the session your own POST /v1/operator/games/launch call created. Pass it through unchanged; there's no separate operatorId/playerRef field you need to cross-check it against. |
type | TransactionType | 'BET' | 'WIN' | 'ROLLBACK' | 'ADJUSTMENT' |
roundId | string | Groups the transactions belonging to one round. |
roundComplete | boolean | true on whichever of BET/WIN ends the round. Meaningful only for BET/WIN; ignored for ROLLBACK/ADJUSTMENT. |
originalTransactionId | string? | Present when type === 'ROLLBACK' — the BET's transactionId being reversed. Absent for every other type. |
playerRef | string | Your internal player identifier, the same one you passed to launchGame. |
amount | number (int64) | Minor units, >= 0. A zero-amount WIN (no payout) is valid. |
currency | string | Uppercase ISO-4217, matches the currency the session was launched with. |
gameId | string | Matches the session's game. |
direction | 'DEBIT' | 'CREDIT'? | Present only for ADJUSTMENT — which way to move the balance. Absent for BET/WIN/ROLLBACK (their direction is implied by type). |
metadata | object? | Opaque, capped at 8 KiB — see below. |
Metadata & jackpot payouts
metadata is a provider-supplied JSON object the platform stores and forwards to you verbatim, without interpreting it. It's optional, and the platform accepts it on any transaction type — the typical use is attaching jackpot detail to a WIN.
- Must be a JSON object — an array, string, number, or
nullis rejected by the platform before it ever reaches you. - Capped at 8 KiB.
- The platform never reads any key inside it — display or store it as you see fit; there's nothing you're required to act on.
// A documentation-only convention for a jackpot WIN's metadata — the
// platform does not enforce this shape, and neither should you. Any JSON
// object is accepted; treat unrecognized shapes as "nothing to show."
type JackpotMetadata = {
jackpot?: {
won: boolean
tier?: string
amountMinor?: number
poolId?: string
}
}TransactionResponse
What your implementation returns:
type ResponseStatus = 'OK' | 'DECLINED'
type TransactionResponse = { status: ResponseStatus; balance: number }DECLINED is only ever a valid outcome for a BET (insufficient funds, or outside your own configured bet limits) — it's a normal business result, not an error. WIN, ROLLBACK, and ADJUSTMENT must never be declined: if you can't apply one of those, respond with a non-200 status instead and let the platform's retry/reconciliation machinery handle it — see Errors & retry.
Session
The mapping POST /v1/operator/games/launch creates, and which sessionToken on every subsequent wallet call resolves back to:
type Session = {
token: string
playerRef: string
operatorId: string
providerId: string
gameId: string
currency: string
language: string
createdAt: string
expiresAt: string
demo: boolean
}You never see this shape directly — it's server-side platform state. It's documented here because every field on TransactionRequest that looks like it should be cross-checked (playerRef, gameId, currency) is already validated against it before the request reaches you.
Round ownership
A roundId is only unique within a (providerId, operatorId) pair — the same roundId string can exist under a different operator, or under a different game from a different provider, without colliding. This is why POST /v1/operator/rounds/replay scopes its lookup to your own operator tenant, and why a roundId you receive on a TransactionRequest is only ever meaningful paired with the gameId on the same request.
Ledger direction
Player balance delta = Σ(CREDIT) − Σ(DEBIT). BET debits, WIN credits, ROLLBACK reverses a BET (credits back), and ADJUSTMENT carries its direction explicitly. You don't need to derive this yourself — it's context for reading your own ledger against what the platform expects to see.