Integration
Conventions
Requests and responses#
- Server calls are
POSTwithContent-Type: application/jsonand a JSON object body.application/x-www-form-urlencodedbodies are also parsed, but JSON is the contract. Always send one of these two content types: with any other type, such astext/plain, the body is not parsed as JSON and the call fails (typically withUNAUTHORIZED, becausepartneris not found). - The body is limited to 128 KiB (131072 bytes). A larger body is rejected by the web server with HTTP 413 and an HTML page before the API sees it, so there is no JSON error envelope. A malformed JSON body or a missing or unsupported content type (for example
application/xml) is answered with HTTP 400REQUEST_FAILED, notINVALID_REQUEST. - Success answers contain
"status": "ok"plus the result fields. - Errors are
{"status":"error","message":"<CODE>"}with an HTTP status that depends on the code.messageis always an upper-case code; see the error reference. A failure without a public code isREQUEST_FAILED. - Answers are sent with
Cache-Control: no-store: cache the public catalog on your side. - Public GET endpoints return JSON as well (Catalog). A request with a wrong HTTP method or an unknown path is answered with HTTP 404 and a JSON body from the API in a different shape,
{"message":"Route GET:/nope not found","error":"Not Found","statusCode":404}, not with the error envelope.
| HTTP | Typical meaning |
|---|---|
| 200 | Success |
| 400 | Validation error or a business rule (INVALID_REQUEST, PROJECT_BET_LIMIT, …); also most failures without a more specific status, and IDEMPOTENCY_CONFLICT on /playGame.do |
| 401 | UNAUTHORIZED |
| 403 | IP_NOT_ALLOWED (or FORBIDDEN) |
| 404 | Unknown game or record (UNSUPPORTED_GAME, GAME_NOT_FOUND, GRANT_NOT_FOUND, OUTCOME_NOT_FOUND) |
| 409 | /gameActions.do only: IDEMPOTENCY_CONFLICT, DUPLICATE_EXTERNAL_ID, ROUND_NOT_CANCELLABLE, ROUND_BUSY |
| 429 | RATE_LIMITED |
| 503 | DEMO_UNAVAILABLE at launch; DATABASE_UNAVAILABLE on GET /health |
Idempotency#
POST /playGame.do and POST /gameActions.do accept the optional header Idempotency-Key: 1 to 128 printable ASCII characters (no spaces). A malformed key gives HTTP 400 INVALID_IDEMPOTENCY_KEY.
- Scope. A key is scoped to your project and to the endpoint (
/playGame.doand/gameActions.dokeep separate keys). On/gameActions.dothe same key used for two differentmethodvalues is a conflict./playerRtp.dodoes not use the header. - Repeating a request with the same key and the same body returns the first answer without doing the work again. The
api_keyfield is not part of the comparison. - The same key with a different body is answered with
IDEMPOTENCY_CONFLICT: HTTP 400 on/playGame.do, HTTP 409 on/gameActions.do. report_*methods ignore the header (they are read-only).freespins_createandoutcome_scheduleare additionally protected byexternal_id(DUPLICATE_EXTERNAL_ID).- Without the header the call is executed every time (a launch without a key is treated as a new launch).
Rate limits#
The operator endpoints are limited per project and per minute so that one integration cannot starve the others. There are three independent quotas:
| Class | Endpoint | Default quota |
|---|---|---|
| launch | POST /playGame.do | 1200 per minute |
| actions | POST /gameActions.do (free spins, target outcomes, round_cancel) | 600 per minute |
| reports | POST /gameActions.do with report_* | 120 per minute |
- The quota is a token bucket: a full minute of calls may be sent in a burst, tokens return continuously.
POST /playerRtp.doand the public GET endpoints are not limited. - The bucket is chosen by the
partnerfield of the body before the key is checked: calls with a knownpartnerand a wrong key also use up the quota, and429can be answered before401. The counters live in memory of the server process and start again after a restart. - Over the quota the answer is HTTP 429
RATE_LIMITEDand nothing is executed. Counted answers carryX-RateLimit-Limit(for example600/min); allowed ones alsoX-RateLimit-Remaining; a refusal carriesRetry-Afterin whole seconds (at least 1). - The values of an environment are in
rateLimitsofGET /capabilities; higher values can be agreed with your account manager.
HTTP/1.1 429 Too Many Requests
Retry-After: 7
X-RateLimit-Limit: 600/min
content-type: application/json
{"status":"error","message":"RATE_LIMITED"}On 429 wait Retry-After seconds and retry with the same Idempotency-Key. Do not poll reports: page through report_rounds with cursor, and call report_ggr and report_reconciliation once per period. Wallet callbacks from the platform to you are not part of these quotas.
Amounts#
All currencies have two decimals (Currencies). Amounts are exact: parse them with a decimal type, not floating point.
| Context | Format | Example |
|---|---|---|
Wallet callbacks: amount, bet_amount, win_amount | JSON number, written with two decimals by the platform | 1.50, 12.75 |
Wallet answer: balance | JSON number, non-negative, at most 2 decimals, no exponent | 998.50 |
bet, total_win of free spins and freespins_finished; reports; demo_balance | Decimal string, at most 2 decimals | "1.00" |
min_minor, max_minor | String of digits, minor units | "1250" |
At most two decimals are accepted and at most 13 digits before the point; leading zeros are not allowed. The platform sends wallet amounts as JSON numbers with exactly two decimals (1.50, not 1.5). Some informational meta fields (nominal_bet, total_win inside meta.freespins, multiplier) are plain numbers without padding. Hash and verify the signature over the raw bytes of the body, never over re-serialised JSON (Callback signature).
Dates and times#
expires_at,created_at,finished_atand similar fields are ISO 8601. When you sendexpires_atit must include a zone (Zor+02:00), for example2027-02-01T12:00:00Z.- Wallet callbacks carry Unix timestamps in seconds (
meta.time,timestamp).
Identifiers#
| Id | Where it comes from |
|---|---|
player_id | Chosen by you (1–128 printable ASCII characters) |
session_id | Returned by the launch method |
round_id | Generated by the platform; appears in wallet callbacks and the admin Game History |
meta.transaction | Unique id of each wallet operation (bet, win, refund) |
grant_id, outcome_id | UUIDs generated by the platform |
external_id | Optional id of your own for grants and outcomes, unique within the project (1–128 printable characters without spaces) |
Unknown fields#
The launch method rejects fields it does not know with INVALID_REQUEST. Send only the documented fields.
Time-outs and retries from your side#
Use a client time-out of about 10 seconds; on a time-out or a 5xx, repeat the call with the same Idempotency-Key. A 4xx is a definitive answer: fix the request first.