Operator Integration Guide
This guide walks you through integrating with The Aggregator from start to go-live. After completing the steps below, you will have a working game integration that can launch real-money sessions and process wallet callbacks.
Start after access, provider availability, callback setup and funding are confirmed. Implementation and validation time depend on your existing wallet integration.
Prerequisites:
- An operator account in The Aggregator cabinet (register here)
- A server that can receive HTTPS callbacks on a public URL
- Familiarity with REST APIs and webhook/callback patterns
How a Game Round Works
Section titled “How a Game Round Works”Before you start writing code, here is the full lifecycle of a single game round. This representative paid-round flow does not cover every provider or free-round sequence; see the free-round contract.
sequenceDiagram participant Player participant Operator participant Aggregator participant Provider
Player->>Operator: Opens game lobby Operator->>Aggregator: POST /v1/sessions (game_id, player_id, balance) Aggregator->>Provider: Create session Provider-->>Aggregator: Session URL Aggregator-->>Operator: { session_id, game_url } Operator->>Player: Redirect to game_url
Note over Player, Provider: Player places a bet
Provider->>Aggregator: Bet callback Aggregator->>Operator: POST {callback_url} (bet transaction) Operator-->>Aggregator: 200 OK { balance, currency } Aggregator-->>Provider: Balance confirmed
Note over Player, Provider: Player wins
Provider->>Aggregator: Win callback Aggregator->>Operator: POST {callback_url} (win transaction) Operator-->>Aggregator: 200 OK { balance, currency } Aggregator-->>Provider: Balance confirmed
Player->>Operator: Closes game (redirected to return_url)Key points to understand:
- You own the wallet. The Aggregator never holds player funds. Paid bets debit your ledger; a free bet with
is_free: truedoes not debit real money. Apply wins and refunds according to the wallet contract. - Callbacks are synchronous. The game provider waits for your response before showing the result to the player. Your callback endpoint must respond within 5 seconds.
- Idempotency is required. You may receive the same callback more than once. Use integration/organization,
provider_codeandtransaction_idto deduplicate.
Step 1: Get Your Credentials
Section titled “Step 1: Get Your Credentials”- Confirm access to the operator organization and deployment for your integration.
- Obtain a credential with permission for the intended operations, using the key-management controls available to your organization.
- Store the issued key unchanged in your secrets manager; capture it securely when it is provided.
- Configure an HTTPS callback URL and a separate signing secret. Where your deployment exposes Organization → Callback configuration or an integration wizard, use those settings; confirm the available navigation with your account contact. Store the secret when you set it rather than expecting to retrieve it from API Keys.
- Confirm provider/game availability and funding or any welcome credits agreed for real-session validation.
Complete the applicable commercial and compliance requirements before operating. Key access and technical tests do not constitute launch approval.
Funding: welcome credits depend on your launch agreement and activation. Confirm availability and permitted use before creating real-money sessions; registration does not guarantee credits. See Environments & testing.
Security: Store your API key and callback secret in environment variables or a secrets manager. Never commit them to source control. Never expose the key in browser-side code — this API is server-to-server only.
Step 2: Explore the Game Catalog
Section titled “Step 2: Explore the Game Catalog”Use the credential issued for your integration to browse its enabled games.
Request:
curl -X GET "https://api.aggregator.gg/v1/games?per_page=5" \ --header @- <<EOFAuthorization: Bearer ${AGGREGATOR_API_KEY:?Set the issued API key in the protected environment}EOFResponse:
{ "games": [ { "id": "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d", "name": "Book of Sun", "provider_code": "truelabs", "game_type": "slots", "rtp": 96.5, "volatility": "high", "has_mobile": true, "has_desktop": true, "has_demo": true, "thumbnail_url": "https://cdn.aggregator.gg/thumbs/book-of-sun.jpg", "blocked_countries": ["US", "GB"], "features": ["free_spins", "bonus_buy"], "supported_currencies": ["USD", "EUR"] } ], "total": 142, "page": 1, "per_page": 5}Using the SDK: @aggregator-gg/sdk@1.0.0 requires Node.js 24 or newer.
import { Aggregator } from "@aggregator-gg/sdk";
const apiKey = process.env.AGGREGATOR_API_KEY;if (!apiKey) throw new Error("Set AGGREGATOR_API_KEY in the server environment");const aggregator = new Aggregator({ apiKey });
// Published SDK errors can contain untrusted upstream details. Keep them out// of uncaught exceptions and logs; reuse this helper in the examples below.async function safeSdkRequest<T>(operation: () => Promise<T>): Promise<T> { try { return await operation(); } catch { throw new Error("Aggregator request failed"); }}
const { games, total } = await safeSdkRequest(() => aggregator.games.list({ type: "slots", rtp_min: 95, per_page: 25,}));
// Validate the returned fields against the API contract before using them.You can filter by provider, game type, volatility, RTP range, features, currency, and full-text search. See the full API reference for all query parameters.
Currency support
Section titled “Currency support”Every game returns supported_currencies — the ISO-4217 currencies it can be launched in. This is the game’s own list when set, otherwise the currencies its provider declares (provider→game inheritance), so a game with an empty list still inherits provider support.
Use it to build a storefront that never shows a player a game their wallet currency can’t open. Filter the catalog to a single currency with the currency query parameter:
curl -X GET "https://api.aggregator.gg/v1/games?currency=EUR" \ --header @- <<EOFAuthorization: Bearer ${AGGREGATOR_API_KEY:?Set the issued API key in the protected environment}EOFOnly games whose effective supported_currencies includes EUR are returned (filtered before pagination, so total reflects it). You can also read provider-level support directly — without paging through games — from GET /v1/providers/registry, where each provider carries its own supported_currencies.
A session launched (Step 3) in a currency the selected game and provider don’t support can fail at launch, so filtering the catalog up front is the difference between a clean storefront and a dead-end click for the player.
Step 3: Launch a Game
Section titled “Step 3: Launch a Game”To launch a game for a player, create a session. The response includes a game_url that you redirect the player to.
Request:
curl -X POST "https://api.aggregator.gg/v1/sessions" \ --header @- \ -H "Idempotency-Key: launch-player-42-20260402-001" \ -H "Content-Type: application/json" \ -d '{ "game_id": "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d", "player_id": "player_42", "balance": 10000, "currency": "EUR", "country": "DE", "lang": "de", "return_url": "https://your-casino.com/lobby" }' <<EOFAuthorization: Bearer ${AGGREGATOR_API_KEY:?Set the issued API key in the protected environment}EOFResponse:
{ "session_id": "8c8e8c8e-8c8e-4c8e-8c8e-8c8e8c8e8c8e", "game_url": "https://games.aggregator.gg/launch/8c8e8c8e-8c8e-4c8e-8c8e-8c8e8c8e8c8e", "provider_session_uid": "tl_session_abc", "provider_code": "truelabs"}Using the SDK: @aggregator-gg/sdk@1.0.0 requires Node.js 24 or newer.
const session = await safeSdkRequest(() => aggregator.sessions.create({ game_id: "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d", player_id: "player_42", balance: 10000, currency: "EUR", country: "DE", lang: "de", return_url: "https://your-casino.com/lobby",}));
// Validate the response against the API contract before redirecting the player// to its game_url. Do not log the single-use URL.If you need stable retries across your own queue or worker boundary, pass the same key explicitly:
const session = await safeSdkRequest(() => aggregator.sessions.create( { game_id: "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d", player_id: "player_42", balance: 10000, currency: "EUR", country: "DE", lang: "de", return_url: "https://your-casino.com/lobby", }, { idempotencyKey: "launch-player-42-20260402-001" },));Important details:
game_idis The Aggregator catalog UUID — theidreturned byGET /v1/games. It is not the provider’s own game code (provider_game_id, for reference only). Always send The Aggregatorid.balanceis in the currency’s minor units — the ISO-4217 minor unit, determined by the currency (not configurable per operator). Every currency The Aggregator currently supports is 2-decimal, so the minor unit is 1/100:10000=100.00 EUR. (A 0-decimal currency such as JPY would use whole units, but no non-2-decimal currency is enabled today.)countrydetermines jurisdiction rules. Games blocked in the player’s country return a403.return_urlis where the player lands when they close the game. If omitted, the Aggregator’s game-complete page is used.game_urlis single-use. Create a new session each time the player needs to launch the game.
Embedding a game in an iframe
Section titled “Embedding a game in an iframe”You may redirect the browser to game_url or embed it in an iframe. If you
rely on a provider’s URL-navigation fallback inside a sandboxed iframe,
include allow-top-navigation-by-user-activation alongside the permissions
your provider needs. Every sandboxed ancestor iframe must also permit this
user-activated top-level navigation; a nested iframe cannot relax its ancestor’s
restrictions:
<iframe src="https://provider.example/launch/..." title="Game" sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-top-navigation-by-user-activation"></iframe>TRUE LABS’ current URL-based in-game Top-up fallback uses a direct player click
to navigate the top-level casino page. Without
allow-top-navigation-by-user-activation, the browser blocks that navigation
with a SecurityError. The session contract carries a separate optional
deposit_url; when you omit it, the Aggregator falls back to sending your
return_url as the deposit destination (or the Aggregator game-complete page
if both URLs are omitted). Either way the in-game Top-up CTA
navigates to that exact URL — it does not invoke an external Deposit button or
cashier modal. Send a trusted deposit_url on your casino domain that opens the
cashier flow. If you leave it unset and your return_url route automatically
restores the current game, Top-up will appear to refresh or relaunch the game
instead.
This iframe permission is a compatibility requirement for the URL fallback, not a no-reload cashier integration. A URL with a different origin, path, or query performs a full top-level document navigation and may recreate both the casino page and game iframe.
To keep the casino page in place, use a same-document host hook. Set
deposit_url to your current casino URL with only a dedicated fragment added —
for example https://casino.example/game/abc#deposit. Fragment-only navigation
stays in the current document; your front-end
can handle the exact fragment on initial load and hashchange, open its existing
cashier UI, and remove the fragment with history.replaceState so repeated
clicks work. The origin, path, and query
must otherwise match the current top-level URL exactly.
After changing deposit_url, create a new session with a fresh
Idempotency-Key and launch its new game_url. Reconcile any ambiguous earlier
launch before starting this new logical session. /v1/sessions caches the
response for each operator and key for 24 hours. Reusing the previous key during
that window replays the original session without evaluating the changed request
body, so TRUE LABS would still receive the old deposit destination.
An agreed provider-to-host event bridge is another no-reload option. For that design, validate the exact message schema, source iframe, and allowed origin before opening the cashier.
Do not replace this narrow permission with
allow-top-navigation, which permits top-level navigation without a user
click.
You can also launch demo sessions (no player credentials required):
const demo = await safeSdkRequest(() => aggregator.sessions.createDemo({ game_id: "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d",}));// demo.game_url opens the game in free-play modeStep 4: Handle Wallet Callbacks
Section titled “Step 4: Handle Wallet Callbacks”When a player places a bet or receives a win, The Aggregator sends an HTTPS callback to the URL configured for your organization. Where your deployment exposes Organization → Callback configuration, use those settings; confirm the available controls before testing. Keep the signing secret separate from the API key.
Callback format
Section titled “Callback format”The Aggregator sends a POST request with a JSON body:
{ "action": "BET-WIN", "transaction_type": "bet", "transaction_id": "tx_bet_001", "amount": 500, "currency": "EUR", "player_id": "player_42", "provider_code": "truelabs", "game": "book-of-sun", "game_id": "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d", "round_id": "round_abc", "finished": false, "session_id": "8c8e8c8e-8c8e-4c8e-8c8e-8c8e8c8e8c8e"}Key fields (full reference in the wallet callbacks guide):
- Branch on
transaction_type(bet/win/refund) — notaction, which is a provider-specific label ("BET-WIN","BET", …). amountis an integer in minor units; supported zero-win settlements may haveamount: 0(e.g.500= 5 EUR) — the same unit as the responsebalancebelow. The minor unit is determined by the ISO-4217 currency: 2-decimal currencies (EUR/USD) use 1/100 (500= €5.00), 0-decimal currencies (JPY/KRW) are 1:1 (278= ¥278), and 3-decimal currencies (KWD/BHD/OMR) use 1/1000.game_idis The Aggregator catalog UUID;gameis the provider’s own slug.finishedistrueon the final callback of a round.
Transaction types (the transaction_type field):
transaction_type |
Description | Your action |
|---|---|---|
bet |
Player placed a bet | Debit paid bets only; on is_free: true, do not debit the player’s real-money balance |
win |
Player won | Credit amount to the player’s balance |
refund |
A previous bet was reversed | Reverse the original recorded wallet debit once; reconcile a missing or ambiguous original outcome |
Verify the signature
Section titled “Verify the signature”Verify the exact raw request bytes with the reviewed signature helpers. They reject missing or malformed signatures and missing or empty protected environment secrets before comparison. Keep the callback secret separate from the API key. Node exposes the X-SIGNATURE header as req.headers["x-signature"].
Verify before parsing or changing money. Keep raw bodies, headers and secrets out of errors and logs; use fixed-code diagnostics.
Respond correctly
Section titled “Respond correctly”Your endpoint must return HTTP 200 with a JSON body containing balance and currency (both required — a balance-only body is rejected), and echo the player_id:
Success (200):
{ "balance": 9500, "currency": "EUR", "player_id": "player_42"}balance is the player’s new balance in minor units (cents — e.g. 9500 = 95.00 EUR). This is the same denomination as the request amount (an integer in minor units, 500 = €5.00), so you can apply amount to balance directly with no unit conversion. currency must match the request.
Error responses:
| Status | When to use |
|---|---|
200 |
Transaction processed successfully. Return the new balance. |
402 |
Insufficient funds. Only valid for bet transactions. The bet is not placed. |
500 |
Internal error. Retry eligibility follows the deployed delivery policy. |
A duplicate of the full scoped transaction identity is not a distinct status — it is an idempotent retry. Replay your original response (same HTTP status and balance you returned the first time — 200 for a settled bet), never a fresh 409. See Handle idempotency.
Handle idempotency
Section titled “Handle idempotency”Use the full integration/organization, provider_code and transaction_id as the wallet transaction identity. Provider IDs are opaque and are not globally unique.
- Validate the signed callback against the transaction and provider contract. On a free bet with
is_free: true, do not debit the player’s real-money balance. - For a duplicate, replay the stored original status and body without another wallet movement. Never rebuild that response from values in a later request.
- Atomically commit the wallet change and its stored original status and body before returning success. A separate balance update followed by a separate result save is not sufficient.
- Reverse only the original recorded wallet debit for a refund, once. Reconcile a missing or ambiguous original outcome; a free bet must not create an extra real-money refund credit.
Implement these guarantees in your persistent ledger using the callback integration requirements; a short in-memory endpoint does not provide them. A timeout does not prove the wallet change failed: reconcile before recovery.
For full callback documentation, see the wallet callbacks guide.
Step 5: Test Your Integration
Section titled “Step 5: Test Your Integration”Run real-session tests only after deployment access, providers, callbacks and funding or agreed credits are enabled. Use authorized test players and reconcile every movement. See Testing your integration for the recommended sequence.
Testing checklist
Section titled “Testing checklist”- Game catalog – List games and verify filtering works
- Session creation – Create a session and confirm you receive a valid
game_url - Demo session – Create a demo session and verify free-play mode works (no wallet movement)
- Bet callback – Verify paid bets debit once and free bets do not debit real money
- Win callback – Verify your endpoint credits the correct amount
- Refund callback – Verify your endpoint reverses a bet correctly
- Insufficient funds – Send a bet larger than the player’s balance and confirm you return
402 - Idempotency – Replay the same integration/organization,
provider_codeandtransaction_idand confirm the stored original status and body; the same ID from a different provider must remain distinct - Signature verification – Send a request with a tampered signature and confirm your endpoint rejects it with
401 - Timeout handling – Confirm your callback endpoint responds within 5 seconds under load
- Blocked country – Attempt to create a session for a blocked country and confirm you receive
403
Viewing transactions
Section titled “Viewing transactions”You can inspect all your transactions through the API:
const { transactions } = await safeSdkRequest(() => aggregator.transactions.list({ page: 1, per_page: 100,}));Or view them in the operator cabinet under Transactions.
Step 6: Go Live
Section titled “Step 6: Go Live”After validating the full callback path, confirm the applicable launch requirements and approvals before opening customer traffic. Technical checks and any welcome credits do not themselves authorize launch.
Production checklist
Section titled “Production checklist”API and authentication:
- Your issued API key and separate callback secret are stored in a secrets manager, not in code
- Where supported, CI/integration runs use a separate credential with permissions appropriate to those runs
- Your production callback URL is configured in the operator cabinet
Callback endpoint:
- Endpoint is publicly accessible over HTTPS (TLS 1.2+)
- Signature verification is enabled and tested
- Idempotency handling is implemented and tested
- Endpoint responds within 5 seconds under expected load
- Error responses follow the documented status codes (200, 402, 500); duplicates replay the original response
Reliability:
- Callback endpoint has monitoring and alerting configured
- You have a process for investigating and resolving failed callbacks
- Your database transactions for balance updates are atomic (no partial updates)
- Your protected ledger retains validated transaction records for reconciliation; operational diagnostics use fixed codes and locally generated correlation IDs, without raw request values or secrets
Compliance:
- You respect
blocked_countriesand do not launch games for restricted jurisdictions - Player balances are displayed in the correct currency and denomination
- You have completed KYB verification and your operator account is approved for production
Final verification:
- Run one real session with a small balance to confirm the full flow works in production
- Verify callback delivery by checking the transaction in both your system and the operator cabinet
Further Reading
Section titled “Further Reading”- Full API Reference – Complete endpoint documentation with request/response schemas
- Wallet Callback Guide – Detailed callback specification, retry behavior, and edge cases
- TypeScript SDK 1.0.0 — install
@aggregator-gg/sdk@1.0.0from npm; requires Node.js 24 or newer. SDK 1.1.0 is not required for these examples.