Skip to content

Open app

Node.js SDK

@aggregator-gg/sdk is the official TypeScript client for the Aggregator.gg machine API: games, sessions, and transactions behind one typed, promise-based interface. Published on npm at version 1.1.0 under the MIT license. It wraps the same HTTP contract documented on Callbacks and Code samples; anything the SDK does, plain fetch can do too.

The SDK runs in a trusted server-side Node.js process only. Never bundle an Aggregator API key into browser or mobile code: your backend returns the launched game_url to an authenticated frontend, and the key never leaves your server.

Prerequisite: Node.js 24+ (the SDK uses global fetch by default).

Terminal window
npm install --save-exact @aggregator-gg/sdk@1.1.0
# or
yarn add --exact @aggregator-gg/sdk@1.1.0
# or
pnpm add --save-exact @aggregator-gg/sdk@1.1.0

The package ships ESM and CommonJS builds with bundled TypeScript definitions; no @types package needed.

Step check: npm ls @aggregator-gg/sdk --depth=0 shows your installed 1.1.0; npm view @aggregator-gg/sdk@1.1.0 version checks that exact registry version, and node -e "import('@aggregator-gg/sdk').then(m => console.log(typeof m.Aggregator))" prints function.

import { Aggregator } from "@aggregator-gg/sdk";
const apiKey = process.env.AGGREGATOR_API_KEY;
if (!apiKey) {
throw new Error("AGGREGATOR_API_KEY is required");
}
const aggregator = new Aggregator({ apiKey });
// List available games
const { games } = await aggregator.games.list({ per_page: 10 });
const game = games[0];
if (!game) {
throw new Error("No games are available");
}
console.log("Catalog read succeeded");
// Launch a no-money integration demo
const session = await aggregator.sessions.createDemo({ game_id: game.id });
console.log("Demo session created");
// Return { game_url: session.game_url } from your authenticated backend route.

New operator keys use agg_ with a stored live environment; no new test keys are issued. Existing legacy compatibility is described in API keys. The client sends the complete key as Authorization: Bearer on every call. A key does not supply a test budget or authorize money-bearing operations. The operator runs the demo above; it checks game presentation, not wallet settlement (Environments).

const aggregator = new Aggregator({
apiKey, // required
baseUrl: "https://api.aggregator.gg/v1", // optional, this is the default
timeoutMs: 30_000, // optional, per attempt
retry: { maxRetries: 2 }, // optional; false disables retries
});
Option Type Default Description
apiKey string required Your agg_ key.
baseUrl string https://api.aggregator.gg/v1 Override for private deployments. HTTPS origins only; credentials, query strings, and fragments are rejected, and plain HTTP is limited to exact loopback hosts.
fetch typeof fetch globalThis.fetch Custom fetch implementation for tests or unusual runtimes.
timeoutMs number 30000 Per-attempt timeout, 1 ms through 10 minutes.
retry RetryConfig or false 2 retries Bounded retry policy; see the safety rules below.
userAgent string unset Optional product identifier; control characters rejected.

Retry safety is deliberate and narrow:

  • Only safe GETs and idempotency-keyed session creation are retried. Demo-session POSTs are never replayed.
  • Automatic retries honour Retry-After (delta seconds or an HTTP date), clamp the delay to the configured maximum, and stop when the caller aborts.
  • Every public operation accepts an AbortSignal, so your own deadlines always win.

Step check: construct the client with retry: false, use an injected synthetic failing fetch, and confirm one attempt fails; reconstruct with defaults and confirm a GET retries while a demo-session create does not.

The client exposes three sub-clients: games, sessions, and transactions. Platforms create their first brand separately, pass sub_operator_ref where supported and confirm their shared wallet; see Platform accounts. The SDK does not add a brand-management or free-rounds client.

Browse the catalog. games.list takes the catalog filters (provider, type, volatility, rtp_min/rtp_max, features, search, sort, page, per_page up to 200, currency, and sub_operator_ref for platform accounts); games.get(id) returns full details including has_demo, blocked_countries, free_rounds_support, and provider-declared bet limits.

Launch real-money sessions. With a new live key, this enters the money path. The operator first confirms access, a controlled test player, available credits and spending limits. sessions.create sends the Idempotency-Key header automatically; persist a unique key for each logical launch and pass { idempotencyKey } as the second argument. The illustrative ID below must be replaced; reuse the same key and body on application retries, not just the SDK’s internal attempts:

