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:
- 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. - The pool is finite. When every ticket has been sold, the raffle closes permanently and further spin requests return
KS-4218(HTTP 410).
The Spin Request
The request is identical to a slot spin — same endpoint, same fields:
POST /api/partner/v1/spin| Field | Type | Required | Description |
|---|---|---|---|
gameId | number | Yes | Game configuration ID from registration |
playerId | string | Yes | Your external player identifier |
wagerUsd | number | Yes | The ticket price in USD |
requestId | string | No | Idempotency 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
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:
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
{
"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
| Field | Description |
|---|---|
type | Always "raffle" for raffle games. Narrow on this field to pick your renderer — slot games send type: "slot". |
prizeName | Human-readable prize name to display, e.g. "$500 Gift Card". No-win outcomes carry "No Win". |
prizeTier | Prize tier number (0 = no win). Duplicates outcome.prizeTier for renderer convenience. |
celebrationTier | Celebration intensity: none, small, medium, large, or jackpot. |
A no-win ticket looks like this:
{
"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. Once the last ticket is drawn, the raffle is permanently closed:
{
"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
BLOCK_UNAVAILABLE(503, temporary queue exhaustion — retryable), a 410 will never succeed later. - Render "raffle closed" in your UI and stop sending spin requests for this
gameId. - To keep selling, launch a new raffle — a new game registration with a fresh prize pool.
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 Code | HTTP Status | Meaning |
|---|---|---|
KS-4218 | 410 | Raffle closed — all tickets sold. Terminal; do not retry. |
KS-4103 | 400 | Wager does not match the ticket price. |
KS-4201 | 404 | Game not found. Check the gameId. |
KS-4291 | 429 | Spin rate limit exceeded. Back off and retry. |
Next Steps
- Review the full spin request and response
- Learn about daily settlement reconciliation
- Set up webhooks for real-time event notifications
