Open Entertainment Platform

Authentication

All POST requests use Content-Type: application/json. Except health and create_token, public APIs require the token request header.

Server IP allowlist

Token requests and subsequent API calls validate your server's outbound IP. An unlisted IP receives HTTP 403 with ip_not_allowed. An empty allowlist denies access. Register the calling server's public outbound IP, not a platform proxy IP.

The HTTPS entry overwrites and forwards the actual source IP. WebDeliverServer trusts X-Real-IP only when the connection comes from an explicitly configured trusted proxy. Other proxy headers, X-Forwarded-For and IPs declared in request bodies cannot bypass allowlisting. Partners do not need to set these headers.

Allowlist changes, suspension and secret resets take effect on runtime configuration refresh, usually within seconds. Existing tokens are also subject to IP validation.

Obtain a token

POST /api/v1/create_token

{
  "partner": "YOUR_CODE",
  "timestamp": "UNIX_SECONDS",
  "nonce": "32_LOWERCASE_HEX_CHARACTERS",
  "sign": "64_LOWERCASE_HEX_HMAC"
}

Calculate HMAC-SHA256(secret, timestamp + ":" + nonce) and encode it as lowercase hexadecimal. timestamp is a string containing Unix seconds, with a permitted clock difference of 300 seconds. nonce must be exactly 32 lowercase hexadecimal characters, representing 16 cryptographically random bytes. Generate a new nonce and timestamp for every attempt, including retries. Use the displayed secret text as the HMAC key; do not hex-decode it.

{
  "success": true,
  "message": "TOKEN",
  "expires_in": 3600
}

Invalid secrets, expired signatures, reused nonces and unapproved partners are rejected. Tokens last at most one hour. Repeated requests reuse an unexpired token; cache for no more than 50 minutes. Obtain a new token after DBServer restarts. Secret changes and partner suspension invalidate old tokens.

Do not request a token for every operation or replay failed business requests unconditionally. After obtaining a new token, retry only operations explicitly safe to retry. API errors, session interruption and wallet callback failures are different conditions.

Go signing example

h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(timestamp + ":" + nonce))
sign := hex.EncodeToString(h.Sum(nil))

Example domains and credentials are placeholders. Use HTTPS for deployment; HTTP is acceptable for local testing. Exclude token, secret, sign, user_key and session-bearing launch URLs from access logs.

Request and response conventions

Obtain the API base URL from Applications → app → Credentials. Endpoint, code and secret must all belong to the app. partner contains the app's code, not the app ID, email or literal word code. Use secret only to calculate signatures locally; never send it to the API. This protocol uses the token header, not Authorization: Bearer.

Token request field Type Requirement
partner string Required: approved app code
timestamp string Required: decimal Unix seconds, not milliseconds
nonce string Required: 32 random lowercase hexadecimal characters
sign string Required: 64 lowercase hexadecimal HMAC-SHA256 characters
Token response field Type Meaning
success boolean Business result
message string Token on success; explanation on failure
expires_in integer Currently 3600; reuse does not extend the token's remaining life
POST /api/v1/gamelist HTTP/1.1
Host: api.example.invalid
Content-Type: application/json
token: YOUR_TOKEN

{}

Check HTTP status first, then success. Only game catalog, machine catalog and game activity return a JSON-encoded message string requiring a second parse. Other APIs use top-level fields; health has no success field. Never JSON.parse every message unconditionally.

const response = await fetch(apiBase + "/api/v1/gamelist", {
  method: "POST",
  headers: { "Content-Type": "application/json", token },
  body: "{}"
});
const body = await response.json();
if (!response.ok || body.success !== true) {
  throw new Error(body.message || body.error || "API request failed");
}
const catalog = JSON.parse(body.message);
const games = catalog.list;

Run this on your server only. Production implementations also need timeouts, non-JSON response handling and sensitive-log redaction.

Errors and retries

There are two error shapes; error is not always present. HTTP 200 can still indicate business failure.

{"success": false, "message": "invalid user code"}
{"error": "ip_not_allowed", "message": "server IP is not in the partner whitelist"}
HTTP status Typical response Action
200 with success=false message explains the business failure Correct parameters or business conditions; do not treat as success
400 request_body_required / invalid_json_body Check body and JSON encoding
401 invalid credentials Check endpoint, code, secret, clock and nonce
401 missing partner token / invalid or expired partner token Supply a valid token or obtain a new one
403 ip_not_allowed Update the app's server outbound IP, not the player's browser IP
404 route_not_found / method_not_allowed Check path and method; wrong methods currently also return 404
413 Body too large Reduce the request; do not repeat it unchanged
500 / 503 Service error or db_unavailable Log redacted context; bounded backoff for read-only requests
504 http_timeout Result may be unknown; check status or reconcile records first

Read-only catalog and status queries may use bounded retries after transient failures. A launch or kick timeout does not prove the operation was not executed; check player status first. There is no generic idempotency request header. Do not assume another platform's Idempotency-Key semantics. See Callbacks and settlement.