Appearance
PatePlay for Operators
Add PatePlay (HTML5 slots + live tables) to your casino through OneHazel. You never speak PatePlay's wire protocol, never hold PatePlay's signing secret, and never build a PatePlay-shaped payload. You expose your platform's own native provider surface (/provider/v1/*, snake_case, int64 minor units) and point each game's launch template at PatePlay's relay. OneHazel runs the connector that translates PatePlay ⇄ your native shape.
This is a config + seed-data integration. If your platform already exposes the vendor-neutral /provider/v1/* surface (the SIM Casino reference implementation of the contract does), it is near zero-code on your side — you register the provider, mint a key, sync the catalogue, seed a few test players, and verify. The connector, the HMAC verification, the money translation, session auth, jackpots, and free/bonus bets live on OneHazel + PatePlay.
Who does what
| Party | Owns |
|---|---|
| You (operator) | Registering the provider; a provider_callback integrator key; the native /provider/v1/* wallet + session surface (your platform feature); the synced catalogue + launch templates on your storefront; a handful of seeded test players; verification. |
| OneHazel | The PatePlay connector (HMAC verify + money translation + session mapping), the relay/site provisioning, the connection that binds your operator + key + PatePlay environment, and coordinating PatePlay's certification + staging activation. |
| PatePlay | The game runtime + RGS, the x-api-key/x-api-hmac credential pair, the game catalogue + siteCode, the relay hosts, the hosted certification suite, and activating the staging environment. |
You talk to OneHazel. OneHazel talks to PatePlay. You expose native data; OneHazel translates.
How a spin flows
PatePlay hosts the game and runs the RGS. It is a seamless (transfer) wallet: during play PatePlay's RGS calls the connector, which calls your wallet — there is no pre-funded PatePlay balance.
player clicks Play
│ your storefront → your backend mints a launch token (plaunch_*)
▼
redirect/iframe → https://<relay>/?authCode=plaunch_*&siteCode=<siteCode>&game=<code>&language=<lang>
│ the plaunch_* IS PatePlay's authCode — no OneHazel launcher hop
▼
PatePlay game runtime ── /authenticate · /balance · /withdraw · /deposit · /cancel ──┐
│ each call signed x-api-key + x-api-hmac (HMAC-SHA256 of raw body) │
▼ │
OneHazel connector ── verifies HMAC → resolves session → translates ─────────────────┘
│ POST /provider/v1/{session/exchange, session/balance, wallet/bet, wallet/win, wallet/rollback}
▼ Authorization: Bearer <your provider_callback key>
YOUR casino wallet (the ledger; int64 minor units)Two things make this work and are the only places operators get bitten:
- The launch token IS the authCode. Your
/session/startmints a one-time launch token; you drop it straight into the relay URL asauthCode. There is no launcher hop (unlike some aggregated providers) — the browser goes to the relay directly. - Your surface speaks minor units; the connector converts. You emit
balance_minor: 100000(int64). The connector turns that into PatePlay's decimal string"1000.00". Never emit decimals from/provider/v1/*.
Prerequisites
- You are a OneHazel operator (operator id / brand provisioned).
- Your platform exposes the vendor-neutral
/provider/v1/*surface —session/start,session/exchange,session/balance,wallet/bet,wallet/win,wallet/rollback,catalog/sync. The full wire contract lives inOPERATOR_API.md(the SIM Casino reference implementation you can build against). - An admin CMS where you can register game providers and mint integrator keys.
- A storefront that renders your game catalogue and can redirect/iframe to a launch URL.
- From OneHazel/PatePlay: your
siteCode, the relay base for your environment, and the list of game codes.
Step 1 — Register the PatePlay provider
In your CMS, register PatePlay as a game provider with the relay base as launch_base_url (games get their per-game template in Step 3).
POST /api/v1/admin/game-providers
{ "name": "PatePlay", "slug": "pateplay", "default_currency": "EUR",
"launch_base_url": "https://<relay-base>/" }
→ { "id": "gp_…", "slug": "pateplay", "status": "active" }Step 2 — Mint a provider-callback key and hand it to OneHazel
Mint an integrator key with the provider_callback scope. You get the key string once — copy it immediately.
POST /api/v1/admin/integrator-keys
{ "name": "pateplay-connector", "scopes": ["provider_callback"] }
→ { "key": "sim_live_…", "last4": "…", "is_active": true } # shown onceGive OneHazel, over a secure channel:
- the integrator key (the credential the connector presents on every
/provider/v1/*call), - your casino API base URL (where your
/provider/v1/*surface lives — this becomes the connection'sprovider_base), - your operator identity (the OneHazel operator the connection binds to).
The key must carry the provider_callback scope
A key minted without provider_callback authenticates but is rejected on every wallet call (401). If wallet calls 401 after go-live, re-check the scope first.
Step 3 — Catalogue sync
Publish PatePlay's games to your catalogue with POST /provider/v1/catalog/sync (authed with your integrator key). Each entry's launch_url_template points at the relay with {token}/{lang} placeholders your backend fills at launch time:
https://<relay>/?authCode={token}&siteCode=<siteCode>&game=<gameCode>&language={lang}Classify live-table codes (e.g. the auto-live-roulette-* family) as kind: "casino" and the rest as kind: "slot".
Confirm the games landed in the catalogue your storefront reads:
bash
curl -s 'https://<your-casino-api>/api/v1/public/v2/games?kind=slot&limit=500' \
| grep -o '"provider_code":"pateplay"' | wc -l # > 0Re-sync to add or update games
Adding titles or changing metadata is just another catalog/sync — no operator code change. The sync upserts by the provider game code.
Step 4 — Surface the games and wire launch
Surface the catalogue
Render the synced games on your storefront from your transactional catalogue API (the same table catalog/sync writes to), not a hand-curated CMS list.
Large catalogues and the page cap
If your storefront requests more games than your catalogue endpoint returns per page, whole providers can drop below the cut and silently vanish — request the full page (e.g. limit=500) and page if you exceed it.
Wire launch (the launch-token = authCode model)
When a player clicks Play:
- Your storefront asks your backend to mint a launch token. The backend substitutes the template placeholders and returns a
launch_urlcontaining a single-use launch token — which is PatePlay'sauthCode. - Your storefront redirects the browser to that
launch_url(or iframes it). The browser hits the relay directly — there is no launcher exchange hop. - PatePlay's runtime calls back with
/authenticate(carrying theauthCode), which the connector maps to your/session/exchange.
Relay query params (PatePlay Wallet 1.1, camelCase): authCode (20–255 chars, one-time), siteCode, game (default lobby), language (default en), plus optional playerId, playerName, device (desktop|mobile).
Step 5 — The wallet leg (what your surface must return)
As the player plays, PatePlay's RGS calls the connector, which calls your native surface. You implement nothing PatePlay-specific — you return native shapes and the connector converts:
| PatePlay call (RGS → connector) | Reaches your surface as | You return |
|---|---|---|
/authenticate (authCode) | POST /provider/v1/session/exchange | { session: { token }, player: { external_id, currency, balance_minor, name, country } } |
/balance | POST /provider/v1/session/balance | { balance_minor, currency } |
/init-game | POST /provider/v1/session/balance (balance echo) | { balance_minor, currency } |
/withdraw (bet) | POST /provider/v1/wallet/bet | debit; { status, balance_minor } |
/deposit (win) | POST /provider/v1/wallet/win | credit; { status, balance_minor } |
/withdraw-and-deposit | wallet/bet only (the 0-value deposit leg is connector bookkeeping; wallet/win fires only if the deposit leg is ever nonzero) | debit; { status, balance_minor } |
/cancel | POST /provider/v1/wallet/rollback — bets only (0-value deposits are cancelled connector-locally; a credited win is not cancellable) | reverse the targeted bet |
/check | — (connector-local transaction lookup) | — |
session.token and minor units are both load-bearing
/session/exchange MUST return both halves: session: { token } (the wallet-capable session the connector uses on every subsequent call — returning only player breaks everything downstream) and the player block with balance_minor as an int64: 100000 means €1000.00. If you emit 1000.00 or balance instead of balance_minor, the in-game balance breaks.
Step 6 — Seed and fund test players
PatePlay's certification suite and the first live launches run against real players on your platform. Seed a handful (EUR wallets), fund them, and give OneHazel their external_ids — the connector mints certification sessions for them through your existing /session/start, so no bespoke provisioning endpoint is needed.
bash
# register
POST /api/v1/public/auth/register
{ "email":"pp_test_1@…","username":"pp_test_1","password":"…",
"first_name":"Pate","last_name":"Tester1","country":"MT","currency":"EUR" }
→ { "player": { "external_id": "p_…" } }
# fund (login → deposit)
POST /api/v1/me/transactions/deposit { "amount_minor": 100000, "method": "bank_transfer" }Hand OneHazel the external_ids over the secure channel (never the passwords).
Step 7 — Verify end-to-end
- Config resolves — mint a launch token for a seeded player and a real game code; confirm the relay URL + balance ride along:bash
curl -s -X POST 'https://<your-casino-api>/provider/v1/session/start' \ -H "Authorization: Bearer <integrator-key>" -H 'Content-Type: application/json' \ -d '{"idempotency_key":"verify1","player_external_id":"p_…","provider_slug":"pateplay","provider_game_code":"<code>","currency":"EUR","language":"en"}' # → { launch_token.token: "plaunch_…", launch_url: "https://<relay>/?authCode=plaunch_…", player.balance_minor: 100000 } - Certification — OneHazel runs PatePlay's hosted suite against the connector; it should reach 100% with no operator change beyond what you shipped.
- First
/authenticate— after PatePlay activates the environment, the first real/authenticatereturns a session + balance;/balance,/withdraw,/deposit,/cancelcomplete the loop. - Wallet reconciles — check the player's wallet in your admin before and after: a bet debits, a win credits, a cancel restores exactly.
The deltas that matter (PatePlay-specific rules)
- Auth:
x-api-key+x-api-hmac. Lowercase-hexHMAC-SHA256of the raw request body, keyed by the API secret (never on the wire). Compute over the exact received bytes — never re-serialize the JSON first, or the digest drifts and verification fails withNOT_AUTHORIZED. Reproduce a vector:bashOneHazel supplies the full cross-check vector set during onboarding.SECRET='pateplay_example_secret_0123456789' BODY='{"authToken":"e16e5e30-3fac-49c9-a12f-4f8d735c29d4","siteCode":"testsite","deviceType":"desktop"}' printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d' ' -f1 # → fd0f39cade451125c24b6d42bf3ad732b592a02ba6d2be0e6723dad39e30e2e1 - Money: v1 is 2-decimal currencies only (EUR/USD/…). Zero-decimal currencies (KRW/VND/CLP/PYG/UGX/…) need an ISO-4217 per-currency exponent map on both the connector and the wallet/UI — a planned fast-follow, out of v1.
- Free/bonus bets: PatePlay marks free bets inline (
bonus{free:true}) — the connector does not debit the stake and credits wins per-spin via/wallet/win. If your platform mirrors issuance into afreeroundsmodule, any settle call must carrytotal_win_minor = 0— the winnings were already credited per-spin, and a positive settle value double-pays. - Jackpots (v1 approximation):
jackpotContributionrides inside the stake; a jackpot payout is a normal/wallet/win(round_end). No native jackpot modelling required. - Player name/country:
/session/exchangecarriesplayer.name+countryfor PatePlay'splayerName/country. If they come back empty, the data isn't set on the player or your backend build doesn't return the fields yet — it is not a connector bug.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Game won't load: relay "took too long to respond" (TCP timeout, no HTTP status) | The PatePlay environment isn't activated yet — the relay is firewalled until PatePlay's "request staging setup" step (which comes after the certification suite) | Not a casino or connector bug. Complete certification → OneHazel sends PatePlay the setup pack → PatePlay activates the relay → launches resolve. |
Every wallet call NOT_AUTHORIZED | HMAC computed over a re-serialized body, or wrong secret | Sign the raw received bytes; confirm the secret; match against the vector above. |
Every wallet call 401 | Integrator key missing the provider_callback scope, or a wrong/revoked key in the connection | Re-mint with the scope; confirm OneHazel has the current key in the connection. |
/session/exchange returns empty name/country | The player has no name/country set, or your backend build doesn't return the fields | Set the player fields; if data is present but the response is empty, deploy the backend build that returns them. |
In-game balance shows a wrong number (e.g. 100000.00 or 10.00) | Units bug: balance_minor emitted as a decimal, or ÷100 applied twice | Emit balance_minor as an int64; contact OneHazel if your surface is correct and the game still shows a wrong figure. |
| Games synced but don't appear on the storefront | Storefront reading a curated CMS list, or hitting the catalogue page cap | Point the storefront at the transactional catalogue and request the full page (limit=500). |
Duplicate-looking wallet response with "duplicate": true | A retry reused the same idempotency_key — success, not failure | The body is the original successful response; treat as accepted. |
Day-2 operations
- Rotating the integrator key — mint the new key, give it to OneHazel, have them update the connection, then revoke the old one. Allow ~30 seconds after OneHazel confirms the update before revoking — the connector briefly caches the connection's decrypted config.
- Adding / updating games — re-run
catalog/sync; verify the new titles in your public catalogue. No operator code change. - Zero-decimal currencies — before enabling KRW/VND/CLP/…, coordinate with OneHazel: the ISO-4217 exponent handling must land on the connector and your wallet/UI together. Out of v1.
- Staging → production — a new PatePlay environment means a new relay base and
siteCode; updatelaunch_base_urland re-sync so templates point at the production relay.
Summary checklist
- [ ] PatePlay provider registered (
slug: pateplay, relaylaunch_base_url) - [ ]
provider_callbackkey minted; key + casino API base URL + operator identity handed to OneHazel securely - [ ]
catalog/synclanded; live-table codeskind: casino, restkind: slot; titles visible in your public catalogue - [ ] Storefront reads the transactional catalogue (full page); launch template →
<relay>/?authCode={token}&siteCode=…&game=<code>&language={lang} - [ ] Test players seeded + funded;
external_ids handed to OneHazel - [ ] HMAC signing cross-checked against the vector set
- [ ] Certification 100%; PatePlay environment activated; first
/authenticate+ wallet loop verified against the wallet ledger
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).
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 PatePlay integration end-to-end and will diagnose it.