npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aggregator-gg/sdk

v1.0.0

Published

TypeScript SDK for The Aggregator machine API

Readme

@aggregator-gg/sdk

TypeScript SDK for integrating with The Aggregator iGaming API -- browse games, launch sessions, and query transactions with a single client.

Package availability is not operational approval. Installing this SDK does not authorize a Core consumer switch, production use, live-money readiness, or any change to the Aggregator runtime. Use sk_test_* credentials for integration work until those separate gates are approved.

Why This Exists

Integrating a game aggregator API means managing authentication, pagination, error handling, and multiple resource endpoints. This SDK wraps all of that into a typed, promise-based client so you can ship your integration in hours instead of days.

Quick Start

Install the public package from npm. Repository contributors validating an unpublished candidate should instead use this repository's locked workspace and npm ci; repository source or a green build does not authorize publication.

Run the SDK only in a trusted server-side Node.js process. Never bundle an Aggregator API key into browser or mobile code. Your backend may return the resulting game_url to an authenticated frontend, which can then navigate the player without receiving the API key.

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, // use an sk_test_* key for integration/sandbox work
});

// 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(game.name); // "Book of Sun"

// Launch a no-money integration demo
const session = await aggregator.sessions.createDemo({
  game_id: game.id,
});

console.log(`Created demo session ${session.session_id}`);
// Return { game_url: session.game_url } from your authenticated backend route.

Installation

Prerequisites: Node.js 24+

npm install @aggregator-gg/sdk
# or
yarn add @aggregator-gg/sdk
# or
pnpm add @aggregator-gg/sdk

The package ships ESM and CommonJS builds. TypeScript type definitions are included -- no @types package needed.

Configuration

Create a client by passing an AggregatorConfig object to the constructor:

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,
  baseUrl: "https://api.aggregator.gg/v1", // optional, this is the default
  fetch: customFetch,                      // optional, for custom environments
  timeoutMs: 30_000,                       // optional, per attempt
  retry: { maxRetries: 2 },                // optional; false disables retries
});

For a non-production environment, pass the HTTPS base URL supplied by the Aggregator operator. This public package does not publish private staging hostnames.

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | (required) | Use an sk_test_* key for integration/sandbox work. Use sk_live_* only after readiness approval. | | baseUrl | string | https://api.aggregator.gg/v1 | Override the API base URL. Arbitrary HTTPS origins are supported for private deployments. Credentials, query strings, and fragments are rejected; plain HTTP is limited to exact loopback hosts. | | fetch | typeof fetch | globalThis.fetch | Custom fetch implementation. Useful for testing or environments without a global fetch. | | timeoutMs | number | 30000 | Per-attempt timeout, from 1 ms through 10 minutes. Long-running clients such as readiness orchestration must set an explicit larger budget and still pass an outer AbortSignal. | | retry | RetryConfig \| false | 2 retries | Bounded retry policy. Only safe GETs and idempotency-keyed environment-bound session creation are retried. | | userAgent | string | unset | Optional product identifier. Control characters are rejected. |

Every public operation accepts a caller AbortSignal. Automatic retries honor Retry-After (delta seconds or an HTTP date), clamp the delay to the configured maximum, and stop immediately when the caller aborts. Demo-session POSTs are never replayed. A route-allowlisted request() compatibility surface exists for the SDK-owned MCP package, but it accepts no caller headers, rejects unknown method/path pairs before fetch, and never retries POSTs. Environment-bound session creation must use sessions.create() so idempotency cannot be bypassed. The readiness compatibility POST accepts only the complete { provider_code, mode: "direct_wallet", currency, amount } body; unknown, missing, or malformed fields are rejected before fetch.

Environments

The key tiers have distinct safety boundaries:

  • Product exploration uses the separate keyless demo front door.
  • Machine integration and sandbox calls use sk_test_*; these keys cannot enter the live-money path.
  • sk_live_* keys are issued only after readiness and are required for live money-bearing session operations.
  • The same sessions.create() method selects the sandbox or production environment from the API key; there is no caller-supplied environment switch.

The current Core OpenAPI still describes POST /sessions as real-money only, while the current Core implementation carries a test/live environment on the authenticated identity. This package preserves that implementation-compatible shape, but it is not deployment proof. Do not rely on sk_test_* session semantics until the target runtime has been verified separately, and never use an sk_live_* key for exploratory validation.

const apiKey = process.env.AGGREGATOR_API_KEY;
if (!apiKey) {
  throw new Error("AGGREGATOR_API_KEY is required");
}
const aggregator = new Aggregator({ apiKey });

Usage

The SDK exposes three sub-clients: games, sessions, and transactions.

Games

List games

Retrieve a paginated list of games with optional filters.

const { games, total, page, per_page } = await aggregator.games.list({
  sub_operator_ref: "brand-01", // platform accounts only
  provider: "truelabs",
  type: "slots",
  volatility: "high",
  rtp_min: 95,
  rtp_max: 97,
  features: "free_spins",
  search: "book",
  sort: "name",
  page: 1,
  per_page: 25,
  currency: "EUR",
});

