Skip to content

Raffle Games

Raffle games are single-draw prize reveals: the player buys a ticket, one outcome is drawn, and a prize (or "No Win") is revealed. Like every KINGSTONE game, the outcomes are pre-determined — the full prize pool is generated and sealed before the raffle opens, and each ticket simply consumes the next position in the sealed sequence.

Two things make raffles different from slots:

  1. The presentation is a prize reveal, not reels. The response carries a type: 'raffle' presentation block with a prize name instead of symbols and reel stops.
  2. The pool is finite. When every ticket has been sold, the raffle closes permanently and further spin requests return KS-4218 (HTTP 410).

How a Raffle Is Created

Unlike slot games, you do not create a raffle through the public API. Raffles are sealed by Predigy from the certified prize table you provide (under NDA), using our in-process engine lane. Send us your certified table — the prizes, their per-tier counts, and the ticket price — and we register the game and seal the finite pool for you. The public POST /par-sheets and POST /games endpoints are for slot games; they do not accept a raffle prize table.

Once your raffle is live, you interact with it entirely through the standard spin call below.

The Spin Request

The request is identical to a slot spin — same endpoint, same fields:

POST /api/partner/v1/spin
FieldTypeRequiredDescription
gameIdnumberYesGame configuration ID from registration
playerIdstringYesYour external player identifier
wagerUsdnumberYesThe ticket price in USD
requestIdstringNoIdempotency key (echoed back in response)

Raffles are fixed-wager games: the wager is the ticket price, and the game is configured with minimum = maximum = increment = ticket price. Sending any other wagerUsd value is rejected with KS-4103.

With curl

bash
curl -X POST https://sandbox.kingstone.dev/api/partner/v1/spin \
  -H "X-API-Key: ks_sandbox_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "gameId": 9,
    "playerId": "player-abc-123",
    "wagerUsd": 1.00
  }'

With the SDK

The SDK call is the same spin() you already use for slots:

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

const client = new KingstoneClient({
  apiKey: 'ks_sandbox_your_key_here',
  sandbox: true,
});

const result = await client.spin({
  gameId: 9,
  playerId: 'player-abc-123',
  wagerUsd: 1.00,
});

console.log(`Spin ID: ${result.spinId}`);
console.log(`Prize tier: ${result.outcome.prizeTier}`);
console.log(`Payout: $${result.outcome.payoutUsd.toFixed(2)}`);

The Raffle Response

json
{
  "spinId": "12345",
  "outcome": {
    "prizeTier": 3,
    "payoutUsd": 500,
    "isBonusTrigger": false
  },
  "presentation": {
    "type": "raffle",
    "prizeName": "$500 Gift Card",
    "prizeTier": 3,
    "celebrationTier": "large"
  },
  "balance": {
    "balanceUsd": 42.5
  },
  "communityBonus": null
}

The outcome and balance blocks are identical to slot spins — see the spin response reference. Only the presentation block differs.

The presentation Block

FieldDescription
typeAlways "raffle" for raffle games. Narrow on this field to pick your renderer — slot games send type: "slot".
prizeNameHuman-readable prize name to display, e.g. "$500 Gift Card". No-win outcomes carry "No Win".
prizeTierPrize tier number (0 = no win). Duplicates outcome.prizeTier for renderer convenience.
celebrationTierCelebration intensity: none, small, medium, large, or jackpot.

A no-win ticket looks like this:

json
{
  "type": "raffle",
  "prizeName": "No Win",
  "prizeTier": 0,
  "celebrationTier": "none"
}

Finite Pool Lifecycle

A raffle has a fixed number of tickets — exactly as many as the advertised prize table.

Any pool size is supported. Send your certified prize table exactly as it is: the pool can be any total up to 1,000,000 tickets — 2,438, 10,000, or any other — with any per-tier counts, and there is no need to round it to a "clean" number. KingStone seals a sequence containing precisely your advertised counts, so every prize you advertise is awarded exactly once before the raffle closes.

Once the last ticket is drawn, the raffle is permanently closed:

json
{
  "status": "error",
  "message": "This raffle has closed — all tickets have been sold",
  "errorCode": "KS-4218"
}

KS-4218 (HTTP 410) is a terminal state — the raffle will never reopen:

  • Do not retry. Unlike the slot-side KS-4203 (queue exhaustion, 503, temporary — retryable), a 410 will never succeed later.
  • Render "raffle closed" in your UI and stop sending spin requests for this gameId.
  • To keep selling, Predigy seals a new raffle for you from your certified prize table (a new game with a fresh pool) — see How a Raffle Is Created.

Idempotency

Raffle spins use the same requestId idempotency mechanism as slots — pass a unique requestId per ticket purchase and reuse it only to retry the exact same request. See the spin request reference and error codes KS-4110 / KS-4111 on the error codes page.

Common Errors

Error CodeHTTP StatusMeaning
KS-4218410Raffle closed — all tickets sold. Terminal; do not retry.
KS-4103400Wager does not match the ticket price.
KS-4006403Game not found or not registered to this partner. Check the gameId.
KS-4291429Spin rate limit exceeded. Back off and retry.

Next Steps

KINGSTONE by Predigy Inc.