API Docs
Table of contents
Glossary
Denomination - a positive integer number which is a denominator of a given amount of a balance transaction. It makes using floating-point numbers and precision errors avoidable. It is presented together with the value it corresponds to. For example, $30.73 would look like
{ "amount": 3073, "denomination": 100 }{ "amount": 3073, "denomination": 100 } Transaction ID - is used in balance-related operations to prevent double is used in balance-related operations to prevent double spend, when multiple consecutive requests are issued as a result of possible failures in request retry loop, i.e. the 1st request could be accepted by provider’s server, but for some reason, we didn’t receive a successfull response, after which, a 2nd request shall be issued with the same transaction ID.
Game history - when a user_id parameter is
supplied at session initialization, it is then used to track, which machines
are chosen by user and push them to the “Recently played” list.
Sequence Diagram
sequenceDiagram
participant P as Provider
participant S as Game Server
participant C as Web Client
P ->>+ S: Send Session Init request
S ->>- P: URL to application
P ->> C: Open URL in tab/iframe
C ->> S: Connect
loop
C ->> S: Choose Machine
C ->>+ S: Choose Amount
S ->>- P: Send Update Balance request (withdraw)
opt
S ->> P: Send Log Action request
end
C ->>+ S: Exit to lobby / Close tab / Go offline
S ->>- P: Send Balance Update request (deposit)
end
Note over S: Session is closed API Endpoints
Requests made by Provider to Server
OpenAPI spec in json or yaml format.
Initialize a Session
Endpoint: POST /api/v1/session/init
Request payload:
{
"casino_id": "<identifier>", // required
"game_id": "<game identifier>", // required
"session": "<session identifier>", // required
"user_id": "<user identifier>", // optional
"currency": "USD", // required
"locale": "en", // optional
"geo": "", // optional
"denomination": 1000,
"balance": 17020,
"return_url": "https://example.com", // optional
"cashier_url": "https://example.com", // optional
"sub_id": "<id1>,<id2>,<id3>", // optional
"buffer": "<encoded internal state>", // optional
"sign": "<payload signature, see below>" // required
}{
"casino_id": "<identifier>", // required
"game_id": "<game identifier>", // required
"session": "<session identifier>", // required
"user_id": "<user identifier>", // optional
"currency": "USD", // required
"locale": "en", // optional
"geo": "", // optional
"denomination": 1000,
"balance": 17020,
"return_url": "https://example.com", // optional
"cashier_url": "https://example.com", // optional
"sub_id": "<id1>,<id2>,<id3>", // optional
"buffer": "<encoded internal state>", // optional
"sign": "<payload signature, see below>" // required
} | Field | Type | Required | Description |
|---|---|---|---|
casino_id | string | ✓ | A predetermined casino identifier |
game_id | string | ✓ | A Lobby identifier, either negotiated before or retrieved from the list-endpoint |
session | string | ✓ | A unique session identifier |
user_id | string | ✗ | A user identifier. If supplied, then history feature becomes available for the session |
currency | string | ✓ | ISO 4217 currency code |
locale | string | ✗ | ISO 639 language code |
geo | string | ✗ | ISO_3166-2 string representing user’s geo, i.e. CA, CA-ON |
denomination | integer | ✓ | Denomination of the balance |
balance | integer | ✓ | User’s balance |
return_url | string | ✗ | A URL, which would be used for redirects at the end of the session |
cashier_url | string | ✗ | A URL for redirecting to deposit page |
sub_id | string | ✗ | IDs of sub-clients, in the form of comma-separated list |
buffer | string | ✗ | Used for integration with stateless systems |
sign | string | ✓ | A Request signature |
Responses:
200 OK{ "url": "<game URL>" }{ "url": "<game URL>" }Field Type Required Description urlstring ✓ URL of the game’s client The
game_idis either aserialproperty of an object with"type": "machine"ornameproperty of an object with"type": "lobby", which are returned from List machines and lobbies endpoint.404 Not FoundUnknown
casino_id
List machines and lobbies
Endpoint: POST /api/v1/machine/list
Request payload:
{
"casino_id": "<identifier>",
"sign": "<payload signature, see below>"
}{
"casino_id": "<identifier>",
"sign": "<payload signature, see below>"
} | Field | Type | Required | Description |
|---|---|---|---|
casino_id | string | ✓ | A predetermined casino identifier |
sign | string | ✓ | A Request signature |
Responses:
200 OK{ "items": [ { "type": "lobby", "id": "lobby_1" }, { "type": "lobby", "id": "lobby_2" }, { "type": "machine", "serial": "FF000000000000FF", "status": "online", "tags": { "manufacturer": "Novomatic" } } ] }{ "items": [ { "type": "lobby", "id": "lobby_1" }, { "type": "lobby", "id": "lobby_2" }, { "type": "machine", "serial": "FF000000000000FF", "status": "online", "tags": { "manufacturer": "Novomatic" } } ] }Each element of the
itemsproperty represents a lobby. Theidproperty shall be used ingame_idparameter, when initializing a session.404 Not FoundUnknown
casino_id
Link to Session History
Endpoint: POST /api/v1/history/link
Request payload:
{
"session": "<identifier>",
"casino_id": "<identifier>",
"sign": "<payload signature, see below>"
}{
"session": "<identifier>",
"casino_id": "<identifier>",
"sign": "<payload signature, see below>"
} | Field | Type | Required | Description |
|---|---|---|---|
session | string | ✓ | Session ID used when initializing it |
casino_id | string | ✓ | A predetermined casino identifier |
sign | string | ✓ | A Request signature |
Responses:
200 OK{ "url": "<url to session history>" }{ "url": "<url to session history>" }Field Type Required Description urlstring ✓ URL which directs to the page with session history 404 Not FoundUnknown
casino_id
Requests made by Server to Provider
OpenAPI spec in json or yaml format.
The endpoints can be tweaked per each provider, but the defaults are provided below:
Update Balance
Endpoint: POST /action
Request Payload:
{
"session": "<identifier>",
"currency": "USD",
"amount": 1332,
"denomination": 100,
"type": "win", // "win", "bet" or "refund"
"transaction": "<tx identifier>",
"betTransactionId": "<bet tx identifier>",
"roundId": "<round number>",
"sign": "string", // See Request signing
"timestamp": 1644231487,
"machine": "FFFF456789ABCDEF",
"buffer": "<encoded internal state>" // optional
}{
"session": "<identifier>",
"currency": "USD",
"amount": 1332,
"denomination": 100,
"type": "win", // "win", "bet" or "refund"
"transaction": "<tx identifier>",
"betTransactionId": "<bet tx identifier>",
"roundId": "<round number>",
"sign": "string", // See Request signing
"timestamp": 1644231487,
"machine": "FFFF456789ABCDEF",
"buffer": "<encoded internal state>" // optional
} | Field | Type | Required | Description |
|---|---|---|---|
session | string | ✓ | Session identifier, specified in Initialize a Session endpoint |
currency | string | ✓ | ISO 4217 currency code |
amount | integer | ✓ | Amount to withdraw/deposit |
denomination | integer | ✓ | Denomination of the amount |
type | string | ✓ | "win", "bet" or "refund" |
transaction | string | ✓ | A unique transaction ID |
betTransactionId | string | ✓ | Bet transaction ID, transaction from previous bet request for win/refund, same as transaction for bet |
roundId | integer | ✓ | Non-negative number, binding pairs of bet and win/refund requests |
sign | string | ✓ | A Request signature |
timestamp | integer | ✓ | UNIX Epoch timestamp in milliseconds |
machine | string | ✗ | Machine identifier, on which the game was played |
buffer | string | ✗ | Used for integration with stateless systems |
Response Payload:
{
"balance": 1332,
"denomination": 100,
"transaction": "<tx identifier>",
"buffer": "<encoded internal state>" // optional
}{
"balance": 1332,
"denomination": 100,
"transaction": "<tx identifier>",
"buffer": "<encoded internal state>" // optional
} | Field | Type | Required | Description |
|---|---|---|---|
balance | integer | ✓ | Resulting balance |
denomination | integer | ✓ | Denomination of the amount |
transaction | string | ✓ | A unique transaction ID |
buffer | string | ✗ | Used for integration with stateless systems |
Log Action
This endpoint can be optinally supported by provider, to receive events that happen in-between the withdraw and deposit requests (i.e. through Update Balance endpoint).
Request Payload:
{
"session": "<identifier>", // The identifier, sent by provider in init request
"currency": "USD",
"amount": 132,
"denomination": 100,
"type": "win", // "win", "bet" or "refund"
"transaction": "<tx identifier>",
"sign": "string", // See Request signing
"timestamp": 1644231487,
"buffer": "<encoded internal state>" // optional
}{
"session": "<identifier>", // The identifier, sent by provider in init request
"currency": "USD",
"amount": 132,
"denomination": 100,
"type": "win", // "win", "bet" or "refund"
"transaction": "<tx identifier>",
"sign": "string", // See Request signing
"timestamp": 1644231487,
"buffer": "<encoded internal state>" // optional
} | Field | Type | Required | Description |
|---|---|---|---|
session | string | ✓ | Session identifier, specified in Initialize a Session endpoint |
currency | string | ✓ | ISO 4217 currency code |
amount | integer | ✓ | Amount to withdraw/deposit |
denomination | integer | ✓ | Denomination of the amount |
type | string | ✓ | "win", "bet" or "refund" |
transaction | string | ✓ | A unique transaction ID |
sign | string | ✓ | A Request signature |
timestamp | integer | ✓ | UNIX Epoch timestamp in milliseconds |
buffer | string | ✗ | Used for integration with stateless systems |
Response Payload:
Any non-errorneous status code with arbitrary payload which is ignored.
Wallet
Endpoint: POST /wallet
Request Payload:
{
"session": "<identifier>", // The identifier, sent by provider in init request
"currency": "USD",
"denomination": 100,
"transaction": "<tx identifier>",
"sign": "string", // See Request signing
"timestamp": 1644231487,
"buffer": "<encoded internal state>" // optional
}{
"session": "<identifier>", // The identifier, sent by provider in init request
"currency": "USD",
"denomination": 100,
"transaction": "<tx identifier>",
"sign": "string", // See Request signing
"timestamp": 1644231487,
"buffer": "<encoded internal state>" // optional
} | Field | Type | Required | Description |
|---|---|---|---|
session | string | ✓ | Session identifier, specified in Initialize a Session endpoint |
currency | string | ✓ | ISO 4217 currency code |
denomination | integer | ✓ | Denomination of the amount |
transaction | string | ✓ | A unique transaction ID |
sign | string | ✓ | A Request signature |
timestamp | integer | ✓ | UNIX Epoch timestamp in milliseconds |
buffer | string | ✗ | Used for integration with stateless systems |
Response Payload:
{
"balance": 1332,
"denomination": 100,
"transaction": "<tx identifier>",
"buffer": "<encoded internal state>" // optional
}{
"balance": 1332,
"denomination": 100,
"transaction": "<tx identifier>",
"buffer": "<encoded internal state>" // optional
} | Field | Type | Required | Description |
|---|---|---|---|
balance | integer | ✓ | Resulting balance |
denomination | integer | ✓ | Denomination of the amount |
transaction | string | ✓ | A unique transaction ID |
buffer | string | ✗ | Used for integration with stateless systems |
Request signing
Endpoints that contain top level sign field are subject to payload signing.
The sign is calculated in the following way:
- Encode the payload into JSON. To avoid inconsistency regarding object key ordering, all object values in the payload must have their keys sorted alphabetically. Some languages have this behaviour out-of-the-box (i.e. Pythons’s
json.dumpswithsort_keys=True) - Append a key to the encoded JSON string
- Compute a hash from the resulting string using provided algorithm
- Encode the output of the hashing function into hex string
When performing a request, take the constructed object, compute the sign using the steps above and assign the hex string to the sign property before encoding and sending the payload.
When checking the signature of an incoming request, decode the payload, take the sign property from the object, compute the sign of the object with removed sign key using the steps above and compare the incoming and computed signatures. If they are equal, the request is trusted.
Below are the code snippets for some languages which implement functions for computing the sign, applying it the the payload and checking the incoming request payload:
import { createHash } from 'node:crypto';
function encodeValueSorted(value) {
if (value === null || typeof value !== 'object') {
return JSON.stringify(value);
}
if (Array.isArray(value)) {
return `[${value.map(encodeValueSorted).join(',')}]`;
}
const entries = Object.entries(value)
.filter(([, val]) => val !== undefined)
.sort(([key1], [key2]) => (key1 > key2 ? 1 : -1))
.map(([key, val]) => `${JSON.stringify(key)}:${encodeValueSorted(val)}`);
return `{${entries.join(',')}}`;
}
function getSignature(payload, key, algorithm) {
const hashInput = `${encodeValueSorted(payload)}${key}`;
const hash = createHash(algorithm);
return hash.update(hashInput).digest('hex');
}
const key = '0d50d9b3-7d80-422a-a20d-ab4ca017737f';
const algorithm = 'sha256';
function signPayload(payload) {
const sign = getSignature(payload, key, algorithm);
return { ...payload, sign };
}
function checkPayload(payload) {
const { sign, ...rest } = payload;
return sign === getSignature(rest, key, algorithm);
}import { createHash } from 'node:crypto';
function encodeValueSorted(value) {
if (value === null || typeof value !== 'object') {
return JSON.stringify(value);
}
if (Array.isArray(value)) {
return `[${value.map(encodeValueSorted).join(',')}]`;
}
const entries = Object.entries(value)
.filter(([, val]) => val !== undefined)
.sort(([key1], [key2]) => (key1 > key2 ? 1 : -1))
.map(([key, val]) => `${JSON.stringify(key)}:${encodeValueSorted(val)}`);
return `{${entries.join(',')}}`;
}
function getSignature(payload, key, algorithm) {
const hashInput = `${encodeValueSorted(payload)}${key}`;
const hash = createHash(algorithm);
return hash.update(hashInput).digest('hex');
}
const key = '0d50d9b3-7d80-422a-a20d-ab4ca017737f';
const algorithm = 'sha256';
function signPayload(payload) {
const sign = getSignature(payload, key, algorithm);
return { ...payload, sign };
}
function checkPayload(payload) {
const { sign, ...rest } = payload;
return sign === getSignature(rest, key, algorithm);
} import json
import hashlib
def get_signature(payload, key, algorighm):
hash_input = json.dumps(payload, sort_keys=True, separators=(",", ":"))
hash_input += key
hash = hashlib.new(algorighm, hash_input.encode())
return hash.hexdigest()
key = "0d50d9b3-7d80-422a-a20d-ab4ca017737f"
algorithm = "sha256"
def sign_payload(payload):
sign = get_signature(payload, key, algorithm)
return {**payload, "sign": sign}
def check_payload(payload):
payload = {**payload}
expected = payload.pop("sign")
actual = get_signature(payload, key, algorithm)
return expected == actualimport json
import hashlib
def get_signature(payload, key, algorighm):
hash_input = json.dumps(payload, sort_keys=True, separators=(",", ":"))
hash_input += key
hash = hashlib.new(algorighm, hash_input.encode())
return hash.hexdigest()
key = "0d50d9b3-7d80-422a-a20d-ab4ca017737f"
algorithm = "sha256"
def sign_payload(payload):
sign = get_signature(payload, key, algorithm)
return {**payload, "sign": sign}
def check_payload(payload):
payload = {**payload}
expected = payload.pop("sign")
actual = get_signature(payload, key, algorithm)
return expected == actual package signing
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"hash"
)
type Signable interface {
SetSign(sign string)
ExtractSign() string
}
var hashCtors = map[string]func() hash.Hash{
"sha256": sha256.New,
}
func getSignature(payload any, key string, algorithm string) (string, error) {
createHash, ok := hashCtors[algorithm]
if !ok {
return "", errors.New("Unsupported hash algorithm")
}
var enc []byte
var err error
if enc, err = json.Marshal(payload); err != nil {
return "", err
}
// Sort keys alphabetically by unmarshaling back into map and then marshallng the result from it
pMap := make(map[string]any)
if err = json.Unmarshal(enc, &pMap); err != nil {
return "", err
}
if enc, err = json.Marshal(pMap); err != nil {
return "", err
}
hash := createHash()
if _, err = hash.Write(enc); err != nil {
return "", err
}
if _, err = hash.Write([]byte(key)); err != nil {
return "", err
}
sum := hash.Sum(nil)
return hex.EncodeToString(sum), nil
}
var key = "0d50d9b3-7d80-422a-a20d-ab4ca017737f"
var algorithm = "sha256"
func SignPayload[T Signable](payload T) error {
sign, err := getSignature(payload, key, algorithm)
if err != nil {
return err
}
payload.SetSign(sign)
return nil
}
func CheckPayload[T Signable](payload T) (bool, error) {
expected := payload.ExtractSign()
actual, err := getSignature(payload, key, "sha256")
if err != nil {
return false, err
}
return expected == actual, nil
}package signing
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"hash"
)
type Signable interface {
SetSign(sign string)
ExtractSign() string
}
var hashCtors = map[string]func() hash.Hash{
"sha256": sha256.New,
}
func getSignature(payload any, key string, algorithm string) (string, error) {
createHash, ok := hashCtors[algorithm]
if !ok {
return "", errors.New("Unsupported hash algorithm")
}
var enc []byte
var err error
if enc, err = json.Marshal(payload); err != nil {
return "", err
}
// Sort keys alphabetically by unmarshaling back into map and then marshallng the result from it
pMap := make(map[string]any)
if err = json.Unmarshal(enc, &pMap); err != nil {
return "", err
}
if enc, err = json.Marshal(pMap); err != nil {
return "", err
}
hash := createHash()
if _, err = hash.Write(enc); err != nil {
return "", err
}
if _, err = hash.Write([]byte(key)); err != nil {
return "", err
}
sum := hash.Sum(nil)
return hex.EncodeToString(sum), nil
}
var key = "0d50d9b3-7d80-422a-a20d-ab4ca017737f"
var algorithm = "sha256"
func SignPayload[T Signable](payload T) error {
sign, err := getSignature(payload, key, algorithm)
if err != nil {
return err
}
payload.SetSign(sign)
return nil
}
func CheckPayload[T Signable](payload T) (bool, error) {
expected := payload.ExtractSign()
actual, err := getSignature(payload, key, "sha256")
if err != nil {
return false, err
}
return expected == actual, nil
} <?php
function is_json_array(array $arr): bool {
if ($arr === []) {
return true;
}
return array_keys($arr) === range(0, count($arr) - 1);
}
function encodeValueSorted($value): string {
if (!is_array($value) && !is_object($value)) {
return json_encode($value);
}
if (is_object($value)) {
$value = (array)$value;
}
if (is_json_array($value)) {
$encoded_elements = array_map('encodeValueSorted', $value);
return '[' . implode(',', $encoded_elements) . ']';
}
$entries = [];
foreach ($value as $key => $val) {
$entries[(string)$key] = $val;
}
ksort($entries);
$encoded_entries = [];
foreach ($entries as $key => $val) {
$encoded_key = json_encode((string)$key);
$encoded_value = encodeValueSorted($val);
$encoded_entries[] = $encoded_key . ':' . $encoded_value;
}
return '{' . implode(',', $encoded_entries) . '}';
}
function getSignature($payload, string $key, string $algorithm): string {
$hashInput = encodeValueSorted($payload) . $key;
return hash($algorithm, $hashInput);
}
const key = '0d50d9b3-7d80-422a-a20d-ab4ca017737f';
const algorithm = 'sha256';
function signPayload(array $payload): array {
$sign = getSignature($payload, key, algorithm);
return array_merge($payload, ['sign' => $sign]);
}
function checkPayload(array $payload): bool {
$sign = $payload['sign'] ?? null;
$rest = $payload;
unset($rest['sign']);
return $sign !== null && $sign === getSignature($rest, key, algorithm);
}
?><?php
function is_json_array(array $arr): bool {
if ($arr === []) {
return true;
}
return array_keys($arr) === range(0, count($arr) - 1);
}
function encodeValueSorted($value): string {
if (!is_array($value) && !is_object($value)) {
return json_encode($value);
}
if (is_object($value)) {
$value = (array)$value;
}
if (is_json_array($value)) {
$encoded_elements = array_map('encodeValueSorted', $value);
return '[' . implode(',', $encoded_elements) . ']';
}
$entries = [];
foreach ($value as $key => $val) {
$entries[(string)$key] = $val;
}
ksort($entries);
$encoded_entries = [];
foreach ($entries as $key => $val) {
$encoded_key = json_encode((string)$key);
$encoded_value = encodeValueSorted($val);
$encoded_entries[] = $encoded_key . ':' . $encoded_value;
}
return '{' . implode(',', $encoded_entries) . '}';
}
function getSignature($payload, string $key, string $algorithm): string {
$hashInput = encodeValueSorted($payload) . $key;
return hash($algorithm, $hashInput);
}
const key = '0d50d9b3-7d80-422a-a20d-ab4ca017737f';
const algorithm = 'sha256';
function signPayload(array $payload): array {
$sign = getSignature($payload, key, algorithm);
return array_merge($payload, ['sign' => $sign]);
}
function checkPayload(array $payload): bool {
$sign = $payload['sign'] ?? null;
$rest = $payload;
unset($rest['sign']);
return $sign !== null && $sign === getSignature($rest, key, algorithm);
}
?>Thumbnails
Brand Assets
| Name | Previw |
|---|---|
| RealLiveSlots-logo.svg | |
| RealLiveSlots-logo-310x310.png | ![]() |