const session = await aggregator.sessions.create(
{
game_id: "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d", // catalog UUID from games.list
player_id: "player_42",
balance: 10_000, // integer minor units: 100.00 EUR
currency: "EUR",
country: "DE",
lang: "de", // optional
return_url: "https://your-casino.example/lobby", // optional
},
{ idempotencyKey: "launch-player-42-round-001" },
);
// session.session_id, session.game_url (private: open promptly; provider reuse rules apply)

balance is an integer in minor units, the same denomination the wallet callbacks use. The three code fields are normalised before sending: currency (3-8 ASCII letters) and country (2 letters) go uppercase, lang lowercase, and punctuation, wrong lengths, or inner whitespace are rejected before any network call.

Demo sessions and lookups. sessions.createDemo({ game_id }) launches free-play with no wallet involvement; sessions.get(sessionId) returns state (active, completed, expired, error) and timestamps.

List transactions. transactions.list follows the deployed pagination contract: the wire parameters are limit (1-100) and offset, and the SDK also accepts page/per_page and translates them; do not mix the two families. Responses do not promise total. The SDK normalises the wire field transaction_type into type.

The current Core release normalizes transaction amount to integer minor units at the public boundary; an unavailable/unparseable value can be null. SDK 1.1.0 retains the older number | string type and rejects a row with null as an invalid transaction amount. Treat that as incomplete evidence requiring investigation, not a zero balance or an empty ledger. Validate accepted amounts before arithmetic and do not multiply a current Core amount by 100 again. Reconcile using provider transaction identity, session, currency, status and delivery evidence, not amount alone. The machine transaction feed does not consolidate platform brands or accept sub_operator_ref.

Step check: after a controlled test, compare the callback’s scoped transaction_id with the feed’s provider_transaction_id plus provider/session context. Explain every expected movement and missing/unknown value; a completed status alone is not wallet proof.

API error responses throw a typed AggregatorError. Its upstream code and body are untrusted and may contain secrets. Use a fixed code allowlist and HTTP status; never log the full error or response body:

import { Aggregator, AggregatorError } from "@aggregator-gg/sdk";
try {
await aggregator.games.get("00000000-0000-4000-8000-000000000000");
} catch (err) {
if (err instanceof AggregatorError) {
const code = err.code === "E2001" ? "E2001" : "UNRECOGNIZED";
console.error({ status: err.status, code });
} else {
console.error("Aggregator request failed");
}
}
Property Type Description
message string Generic status-based description that does not relay untrusted upstream detail.
status number HTTP status code.
code string or null Untrusted upstream code; allowlist before logging.
body unknown Untrusted response body; do not log directly.

Branch on status and code; the platform’s code catalogue is the error reference. A 429 should back off per Rate limiting; the SDK’s automatic retry already honours Retry-After for safe operations.

SDK 1.1.0 also exports SecretRedactor from @aggregator-gg/sdk/redaction in ESM and CommonJS. It masks configured secrets and recognized current/legacy API-key candidates in raw text and up to three percent-encoding layers. Bounded JSON-compatible data is handled without evaluating getters or object conversion hooks; unsupported or oversized values produce a fixed marker. Some ambiguous configured secrets are refused at construction. Do not catch that refusal and fall back to raw output.

This is an explicit output-protection utility. Installing it does not automatically sanitize AggregatorError.body, arbitrary logs, every possible encoding, or third-party telemetry, and it does not change authorization. Prefer the fixed diagnostics above. SDK publication also does not update previously installed CLI/MCP npm consumers; those have their own releases.

Every interface is exported from the package root:

import type {
Game,
ListGamesParams,
ListGamesResponse,
CreatedSession,
SessionDetail,
CreateSessionBody,
DemoSession,
CreateDemoSessionBody,
Transaction,
ListTransactionsParams,
ListTransactionsResponse,
AggregatorConfig,
RequestOptions,
RetryConfig,
} from "@aggregator-gg/sdk";

The SDK is written in TypeScript and the definitions ship in the package, so tsc checks your request bodies against the same shapes the client sends.

Step check: in a TypeScript project, passing balance: "100" to sessions.create fails to compile; the money field is a number by type.