Notell API Docs
Русский

Integration

Conventions

Requests and responses#

  • Server calls are POST with Content-Type: application/json and a JSON object body. application/x-www-form-urlencoded bodies are also parsed, but JSON is the contract. Always send one of these two content types: with any other type, such as text/plain, the body is not parsed as JSON and the call fails (typically with UNAUTHORIZED, because partner is 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 400 REQUEST_FAILED, not INVALID_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. message is always an upper-case code; see the error reference. A failure without a public code is REQUEST_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.
HTTPTypical meaning
200Success
400Validation error or a business rule (INVALID_REQUEST, PROJECT_BET_LIMIT, …); also most failures without a more specific status, and IDEMPOTENCY_CONFLICT on /playGame.do
401UNAUTHORIZED
403IP_NOT_ALLOWED (or FORBIDDEN)
404Unknown 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
429RATE_LIMITED
503DEMO_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.do and /gameActions.do keep separate keys). On /gameActions.do the same key used for two different method values is a conflict. /playerRtp.do does 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_key field 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_create and outcome_schedule are additionally protected by external_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:

ClassEndpointDefault quota
launchPOST /playGame.do1200 per minute
actionsPOST /gameActions.do (free spins, target outcomes, round_cancel)600 per minute
reportsPOST /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.do and the public GET endpoints are not limited.
  • The bucket is chosen by the partner field of the body before the key is checked: calls with a known partner and a wrong key also use up the quota, and 429 can be answered before 401. The counters live in memory of the server process and start again after a restart.
  • Over the quota the answer is HTTP 429 RATE_LIMITED and nothing is executed. Counted answers carry X-RateLimit-Limit (for example 600/min); allowed ones also X-RateLimit-Remaining; a refusal carries Retry-After in whole seconds (at least 1).
  • The values of an environment are in rateLimits of GET /capabilities; higher values can be agreed with your account manager.
http
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.

ContextFormatExample
Wallet callbacks: amount, bet_amount, win_amountJSON number, written with two decimals by the platform1.50, 12.75
Wallet answer: balanceJSON number, non-negative, at most 2 decimals, no exponent998.50
bet, total_win of free spins and freespins_finished; reports; demo_balanceDecimal string, at most 2 decimals"1.00"
min_minor, max_minorString 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_at and similar fields are ISO 8601. When you send expires_at it must include a zone (Z or +02:00), for example 2027-02-01T12:00:00Z.
  • Wallet callbacks carry Unix timestamps in seconds (meta.time, timestamp).

Identifiers#

IdWhere it comes from
player_idChosen by you (1–128 printable ASCII characters)
session_idReturned by the launch method
round_idGenerated by the platform; appears in wallet callbacks and the admin Game History
meta.transactionUnique id of each wallet operation (bet, win, refund)
grant_id, outcome_idUUIDs generated by the platform
external_idOptional 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.

Documentation for operators and integrators.TEST_ONLY platform: non-withdrawable units, no real payments.