Filter parameters:

| Parameter | Type | Description | |-----------|------|-------------| | sub_operator_ref | string | Platform accounts only: brand storefront selector. Omit for single-casino/default-brand use; never send an empty value. | | provider | string | Filter by provider code (e.g. "truelabs", "bgaming") | | provider_game_id | string | Filter by the provider's own game identifier | | type | string | Filter by game type (e.g. "slots", "table", "crash") | | volatility | string | Filter by volatility level (e.g. "low", "medium", "high") | | rtp_min | number | Minimum RTP percentage (inclusive) | | rtp_max | number | Maximum RTP percentage (inclusive) | | features | string | Filter by game features (e.g. "free_spins", "bonus_buy") | | search | string | Full-text search across game names and brands | | sort | string | Sort field (e.g. "name", "rtp", "release_date") | | page | number | Page number (1-based) | | per_page | number | Results per page (1–200) | | currency | string | ISO-4217 currency filter |

Get a single game

const game = await aggregator.games.get("d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d");

console.log(game.name);              // "Book of Sun"
console.log(game.provider_code);     // "truelabs"
console.log(game.rtp);               // 96.5
console.log(game.has_demo);          // true
console.log(game.blocked_countries); // ["US", "GB"]

Game object properties:

| Property | Type | Description | |----------|------|-------------| | id | string | Unique game identifier | | provider_game_id | string | Provider's own game ID | | provider_code | string | Provider code (e.g. "truelabs") | | name | string | Display name | | brand | string? | Game brand or studio | | category | string | Game category | | game_type | string? | Game type (slots, table, crash, etc.) | | rtp | number? | Return to player percentage | | volatility | "low" \| "medium" \| "high"? | Volatility level | | has_mobile | boolean? | Mobile-compatible | | has_desktop | boolean? | Desktop-compatible | | has_demo | boolean | Demo mode available | | thumbnail_url | string? | Game thumbnail image URL | | free_rounds_support | boolean? | Whether free-round grants are supported | | blocked_countries | string[]? | ISO country codes where the game is unavailable | | certified_markets | CertifiedMarkets \| null? | Informational provider certification metadata; not a launch gate | | features | string[]? | Game features (free spins, bonus buy, etc.) | | release_date | string? | ISO date string | | supported_currencies | string[]? | Effective declared launch currencies | | min_bet, max_bet, default_bet | number \| null? | Provider-declared limits in bet_limits_currency | | max_win_multiplier | number \| null? | Provider-declared maximum win multiple | | bet_steps | GameBetSteps \| null? | Discrete stake ladder when available |

Sessions

Create an environment-bound player session

Launch a game for a player. The response includes a game_url you redirect the player to. The API key selects the environment:

  • sk_test_* creates a sandbox session with provider test credentials; it does not bill or settle live money.
  • sk_live_* creates a production real-money session and is issued only after readiness approval.

Live-money warning: A call made with sk_live_* enters the production money path. Keep integration and exploratory calls on sk_test_*.

The SDK automatically sends an Idempotency-Key header for this call. Pass { idempotencyKey } as the second argument if you want to control retries explicitly from your side.

const session = await aggregator.sessions.create({
  game_id: "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d",
  player_id: "player_42",
  balance: 10000,        // 100.00 EUR in cents
  currency: "EUR",
  country: "DE",
  lang: "de",            // optional, game UI language
  return_url: "https://your-casino.com/lobby", // optional, where the player returns after closing the game
  sub_operator_ref: "brand-01", // platform accounts only
});

console.log(session.session_id);           // "8c8e8c8e-8c8e-4c8e-8c8e-8c8e8c8e8c8e"
console.log(session.game_url);             // "https://..."
console.log(session.provider_session_uid); // provider reference when returned
console.log(session.provider_code);        // optional on create responses

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | game_id | string | Yes | The Aggregator catalog UUID (id from GET /v1/games), not the provider's provider_game_id | | player_id | string | Yes | Your unique player identifier | | balance | number | Yes | Player balance in minor currency units (cents); sandbox balance with sk_test_*, live balance with sk_live_* | | currency | string | Yes | 3–8 ASCII letters; outer spaces/tabs and either case are accepted, then sent uppercase | | country | string | Yes | Two ASCII letters; outer spaces/tabs and either case are accepted, then sent uppercase | | lang | string | No | Two ASCII letters; outer spaces/tabs and either case are accepted, then sent lowercase | | return_url | string | No | URL the player is redirected to after closing the game | | sub_operator_ref | string | No | Platform brand selector. Use the same non-empty ref for catalog list, launch, and lookup. |

Punctuation, wrong lengths, inner whitespace, and control characters in the three code fields are rejected before any network call. Normalization returns a fresh request body and does not mutate the caller's object.

