Skip to content
For LLMsView as Markdown·

ScatterKings for Operators

Add ScatterKings (SK) slot games to your casino through OneHazel.

The integration direction: OneHazel runs the ScatterKings connector — it speaks SK's protocol, signs and verifies SK's callbacks, and routes them. Your job is to expose a wallet OneHazel can settle play against, sync the games to your storefront, and open the launch link. You never write ScatterKings-specific code, never hold SK's signing keys, and never build an SK-shaped payload.

OneHazel ⇄ you — the contract

OneHazel's connector calls a vendor-neutral wallet & session API on your side (/provider/v1/*) for every balance check, bet, win, rollback, and free-round. You implement that contract (or, on a OneHazel-supported platform, it's already built). OneHazel handles everything SK-specific — protocol, HMAC signatures, routing, currency conversion. The same contract serves every game provider, not just SK.

How a spin flows

 player clicks Play
   → your storefront gets a launch link from OneHazel and opens it
   → OneHazel exchanges the link, starts the SK game, returns the game client
   → as the player spins, SK → OneHazel → YOUR wallet:
        POST /provider/v1/session/balance    show balance
        POST /provider/v1/wallet/bet         debit the stake
        POST /provider/v1/wallet/win         credit a win
        POST /provider/v1/wallet/rollback    reverse on error
   → your ledger is the source of truth; the in-game balance mirrors it

ScatterKings never calls you directly — OneHazel's connector does, after translating SK's protocol into the vendor-neutral contract below.

Which path are you on?

