Skip to content

Examples

These are the key integration patterns, shown inline. The full runnable versions live in the SDK source repository under packages/sdk/examples/ — they are illustrative and are not shipped in the npm package.

Set your API key and base URL before running any of them:

bash
export KINGSTONE_API_KEY=ks_sandbox_your_key_here
export KINGSTONE_BASE_URL=http://localhost:3001/api

Quick Start

File: examples/quick-start.ts

The simplest possible integration. Initializes the client, lists available games, executes a spin, and reads the outcome.

typescript
import { KingstoneClient, KingstoneApiError } from '@kingstoneapp/sdk';

const client = new KingstoneClient({
  apiKey: process.env.KINGSTONE_API_KEY || 'ks_sandbox_REPLACE_ME',
  sandbox: true,
});

// List available games
const { games } = await client.listGames();
console.log(`Found ${games.length} game(s)`);

// Execute a spin on the first game
const game = games[0];
const result = await client.spin({
  gameId: game.gameConfigId,
  playerId: 'demo-player-1',
  wagerUsd: game.minWagerUsd ?? 0.25,
});

console.log(`Prize tier: ${result.outcome.prizeTier}`);
console.log(`Payout: $${result.outcome.payoutUsd.toFixed(2)}`);
if (result.presentation.type === 'slot') {
  console.log(`Combo: ${result.presentation.comboString}`);
}

Express Integration

File: examples/express-integration.ts

Shows how to build an Express route handler that proxies spin requests to KINGSTONE. Your frontend calls your server, and your server calls KINGSTONE. This keeps the API key on the server side.

Key pattern:

typescript
const kingstone = new KingstoneClient({
  apiKey: process.env.KINGSTONE_API_KEY!,
  sandbox: true,
});

// POST /api/spin — your frontend calls this
async function handleSpin(req, res) {
  const { gameId, wagerUsd } = req.body;
  const playerId = req.user.id; // from your auth middleware

  const result = await kingstone.spin({ gameId, playerId, wagerUsd });

  res.json({
    won: result.outcome.payoutUsd > 0,
    payout: result.outcome.payoutUsd,
    // Forward the presentation as-is — narrow on `presentation.type`
    // ('slot' | 'raffle') in your frontend to render it.
    presentation: result.presentation,
    balance: result.balance.balanceUsd,
  });
}

Webhook Handler

File: examples/webhook-handler.ts

Demonstrates receiving and verifying HMAC-SHA256 signed webhook deliveries. Includes the full verification function and an Express route setup.

Key pattern:

typescript
import { createHmac, timingSafeEqual } from 'node:crypto';

function verifyWebhookSignature(rawBody: string, signature: string, secret: string): boolean {
  const prefix = 'sha256=';
  if (!signature.startsWith(prefix)) return false;

  const received = signature.slice(prefix.length);
  const computed = createHmac('sha256', secret).update(rawBody).digest('hex');

  const a = Buffer.from(received, 'hex');
  const b = Buffer.from(computed, 'hex');
  if (a.length !== b.length || a.length === 0) return false;

  return timingSafeEqual(a, b);
}

Settlement Reconciliation

File: examples/settlement-reconciliation.ts

Shows the daily reconciliation workflow: fetch reports, compare against your records, and acknowledge or dispute.

Key pattern:

typescript
const { reports } = await client.listSettlements({ page: 1, limit: 5 });
const report = reports[0];

// Compare against your database
const yourSpins = await db.spins.count({ date: report.reportDate });

if (yourSpins === report.totalSpins) {
  await client.acknowledgeSettlement(report.reportDate);
} else {
  await client.disputeSettlement(report.reportDate, `Mismatch: ${yourSpins} vs ${report.totalSpins}`);
}

Error Handling

File: examples/error-handling.ts

Covers all error types (authentication, validation, rate limits, server errors) with a retry utility for transient failures.

Key pattern:

typescript
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3, baseDelayMs = 1000): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (error instanceof KingstoneApiError && error.retryable && attempt < maxRetries) {
        const delay = baseDelayMs * Math.pow(2, attempt);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Unreachable');
}

// Use it
const games = await withRetry(() => client.listGames());

Sample PAR Sheet

File: examples/sample-par-sheet.json

A minimal valid 3-reel PAR sheet for sandbox testing. Use this as a starting point for the PAR sheet upload flow. It defines 5 symbols, 7 prize tiers (T0-T6), and 8 combinations with a certified RTP of 92.5%.

Next Steps

KINGSTONE by Predigy Inc.