const session = await aggregator.sessions.create(
  {
    game_id: "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d",
    player_id: "player_42",
    balance: 10000,
    currency: "EUR",
    country: "DE",
  },
  { idempotencyKey: "launch-player-42-round-001" },
);

Create a demo session

Launch a game in free-play mode. No player credentials or balance required.

const demo = await aggregator.sessions.createDemo({
  game_id: "d4f7a2b1-3c8e-4f5a-9b6d-1e2f3a4b5c6d",
});

console.log(demo.session_id); // "8c8e8c8e-8c8e-4c8e-8c8e-8c8e8c8e8c8e"
console.log(demo.game_url);   // "https://..."

Get session details

Retrieve the current state of a session.

const session = await aggregator.sessions.get(
  "8c8e8c8e-8c8e-4c8e-8c8e-8c8e8c8e8c8e",
  { sub_operator_ref: "brand-01" }, // platform accounts only
);

console.log(session.status);     // "active" | "completed" | "expired" | "error"
console.log(session.created_at); // ISO-8601 timestamp

The SDK accepts both the canonical unwrapped session-detail response and the legacy { "session": ... } envelope during Core cutover. An id-only legacy response is normalized so SessionDetail always exposes matching id and session_id; conflicting identifiers fail closed.

Transactions

List transactions

Retrieve a paginated list of transactions.

const { transactions, limit, offset } =
  await aggregator.transactions.list({
    page: 2,
    per_page: 50,
  });

for (const tx of transactions) {
  console.log(tx.id, tx.type, tx.amount, tx.currency);
  // "tx_001" "bet" <Core-provided amount> "EUR"
}

The current API implements limit (1–100) and offset. For convenience, the SDK also accepts page and per_page (1–100) and translates them to those wire parameters; do not mix the two families. The current runtime ignores the documented brand/session/player/type/time filters, so this SDK does not expose or send them. Current responses do not promise total, page, or per_page. The SDK normalizes the current transaction_type response field into type. The deployed handler returns its stored amount without a normalized string alias. The SDK preserves that number | string value and does not guess a major-unit conversion. Do not use this endpoint for exact financial reconciliation until Core publishes and deploys one authoritative amount/unit contract.

Transaction object properties:

| Property | Type | Description | |----------|------|-------------| | id | string | Unique transaction identifier | | session_id | string | Associated session | | type | string | Transaction type ("bet", "win", "refund") | | amount | number \| string | Current database-shaped value; no normalized unit/string alias is guaranteed | | currency | string | ISO 4217 currency code | | provider_transaction_id | string? | Provider-side transaction identifier when available | | provider_round_id | string? | Canonical provider round identifier | | status | string? | Processing state: pending, forwarded, completed, failed, or duplicate | | environment | "test" \| "live"? | Ledger environment | | operator_status | number \| null? | Operator callback HTTP status | | operator_response | object \| null? | Authenticated operator wallet response body | | processing_time_ms | number \| null? | Callback processing latency in milliseconds | | error_message | string \| null? | Stored callback error when processing failed | | created_at | string | ISO 8601 timestamp |

Error Handling

All API errors throw an AggregatorError with structured details.

import { Aggregator, AggregatorError } from "@aggregator-gg/sdk";

try {
  await aggregator.games.list({
    per_page: 25,
  }, {
    signal: AbortSignal.timeout(5_000),
  });
  await aggregator.sessions.create({
    game_id: "00000000-0000-4000-8000-000000000000",
    player_id: "player_42",
    balance: 10000,
    currency: "EUR",
    country: "DE",
  });
} catch (err) {
  if (err instanceof AggregatorError) {
    console.error(err.status);  // 404
    console.error(err.message); // "Aggregator API request failed with status 404"
    console.error(err.code);    // "GAME_NOT_FOUND" (or null if not provided)
    console.error(err.body);    // full response body for debugging
  }
}

AggregatorError properties:

| Property | Type | Description | |----------|------|-------------| | message | string | Generic status-based description that does not relay untrusted upstream detail | | status | number | HTTP status code | | code | string \| null | Machine-readable error code from the API, if available | | body | unknown | Full response body for debugging |

Common error codes:

| Status | Meaning | What to do | |--------|---------|------------| | 400 | Bad request -- missing or invalid parameters | Check your request body against the parameter tables above | | 401 | Invalid API key | Verify your apiKey is correct and has not been revoked | | 403 | Forbidden -- key lacks permission for this resource | Ensure you are using a key with the right scope | | 404 | Resource not found | Check the ID you passed (game, session, etc.) | | 429 | Rate limit exceeded | Back off and retry after the Retry-After header interval |

TypeScript Support

The SDK is written in TypeScript and ships type definitions for every interface and method. All types are 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";

Requirements

  • Node.js 24+ (uses globalThis.fetch by default)

Security

Report vulnerabilities privately to the Aggregator Security Team. Do not disclose vulnerability details or credentials in a public issue. The team aims to acknowledge reports within 3 business days.

License

MIT