Free spins
Issue, list, and cancel free-spin grants for your own players without going through the platform admin team — see the Free spins API reference for the exact request/response shapes this guide walks through.
Ad hoc vs campaign
You can issue a grant two ways:
- Ad hoc — specify
gameId,spins,betAmountMinor, andcurrencydirectly on the request. - From a campaign — pass
campaignIdinstead, and those four fields are read from the campaign template and any values you also supply are ignored. Campaigns are reusable presets your integration contact sets up for you; reference one by ID if you have it.
const path = '/v1/operator/free-spins/grants'
const body = JSON.stringify({
playerRef,
gameId,
spins: 10,
betAmountMinor: 100, // or omit/0 to use your wallet's default stake
currency: 'USD',
idempotencyKey: crypto.randomUUID(), // see Idempotency below
})
const headers = signRequest('POST', path, operatorSecret, body, operatorId)
const res = await fetch(`${platformUrl}${path}`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body,
})
const grant = await res.json()
// grant.status: 'pending' | 'active' | 'cancelled' | 'failed'
// grant.externalRef — the provider's own identifier for this batch, once grantedThis call is synchronous
Unlike a wallet transaction, issuing a grant is a live, synchronous call all the way to the provider's game server — it's not queued or fire-and-forget. You'll know immediately whether it succeeded: a failed grant in the response means the provider's own grant call failed (see lastError), and idempotencyKey is permanently consumed by that attempt — retry with a fresh key, not the same one.
Idempotency
idempotencyKey is required and scoped to your operator tenant. A repeat call with the same key returns the original grant's current state instead of issuing a second batch — safe to retry a network failure with the same key, but once a grant reaches failed, that key is spent; generate a new one for another attempt.
Checking status and cancelling
// GET /v1/operator/free-spins/grants/{id} — current state of one grant
// GET /v1/operator/free-spins/grants?playerRef=<ref> — every grant for a player
// POST /v1/operator/free-spins/grants/{id}/cancel — void remaining, unused spinsOnly an active grant can be cancelled. Cancel, like issuance, calls through to the provider synchronously — if that call fails, your grant stays as it was (not marked cancelled), since the spins may still be usable on the provider's side. Retry the cancel rather than assuming it took effect.
Winnings still settle through the wallet callback
A free spin's payout is not part of this API — when the player wins from a free spin, the provider submits it as a normal WIN through POST /v1/wallet/transaction, handled by your wallet callback exactly like any other win. This API only ever moves "how many spins are granted / remaining," never money.