Skip to main content

Partner freeplays

Use /freeplays/* for new integrations. The older /freebets/create and /freebets/state paths are not accepted by the current canonical partner-signing guard. This documentation page keeps its /freebets URL for existing bookmarks. Confirm the deployed sandbox version through capabilities before issuing grants.

Freeplays create a promotion entitlement and do not debit the regular wallet. Use the same canonical signing as launch and callbacks. All requests contain operatorSlug and a UUID idempotencyKey, mirrored in headers. Every authenticated response is signed and uses { "data": ... } or { "error": ... }.

From grant to settlement​

A grant is the promotion package; each accepted freeplay is a separate use of that package. Disabling the package does not undo an already accepted use.

POST /freeplays/capabilities​

Send this signed body to discover supported settings:

{
"operatorSlug": "your-partner-slug",
"idempotencyKey": "bc47cf38-a1e5-418e-bc66-a6c3c8551628"
}

The response's data includes version: 2, payoutMode: "gross", maxCount: 10000, payoutCaps and games. Capabilities describe the implementation; confirm that these features are enabled for your operator, game and currency.

POST /freeplays/create​

Use a stable UUID for the grant key and a unique external reference for your campaign issuance. Set expiresAt to a future UTC time at issuance; replace the illustrative timestamp below with your campaign's actual expiry.

{
"operatorSlug": "your-partner-slug",
"idempotencyKey": "bc47cf38-a1e5-418e-bc66-a6c3c8551628",
"externalReference": "welcome-campaign-player-001",
"playerId": "fd63c560-f443-49b5-a721-c40c0e06b7be",
"gameSlug": "crash",
"currency": "SOL",
"amount": "0.01",
"totalCount": 10,
"minCoefficient": "2",
"maxWinPerPlay": "0.10",
"maxTotalWin": "0.50",
"expiresAt": "2027-01-01T00:00:00.000Z"
}
FieldContract
externalReferenceRequired nonempty string, at most 256 characters; unique per operator.
playerIdRequired external player reference, at most 256 characters. Use the same player UUID supplied at launch.
amountRequired positive decimal string in asset units; up to 16 integer and 8 fractional digits, within currency precision.
totalCountRequired JSON integer from 1 to 10,000.
expiresAtRequired future ISO timestamp; use canonical UTC.
minCoefficientOptional decimal string, at least 1; supported only for Crash cashout. Omit when unused.
maxCoefficientOptional decimal string, at least 1.
maxWinPerPlayOptional positive gross payout cap per play, within currency precision.
maxTotalWinOptional positive gross payout budget for the whole package.
maxWinDeprecated alias of maxWinPerPlay. If both are provided, they must agree.
gameSettingsOptional game-specific object. Plinko supports allowedRows (integers 8–16) and allowedRisks (low, medium, high), each a nonempty array.

Omit optional settings when unused. Do not send legacy fields such as securityCode. A signed HTTP 200 response contains this data shape:

{
"data": {
"id": "f28599df-47da-4b98-b1ac-cc2a3e7c9425",
"grantId": "bc47cf38-a1e5-418e-bc66-a6c3c8551628",
"operatorId": "8e563380-2a27-41b1-8be5-2cdd7d1ec271",
"playerId": "fd63c560-f443-49b5-a721-c40c0e06b7be",
"externalReference": "welcome-campaign-player-001",
"gameSlug": "crash",
"currency": "SOL",
"amount": "0.01",
"maxCoefficient": null,
"maxWin": "0.1",
"maxWinPerPlay": "0.1",
"maxTotalWin": "0.5",
"allocatedWin": "0",
"remainingWinBudget": "0.5",
"payoutMode": "gross",
"minCoefficient": "2",
"gameSettings": {},
"idempotencyKey": "bc47cf38-a1e5-418e-bc66-a6c3c8551628",
"remainingCount": 10,
"totalCount": 10,
"status": "enabled",
"expiresAt": "2027-01-01T00:00:00.000Z",
"createdAt": "2026-10-16T10:00:00.000Z"
}
}

id is the provider enrollment UUID; grantId is your original grant key. There is no outer version: 2 wrapper on this response. Public statuses are enabled, completed, expired and cancelled in lowercase. Decimal formatting is normalized: compare numeric values exactly, not with floats or string equality ("0.10" and "0.1" represent the same amount).

Verify immutable fields against the original request. Repeating the same key and settings returns the existing grant's current view, including its current remaining count and status. A changed payload under the same key returns signed HTTP 409 CONFLICT. Do not create a replacement key to work around an uncertain outcome.

POST /freeplays/state​

Look up an uncertain creation by the original grant key:

{
"operatorSlug": "your-partner-slug",
"idempotencyKey": "bc47cf38-a1e5-418e-bc66-a6c3c8551628"
}

You may also provide the provider id. A found grant returns its current data plus usages, up to the latest 100 records containing betId, status, originalPayout and payout. This is a recent view, not a complete accounting export. Only a verified signed HTTP 404 with error.code: "NOT_FOUND" proves absence. Timeouts, 5xx, malformed JSON and invalid signatures leave the result unknown.

POST /freeplays/cancel​

Cancel remaining entitlement by provider id, with a UUID request key:

{
"operatorSlug": "your-partner-slug",
"idempotencyKey": "4b263ca0-e973-4b10-bce2-c72ba9025b83",
"id": "f28599df-47da-4b98-b1ac-cc2a3e7c9425"
}

A successful cancellation returns the grant with status cancelled. Repeating it returns the current view. Cancellation disables future use; it is not a wallet refund or cancellation of already accepted bets. Reconcile in-flight usages separately.

Wallet callbacks​

Use the ordinary bet, win and cancel paths:

  • isFree: true identifies a freeplay. Require a valid eligible grant.
  • freeplayGrantId equals the issuance idempotencyKey/grantId.
  • freeplayEnrollmentId equals the provider grant id.
  • Bet amount is the nominal stake, not zero. Consume one play without debiting the regular wallet. Persist the usage and transaction atomically.
  • Win amount is the gross payout, already subject to configured caps. It can include payoutCoefficient. Apply the agreed payout destination exactly once; do not subtract a regular-wallet stake that was never debited.
  • Cancel restores eligibility under the grant rules without a regular-wallet credit. Expired/cancelled packages and in-flight usages need explicit reconciliation.
  • Retain the original player, session, game, currency, grant and bet relationship. Duplicate callbacks must replay the original result.

Implement promotion accounting separately from the regular wallet. Complete the promotion acceptance tests, including caps, expiry, cancellation and duplicate usage.