155API

Grant Free Bets

Grant promotional free bets to a player


Grant a promotional free-bet reward to a player. The full grant → bet → win → rollback flow, and exactly what your wallet must return at each step, lives on Freebets & Rewards — this page is the endpoint reference.

Authentication

This endpoint is authenticated by IP whitelist — your server's outbound IP must match the address registered during onboarding. The X-Marbles-Signature header is not required and is ignored if sent.

Endpoint

POST https://api.marbles.xyz/game/free-bets/rewards

Staging: https://api.stagingmarbles.io/game/free-bets/rewards.

Request

{
  "clientPlayerId": "player-123",
  "operatorId": "your-operator-id",
  "clientRewardId": "promo-winter-2025-001",
  "amount": 500000,
  "currency": "USD",
  "quantity": 3,
  "expiresAt": "2025-12-31T23:59:59Z",
  "gameIds": ["game-uuid-1", "game-uuid-2"]
}
FieldTypeRequiredDescription
clientPlayerIdstringYesThe player's unique identifier in your system
operatorIdstringYesYour operator ID
clientRewardIdstringYesYour unique identifier for tracking this reward
amountintegerYesValue per free bet as an integer at the currency's wire precision (USD: 500000 = $5.00) — the same scale as the amount on the /bet callback. A free bet only covers a bet whose wire amount is ≤ this integer, so an under-scaled grant (e.g. cents) makes every free bet unusable. See Currencies
currencystringYesISO 4217 currency code — must match the currency the player bets in
quantityintegerNoNumber of free bets to grant (default: 1, max: 100)
expiresAtstringYes*ISO 8601 expiration datetime. Must be in the future.
startTimestringNoISO 8601 datetime when the free bets become available (for scheduled campaigns)
gameIdsarrayNoRestrict the free bets to specific games (omit for all games)
prepaidIdstringNoGrant from a prepaid template instead of specifying the values inline. When set, currency, expiresAt and the applicable games always come from the template and cannot be overridden per grant; amount and quantity also come from the template when it defines them — your request values apply only where the template leaves them unset

* expiresAt is required unless you grant from a prepaid template (prepaidId), in which case the template's expiry is used.

expiresAt must be in the future

An expiresAt in the past is rejected with 400 Bad RequestexpiresAt must be in the future. Send an explicit UTC offset so there is no ambiguity; a common cause of a rejected grant is re-sending a saved request whose expiresAt has since passed. The response echoes this value back as endTime on the reward object, and as expiresAt on each entry in freeBets[].

Player must exist

The player must have launched at least one game before you can grant them free bets — the endpoint does not create players. Granting to an unknown player returns the 404 below.

Success Response

HTTP/1.1 201 Created

{
  "reward": {
    "type": "Reward",
    "clientRewardId": "promo-winter-2025-001",
    "clientPlayerId": "player-123",
    "operatorId": "your-operator-id",
    "amount": 500000,
    "currency": "USD",
    "quantity": 3,
    "applicableGames": ["game-uuid-1", "game-uuid-2"],
    "meta": {},
    "endTime": "2025-12-31T23:59:59Z",
    "status": "granted",
    "createdAt": "2025-06-15T14:30:00Z"
  },
  "freeBets": [
    {
      "id": "fb-001",
      "amount": 500000,
      "currency": "USD",
      "status": "claimable",
      "createdAt": "2025-06-15T14:30:00Z",
      "expiresAt": "2025-12-31T23:59:59Z",
      "applicableGames": ["game-uuid-1", "game-uuid-2"]
    }
  ]
}

The reward status is "granted" when the free bets are immediately available, or "scheduled" if startTime is in the future (the startTime field only appears on scheduled grants).

Error Responses

All errors use the {"error", "details"} shape (the 409 additionally carries a numeric code):

ErrorHTTP CodeDescription
Validation error400Missing or invalid request fields — details names the field
Bad request400Malformed JSON body
Invalid operator id400Unknown operatorId
Invalid Integration IP400The source IP could not be resolved to your integration
Player not found404details: player with ID <id> not found — the player has never launched a game
REWARD_ALREADY_EXISTS409A reward with this clientRewardId already exists for this player (code: 9003)
Internal server error500Unexpected failure. One specific case to know: details reading free bets are not enabled for operator <operatorId> means the feature is toggled off for your account — free bets are on by default for new operators, so if you see that string, contact us to enable it

Prepaid Templates

If we have configured prepaid free-bet templates for you, list them with:

GET https://api.marbles.xyz/game/free-bets/prepaids?operatorId=your-operator-id
Query parameterRequiredDescription
operatorIdYesYour operator ID — omitting it returns 400 operatorId query parameter is required
gameIdNoOnly return templates applicable to this game

The response is a JSON array of currently-active templates:

[
  {
    "id": "3f2b1c44-...",
    "name": "Welcome pack",
    "description": "5 x $1 free bets",
    "amount": 100000,
    "currency": "USD",
    "quantity": 5,
    "gameIds": [],
    "expiresAt": "2026-12-31T23:59:59Z"
  }
]

The returned id is the value you pass as prepaidId when granting. Templates are configured by 155 — contact us to set one up.

On this page