npm package: @iplaygames/sdk
Description: IPlayGames SDK - High-level wrapper for casino game aggregation
Author: IPlayGames
Latest version: 1.0.8

# IPlayGames JavaScript SDK

High-level JavaScript SDK for the IPlayGames Game Aggregator API.

## Installation

```bash
npm install @iplaygames/sdk
```

## Quick Start

```javascript
import { Client } from '@iplaygames/sdk';

const client = new Client({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.iplaygames.ai',
});

// Get games
const gamesResponse = await client.games().list({ search: 'bonanza' });
if (gamesResponse.success) {
  console.log(`Found ${gamesResponse.games.length} games`);
}

// Start a game session
const sessionResponse = await client.sessions().start({
  gameId: 123,
  playerId: 'player_456',
  currency: 'USD',
  countryCode: 'US',
  ipAddress: '192.168.1.1',
});

if (sessionResponse.success) {
  // Redirect player to game
  window.location.href = sessionResponse.gameUrl;
}
```

## Configuration

```javascript
const client = new Client({
  apiKey: 'your-api-key',            // Required
  baseUrl: 'https://api.iplaygames.ai', // Optional
  webhookSecret: 'your-secret',      // Optional, for webhook verification
});
```

## Response Pattern

All flow methods return response objects with a consistent pattern:

```javascript
const response = await client.games().list({ search: 'bonanza' });

if (response.success) {
  // Use the data
  console.log(response.games);
  console.log(response.meta);
} else {
  // Handle error
  console.error(response.error);
}
```

## Available Flows

### Games

```javascript
// List games with filters
const gamesResponse = await client.games().list({
  search: 'bonanza',
  producerId: 42,
  provider: 'pragmatic',
  type: 'slots',
  perPage: 20,
});

if (gamesResponse.success) {
  for (const game of gamesResponse.games) {
    console.log(`${game.title} by ${game.producer}`);
  }
  console.log(`Total: ${gamesResponse.meta.total}`);
}

// Get single game
const gameResponse = await client.games().get(123);

// Convenience methods
const pragmaticGames = await client.games().byProducer(42); // producerId
const liveGames = await client.games().byCategory('live');
const searchResults = await client.games().search('sweet bonanza');
const allGames = await client.games().all();
```

### Sessions

```javascript
// Start a game session
const sessionResponse = await client.sessions().start({
  gameId: 123,
  playerId: 'player_456',
  currency: 'USD',
  countryCode: 'US',
  ipAddress: req.ip,
  locale: 'en',
  device: 'mobile',
  returnUrl: 'https://casino.com/lobby',
});

if (sessionResponse.success) {
  console.log('Session ID:', sessionResponse.sessionId);
  console.log('Game URL:', sessionResponse.gameUrl);
}

// Get session status
const statusResponse = await client.sessions().status(sessionResponse.sessionId);

// End session
const endResponse = await client.sessions().end(sessionResponse.sessionId);

// Start demo session
const demoResponse = await client.sessions().startDemo(123, {
  currency: 'EUR',
});
```

### Jackpot

```javascript
// Get configuration
const configResponse = await client.jackpot().getConfiguration();

// Get all pools
const poolsResponse = await client.jackpot().getPools();

// Get specific pool
const dailyPoolResponse = await client.jackpot().getPool('daily');

// Get winners
const winnersResponse = await client.jackpot().getWinners('daily');

// Manage games
const addResponse = await client.jackpot().addGames('daily', [1, 2, 3]);
const removeResponse = await client.jackpot().removeGames('daily', [1]);

// Get contributions
const contribResponse = await client.jackpot().getContributions({
  playerId: 'player_456',
});
```

### Promotions

