Appearance
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-sdkV2 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:
| # | Name | Range | Who Picks | Prize |
|---|---|---|---|---|
| 1 | Jackpot | 1 to odds range | Player or Quick Pick | JACKPOT |
| 2 | Bonus 1 | 1 to 1,000,000 | Player or Quick Pick | $25,000 |
| 3 | Bonus 2 | 1 to 100,000 | Player or Quick Pick | $1,000 |
| 4 | Bonus 3 | 1 to 10,000 | Player or Quick Pick | $100 |
| 5 | Bonus 4 | 1 to 1,000 | Player or Quick Pick | $10 |
| 6 | Bonus 5 | 1 to 100 | Player 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
- Authentication — API keys, JWT, webhook signatures
- Webhooks — Event types and receiver setup
- Revenue Model — The 8/15/2/5/70 split