Your platformWhat you do
On a OneHazel-supported platform (the wallet contract is already built in)Config only — mint a key (Step 1); OneHazel registers the connection and syncs the catalogue. Then Steps 3–5.
Your own / custom platformImplement the receiving side of the /provider/v1/* contract (Step 2), then config.

Reference implementation

A complete, code-verified reference implementation of this entire contract exists (SIM Casino, OPERATOR_API.md). Use it as a worked sample to build against — not a platform you adopt. An established operator implements the contract on their own wallet/ledger.

Step 1 — Get approved + mint a callback key

ScatterKings approves each operator in writing before go-live; OneHazel coordinates that approval and provisioning for you. In parallel, mint an integrator key with the provider_callback scope on your platform — the credential OneHazel presents on every wallet call:

bash
POST /api/v1/admin/integrator-keys
Authorization: Bearer <your-admin-jwt>
{ "name": "onehazel-scatterkings", "scopes": ["provider_callback"] }

 { "key": "sim_live_<48 hex>", "last4": "…", "is_active": true }   # shown once

Give OneHazel, over a secure channel (not email/chat): the key, your platform base URL, and your operator identity.

Scope matters

A key without provider_callback authenticates but is rejected on every wallet call with 403 SCOPE_FORBIDDEN (distinct from 401 AUTH_INVALID for an unknown/revoked key). If wallet calls 403 after go-live, check the scope first.

Step 2 — Implement the wallet contract

Custom platforms only — on a supported platform this is built in; skip to Step 3.

OneHazel calls these endpoints on your platform. This is the minimum surface to connect. Auth on every call: Authorization: Bearer sim_live_<your key>. All money is int64 minor units (EUR 3.56 = 356).

EndpointYou implement
POST /provider/v1/session/start + /session/exchangeMint a one-shot launch token, then exchange it for a wallet-capable session token.
POST /provider/v1/session/balanceReturn the wallet balance for a session token.
POST /provider/v1/wallet/bet · /win · /rollbackDebit / credit / reverse against your ledger, keyed on idempotency_key.
POST /provider/v1/catalog/syncUpsert the games OneHazel pushes.
GET /api/v1/public/v2/gamesPublic read of synced games — your lobby source.
POST /provider/v1/freerounds/*Optional — only if you run SK free-round campaigns; otherwise return 501.

Four cross-cutting must-builds underneath those endpoints:

  1. Idempotency store — persist (idempotency_key → HTTP status + response body) and replay it byte-for-byte (adding "duplicate": true) on any repeat. Globally unique across endpoints. This is what makes every mutating call safe to retry.
  2. Wallet ledger in int64 minor units — never floats. bet debits, win credits, rollback reverses by the echoed metadata.amount_minor.
  3. Session mint/verify — a short-lived one-shot plaunch_* (~5-min TTL) exchanged for a longer-lived psess_*; verify on every wallet call.
  4. Public catalogue read — serve the synced games so the storefront can launch them.

Endpoint samples

One flow throughout: player p_abc, EUR wallet at 10000 (€100.00), bet 350, win 1200.

Exchange the launch token → wallet sessionPOST /provider/v1/session/exchange

json
// request
{ "idempotency_key": "ik_exch_<uuid>", "launch_token": "plaunch_abcd1234…", "client_ip": "203.0.113.42" }
// response
{
  "session": { "token": "psess_ef5678…", "expires_at": "2026-05-25T13:00:00Z" },
  "player":  { "external_id": "p_abc", "currency": "EUR", "balance_minor": 10000 },
  "duplicate": false
}

BalancePOST /provider/v1/session/balance

json
// request
{ "session_token": "psess_ef5678…" }
// response
{ "player_external_id": "p_abc", "currency": "EUR", "balance_minor": 10000 }

Bet (debit)POST /provider/v1/wallet/bet

json
// request
{ "idempotency_key": "ik_bet_<uuid>", "session_token": "psess_ef5678…",
  "round_external_id": "round_77a2", "amount_minor": 350, "currency": "EUR",
  "provider_transaction_id": "sk_tx_8841", "round_closed": false }
// response
{ "status": "accepted", "player_external_id": "p_abc", "currency": "EUR",
  "balance_minor": 9650, "transaction_external_id": "tx_0a1b2c3d…", "duplicate": false }

Win (credit)POST /provider/v1/wallet/win

json
// request
{ "idempotency_key": "ik_win_<uuid>", "session_token": "psess_ef5678…",
  "bet_idempotency_key": "ik_bet_<uuid>", "round_external_id": "round_77a2",
  "amount_minor": 1200, "currency": "EUR", "provider_transaction_id": "sk_tx_8842",
  "round_closed": true }
// response
{ "status": "accepted", "player_external_id": "p_abc", "currency": "EUR",
  "balance_minor": 10850, "transaction_external_id": "tx_1b2c3d4e…", "duplicate": false }

RollbackPOST /provider/v1/wallet/rollback — reverses a prior bet or win by its target_idempotency_key. You must echo the original amount in metadata.amount_minor (the original request body isn't stored).

json
// request
{ "idempotency_key": "ik_rbk_<uuid>", "session_token": "psess_ef5678…",
  "target_idempotency_key": "ik_win_<uuid>", "round_external_id": "round_77a2",
  "provider_transaction_id": "sk_tx_8843", "metadata": { "amount_minor": 1200 } }
// response
{ "status": "rolled_back", "player_external_id": "p_abc", "currency": "EUR",
  "balance_minor": 9650, "duplicate": false }

Response contract

Wallet calls return a status string + the post-op balance_minor:

statusMeaningHTTP
acceptedBet/win applied200
insufficient_fundsBalance too low (bet only) — returns the unchanged balance402
rolled_backReversal applied200
"duplicate": trueIdempotent replay of a prior call — original body + status replayed(replays original)

Error envelope is { "success": false, "error": { "code", "message" } }. Key codes: validation_error 400 · session_unknown / session_expired / session_revoked 401 · unknown_player / unknown_provider / unknown_game 404 · unknown_transaction 404 (rollback) · currency_mismatch 409 · bet_out_of_bounds 400 · launch_token_consumed 409.

Session lifecyclebet requires an active session; win and rollback are honored on an expired session (the game runtime may queue a payout after the session lapses); revoked / unknown → 401 on everything.

Free rounds (optional)

If you run SK free-round campaigns, implement freerounds/{issue,get,cancel,settle}. The key rule: free-round bets are funded by the provider (no wallet/bet debits), and winnings are paid as a single lump sum at result time — so settle (mapped from SK's freerounds.result) credits total_win_minor to the wallet exactly once and closes the grant. Do not also credit free-round wins via wallet/win. Replays never double-credit; a re-settle of a closed grant returns 409 before any credit.

Step 3 — Sync + show the games

OneHazel pushes the SK catalogue to your POST /provider/v1/catalog/sync (upsert by <provider_slug>:<provider_game_code>). Your storefront then reads the public catalogue (GET /api/v1/public/v2/games) and renders the SK titles on your slots page alongside your other providers.

Read the right catalogue

Render from the catalogue catalog/sync writes to — not a separate hand-curated CMS list — or the games sync fine but never appear on your site.

Step 4 — Wire game launch

When a player clicks an SK game, get the launch URL from OneHazel for that player + game, and open it — embedded in an iframe or as a full-page redirect.

Two-stage launch token (why it's safe)

The launch URL carries only a single-use plaunch_* token — never a wallet-capable session token. OneHazel's connector exchanges it server-side (/session/exchange) for the psess_* used on wallet calls. A leaked launch URL can't touch the wallet, and a second exchange of the same token returns 409.

If a game won't embed

Some game clients forbid being shown inside another site's frame (X-Frame-Options). If a game shows "refused to display," launch it as a full-page redirect (window.location = launchUrl) instead of an iframe.

Step 5 — Verify end-to-end

  1. Catalogue — the SK titles appear on your storefront's slots page.
  2. Launch — click a game; it loads (iframe or redirect).
  3. Balance — the in-game balance matches the player's wallet (e.g. €100.00, not 0.00 and not 10000.00 — check your minor-units conversion).
  4. Bet / win — a bet lowers the balance and a win raises it; both are reflected in your ledger (GET /api/v1/players/{id}/wallet).
  5. Free rounds (if used) — issue a grant, play it out, confirm the lump-sum credit lands once at settle.

Keeping it running

  • New games / updates — OneHazel re-runs catalog/sync; verify the new titles in your public catalogue. No operator code change.
  • Going to production — moving from the SK test environment to live is handled by OneHazel; you'll receive an updated launch link.

Reference

The full vendor-neutral contract — every endpoint, the complete error table, idempotency, session semantics, money rules, and a worked reference implementation — is in OPERATOR_API.md (the SIM Casino reference implementation you can build against). Free-round custom-bet modes and the exact catalogue shape are covered there.

Need help?

If a game won't load, the in-game balance looks wrong, or a bet/win isn't reflected in your ledger, contact OneHazel with the game and player — OneHazel owns the ScatterKings integration end-to-end and will diagnose it.