```javascript
// List promotions
const promoListResponse = await client.promotions().list({ status: 'active' });

// Get promotion details
const promoResponse = await client.promotions().get(1);

// Create a promotion
const createResponse = await client.promotions().create({
  name: 'Summer Tournament',
  promotionType: 'tournament',
  cycleType: 'daily',
});

// Get leaderboard
const leaderboardResponse = await client.promotions().getLeaderboard(1);

// Opt-in player
const optInResponse = await client.promotions().optIn(1, 'player_456', 'USD');

// Manage games
const manageResponse = await client.promotions().manageGames(1, [1, 2, 3]);
```

### Jackpot Widgets

```javascript
// 1. Register your domain
const domainResponse = await client.jackpotWidget().registerDomain('casino.example.com', {
  name: 'My Casino',
});

// 2. List registered domains
const domainsResponse = await client.jackpotWidget().listDomains();

// 3. Create anonymous token (view-only)
const anonTokenResponse = await client.jackpotWidget().createAnonymousToken('domain_token_here');

// 4. Create player token (can interact)
const playerTokenResponse = await client.jackpotWidget().createPlayerToken(
  'domain_token_here',
  'player_456',
  'USD'
);

// 5. Get embed code for your frontend
if (playerTokenResponse.success) {
  const embedCode = client.jackpotWidget().getEmbedCode(playerTokenResponse.data.token, {
    theme: 'dark',
    container: 'jackpot-widget',
  });
  document.getElementById('widget-container').innerHTML = embedCode;
}
```

### Promotion Widgets

```javascript
// Register domain
const domainResponse = await client.promotionWidget().registerDomain('casino.example.com');

// Create player token
const tokenResponse = await client.promotionWidget().createPlayerToken(
  'domain_token',
  'player_456',
  'USD'
);

// Get embed code
if (tokenResponse.success) {
  const embedCode = client.promotionWidget().getEmbedCode(tokenResponse.data.token, {
    theme: 'dark',
    container: 'promo-widget',
  });
}
```

### Multi-Session (TikTok-style Game Swiping)

```javascript
// Start multi-session
const multiResponse = await client.multiSession().start({
  playerId: 'player_456',
  currency: 'USD',
  countryCode: 'US',
  ipAddress: req.ip,
  device: 'mobile',
  gameIds: ['123', '456', '789'], // Optional: specific games
});

if (multiResponse.success) {
  console.log('Swipe URL:', multiResponse.swipeUrl);
  console.log('Total Games:', multiResponse.totalGames);

  // Get iframe HTML to embed the swipe UI
  const iframe = client.multiSession().getIframe(multiResponse.swipeUrl, {
    width: '100%',
    height: '100vh',
    id: 'game-swiper',
  });
  document.getElementById('game-container').innerHTML = iframe;
}

// Get status
const statusResponse = await client.multiSession().status(multiResponse.multiSessionId);

// End when player leaves
const endResponse = await client.multiSession().end(multiResponse.multiSessionId);
```

## Handling Webhooks

GameHub sends webhooks for transactions. Your casino must implement a webhook endpoint.

### Webhook Types

| Type | Description |
|------|-------------|
| `authenticate` | Verify player exists and get initial data |
| `balance_check` | Get current player balance |
| `bet` | Player placed a bet |
| `win` | Player won money |
| `rollback` | Undo a transaction |
| `reward` | Award from promotions/tournaments |

### Implementing Your Webhook Handler (Express.js)

