Skip to content

Getting Started

This guide walks you through integrating with the UltimaLotto V2 protocol as a licensed operator.

Prerequisites

  • Node.js 20+
  • Operator account with API key (ulk_...)

Installation

bash
npm install @ultimalotto/operator-sdk

V2 Quick Start

typescript
import { UltimaOperator } from "@ultimalotto/operator-sdk";

const operator = new UltimaOperator({
  coordinatorUrl: "https://sandbox.ultimalotto.com",
  apiKey: process.env.ULTIMA_API_KEY!,
  operatorId: process.env.ULTIMA_OPERATOR_ID!,
});

// Start heartbeat
operator.startHeartbeat();

// When round opens — create tickets from player purchases
operator.onRoundOpened(async (event) => {
  const { roundId } = event.data as { roundId: number };
  const { currentOddsRange } = await operator.getOdds();

  // Player picks all 6 numbers
  operator.createTicket(roundId, currentOddsRange, {
    jackpotNumber: 4729156,
    bonus1: 381047,
    bonus2: 62914,
    bonus3: 4207,
    bonus4: 831,
    bonus5: 42,
  });

  // Quick Pick ticket (computer generates all 6)
  operator.createQuickPickTicket(roundId, currentOddsRange);

  // Bulk Quick Pick (for pools)
  operator.createBulkTickets(roundId, currentOddsRange, 100);
});

// When round seals — submit tickets and manifest
operator.onRoundSealed(async (event) => {
  const { roundId } = event.data as { roundId: number };
  const { currentOddsRange } = await operator.getOdds();

  await operator.submitTickets(roundId);
  await operator.submitManifest(roundId, currentOddsRange);
});

// When draw completes — check results
operator.onRoundDrawn(async (event) => {
  const { roundId } = event.data as { roundId: number };
  const results = await operator.checkTickets(roundId);

  if (results.jackpotWinnerCount > 0) {
    console.log("JACKPOT WINNER(S)!", results.jackpotWinners);
  }

  for (const tier of results.bonusTiers) {
    if (tier.winnerCount > 0) {
      console.log(`Bonus ${tier.tier}: ${tier.winnerCount} winners`);
    }
  }
});

Ticket Numbers

Every ticket has 6 numbers — all player-chosen or all Quick Pick:

#NameRangeWho PicksPrize
1Jackpot1 to odds rangePlayer or Quick PickJACKPOT
2Bonus 11 to 1,000,000Player or Quick Pick$25,000
3Bonus 21 to 100,000Player or Quick Pick$1,000
4Bonus 31 to 10,000Player or Quick Pick$100
5Bonus 41 to 1,000Player or Quick Pick$10
6Bonus 51 to 100Player or Quick Pick$5

Players either pick all 6 numbers themselves or use Quick Pick (computer generates all 6 deterministically from ticket ID). No mixing — it's all or nothing.

Affiliate Tracking

typescript
const affiliates = operator.getAffiliateManager();

// Register an affiliate
affiliates.createAffiliate({
  name: "CryptoInfluencer",
  code: "CRYPTO100",
  commissionPercent: 2.5,
});

// Create ticket with affiliate code (player picks all 6)
operator.createTicket(roundId, oddsRange, {
  jackpotNumber: 42,
  bonus1: 500000,
  bonus2: 50000,
  bonus3: 5000,
  bonus4: 500,
  bonus5: 50,
  affiliateCode: "CRYPTO100",
});

// Check affiliate stats
const stats = affiliates.getStats("CRYPTO100");

Pool / Syndicate Management

typescript
const pools = operator.getPoolManager();

// Create a pool
const pool = pools.createPool({
  name: "Office Pool",
  totalShares: 50,
  pricePerShare: 3.00,
  organizerId: "player_123",
});

// Players join
pools.joinPool(pool.id, "player_456", 2);

// Finalize and generate tickets
pools.finalizePool(pool.id, roundId, oddsRange);

// After draw — check results
const drawResult = await operator.getDrawResult(roundId);
const poolResults = pools.checkPoolResults(pool.id, drawResult);

Next Steps