```javascript
import express from 'express';
import { Client, WebhookTypes, getAmountInDollars } from '@iplaygames/sdk';

const app = express();
app.use(express.raw({ type: 'application/json' }));

const client = new Client({
  apiKey: process.env.GAMEHUB_API_KEY,
  webhookSecret: process.env.GAMEHUB_WEBHOOK_SECRET,
});

app.post('/webhooks/gamehub', async (req, res) => {
  const payload = req.body.toString();
  const signature = req.headers['x-signature'];

  // Get webhook handler
  const handler = client.webhooks();

  // Verify signature
  if (!handler.verify(payload, signature)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Parse webhook
  const webhook = handler.parse(payload);

  // Handle by type
  switch (webhook.type) {
    case WebhookTypes.AUTHENTICATE:
      return handleAuthenticate(handler, webhook, res);

    case WebhookTypes.BALANCE_CHECK:
      return handleBalanceCheck(handler, webhook, res);

    case WebhookTypes.BET:
      return handleBet(handler, webhook, res);

    case WebhookTypes.WIN:
      return handleWin(handler, webhook, res);

    case WebhookTypes.ROLLBACK:
      return handleRollback(handler, webhook, res);

    case WebhookTypes.REWARD:
      return handleReward(handler, webhook, res);

    default:
      return res.status(400).json({ error: 'Unknown webhook type' });
  }
});

async function handleAuthenticate(handler, webhook, res) {
  const player = await Player.findById(webhook.playerId);

  if (!player) {
    return res.json(handler.playerNotFoundResponse());
  }

  const balance = await player.getBalance(webhook.currency);

  return res.json(handler.successResponse(balance, {
    playerName: player.name,
  }));
}

async function handleBet(handler, webhook, res) {
  const player = await Player.findById(webhook.playerId);
  const balance = await player.getBalance(webhook.currency);
  const betAmount = getAmountInDollars(webhook); // Helper function

  // Check funds
  if (betAmount !== null && balance < betAmount) {
    return res.json(handler.insufficientFundsResponse(balance));
  }

  // Check idempotency
  const existing = await Transaction.findOne({ externalId: webhook.transactionId });
  if (existing) {
    return res.json(handler.alreadyProcessedResponse(balance));
  }

  // Process bet
  if (betAmount !== null) {
    await player.debit(betAmount, webhook.currency);
    await Transaction.create({
      externalId: webhook.transactionId,
      playerId: webhook.playerId,
      type: 'bet',
      amount: betAmount,
      currency: webhook.currency,
    });
  }

  const newBalance = await player.getBalance(webhook.currency);
  return res.json(handler.successResponse(newBalance));
}

// ... implement other handlers similarly
```

## Webhook Payload Fields

### Common Fields (all webhook types)

```javascript
webhook.type;        // 'bet', 'win', 'rollback', 'reward', 'authenticate', 'balance_check'
webhook.playerId;    // Player's ID in your system
webhook.currency;    // 'USD', 'EUR', etc.
webhook.gameId;      // Game ID (nullable)
webhook.gameType;    // 'slot', 'live', 'table', etc.
webhook.timestamp;   // ISO 8601 timestamp
```

### Transaction Fields (bet, win, rollback, reward)

```javascript
webhook.transactionId;           // Unique transaction ID
webhook.amount;                  // Amount in cents
getAmountInDollars(webhook);     // Amount in dollars (helper function)
webhook.sessionId;               // Game session ID
webhook.roundId;                 // Game round ID
```

### Freespin Fields

```javascript
webhook.isFreespin;              // Is this a freespin round?
webhook.freespinId;              // Freespin campaign ID
webhook.freespinTotal;           // Total freespins awarded
webhook.freespinsRemaining;      // Remaining freespins
webhook.freespinRoundNumber;     // Current spin number
webhook.freespinTotalWinnings;   // Cumulative winnings
```

## Helper Functions

```javascript
import {
  WebhookTypes,
  isBet,
  isWin,
  isRollback,
  isReward,
  isAuthenticate,
  isBalanceCheck,
  getAmountInDollars,
} from '@iplaygames/sdk';

// Check webhook type
if (isBet(webhook)) {
  // Handle bet
}

// Get amount in dollars
const dollars = getAmountInDollars(webhook); // Returns null if no amount
```

## Error Handling

```javascript
const response = await client.sessions().start({...});

if (!response.success) {
  console.error('Error:', response.error);
  return;
}

// Use the data
console.log('Session ID:', response.sessionId);
```

## Running Tests

```bash
npm test
```

## License

MIT