
<center> <font size="10">Integration API Specification </font> </center>
</br>
<center>Version 1.0.1</center>
</br>
<center>Latest Update: October, 2024</center>
---
# Revision History
| Version | Date | Name | Description |
| ------- | ------------ | -------------- | ----------------- |
| 1.0.0 | 01 Jan 2022 | Anh Ngo | Initial document |
| 1.0.0 | 24 Jun 2022 | Phuong Nguyen | Reviewed |
| 1.0.1 | 01 Oct 2024 | Therese Wu | Free Spin Bonus API, <br> Bonus Win API |
---
# API Overview
This document describes set of APIs which Operator needs to implement to integrate with Seamless Wallet API. <br>
The Seamless Wallet integration allows you to add LitePlay Provider games to your platform using your own wallet and authentication systems. You may optionally provide game configuration / parameters to LitePlay Provider. You maintain full control over the player and wallet and all debits / credits are performed against your wallet in real time.<br>
LitePlay Provider will call the methods when players make a bet or get a win and their balance should be updated.<br>
**URL of the Seamless Wallet API should be provided by the Operator for the production and test environments.** <br>
Provider API and Operator Integration API uses signature to validate incoming/outgoing request integrity. The hash encryption algorithm is described in section [Hash Authenticate](#Hash-Authentication) <br>
Some APIs are required to be **idempotent** which means making multiple identical requests has the same effect as making a single request. <br>
* APIs Timeout is 10 seconds.
* You can check your API settings in LitePlay Provider Back Office
* API URL: LitePlay Provider will make API calls to this URL
* Session timeout: member's session timeout, automatically logout member if no action is taken in a time duration
* Whitelist IPs: IPs to access LitePlay Provider Back Office
* API Endpoint Whitelist IP: IP that can call [Private APIs](#Private-APIs)
* Whitelisting
* Seamless wallet users are provided with the LitePlay Provider IP addresses which will call your API.
* If using our web service, you may setup the IP access list in our Back Office.
* Back Office users do not need whitelisting but this can be setup per User in the Back Office
* Data Feeds: APIs on the LitePlay Provider side provides a set of data feeds for:
* [Play Sessions](#Player-History)
* [Failed transactions](#Failed-Transactions) (that needs manual retry)
* Player ID(username parameter) is a unique identifier of the user within the Operator system. Before sending to LitePlay Provider any gaming related request the Operator should authenticate a player using the Authenticate method. If a player is new and its account does not exist in the LitePlay Provider system it will be created automatically on the base of the data sent by the Operator server in the Authenticate response. If a player account already exists in the LitePlay Provider database it will be updated with the response data if necessary. Player ID received in the Authenticate response will be sent with all subsequent requests to the Operator.
* Play Session: a game round in which bets and wins are combined together. Each round can contain several bets, wins and refunds of the bets.
* Transaction Reference: a unique transaction id within LitePlay Provider system. Transaction reference used for bets and wins has to be different.
# Private APIs
* Operator will call these APIs, (Operator -> LitePlay Provider)
* Therefore, Operator will give IP Address to LitePlay Provider to whitelist (this is API Whitelist IP in LitePlay Provider Back Office)
* All APIs are in JSON format (`application/json`), POST method, and in HTTPS
* Authentication: please refer to [Hash Authentication](#Hash-Authentication)
* Fields will be in underscore_
* Special data type (apply to request/response data):
* `Integer`: this will use normal number data type from JSON (no quoted)
For example:`{"counter": 12}`
* `String`: use string data type from JSON (quoted)
For example:`{"name": "abc1234"}`
* `Decimal`: for money, rate fields, this use string data type from JSON (quoted)
For example: `{"credit": "2134.34"}`
* `DateTime`: use string data type from JSON (quoted).
Format will be `DD/MM/YYYY HH:mm:ssZ`.
If no `Z` (timezone) specific, the default `+0000` (UTC) will be used.
For example: `{"from": "15/01/2006 15:04:03+0700"}`
* `username` field:
* Identifier of the user within the Operator’s system <br>Parameter value is case-sensitive
* Example: bet88_anh, 781362, playerABC, playerAbc (playerABC and playerAbc – are two different player accounts within LitePlay Provider system)
* `err` field:
* No `err` field/Empty `err` field means success
* For list of error code, please see [Error Code List](#Error-Code-List)
* Some error will have additional data in `data` field, please also refer to [Error Code List](#Error-Code-List) for example
## Game List
The Operator can use this API to get a list of all available games.
Endpoint: `/games`
Method: `POST`
**Response Parameters**
| Parameter | Data Type | Description |
|-----------|-----------|--------------------------|
| games | Array | Array of **Game Object** |
| err | String | error code |
**Game Object**
| Parameter | Data Type | Description |
| --------- | --------- | ---------------------------------- |
| game_code | String | Game identifier for each game |
| game_name | String | Game name (in EN) |
| game_type | String | Game type e.g. Video Slot, Fishing |
| enable | Boolean | `true` = enable, `false` = disable |
*Example of JSON response:*
```json
{
"games": [
{
"game_code": "vseldorado",
"game_type": "Video Slot",
"game_name": "Eldorado",
"enable": true
},
{
"game_code": "vsoceanblue",
"game_type": "Video Slot",
"game_name": "Ocean Blue",
"enable": false
}
],
"err": ""
}
```
## Get Game URL
The Operator can use this API to get game link for a player to play game
Endpoint: `/game_url`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Mandatory | Description |
|-------------|-----------|-----------|-------------------------------------------------------------------------------------------------------------------------|
| token | String | Required | secure token generated by operator for the player |
| game_code | String | Required | unique identifier for the game, e.g. vseldorado, vswanted, vsdogo, etc. |
| platform | String | Optional | `web`: for desktop devices<br>`mobile`: for mobile devices (mobile web browser), default<br>`app`: for APK (mobile app) |
| language | String | Optional | player language in ISO 639-1 standard (e.g. en, fr, it), default to `en` . For list of languages, please see [Appendix A](#Appendix-A-Languages)|
| lobby_url | String | Optional | an URL for opening the Operator’s website Lobby page |
| history_url | String | Optional | an URL to open game history page on Operator’s side |
**Response Parameters**
| Parameter | Data Type | Description |
|-----------|-----------|-------------|
| url | String | Game URL |
| err | String | error code |
*Example of JSON request:*
```json
{
"token": "xjneroshp458djk34",
"game_code": "vseldorado",
"platform": "web",
"language": "en",
}
```
*Example of JSON response:*
```json
{
"url": "https://<game_domain>?token=xjneroshp458djk34&game_code=vseldorado&platform=web&language=en"
}
```
## Game History
The Operator can use this API to get a list of the game rounds played by all the players during the certain day and (optionally) the specific hour.
Endpoint: `/history`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Mandatory | Description |
|-----------|-----------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| from | DateTime | Required | From time |
| to | DateTime | Required | To time |
| page | Integer | Optional | The page index (default: 1) |
| page_size | Integer | Optional | Number of item per page (default: 100) |
Note:
* To query this, we will use `from` <= `round_date` <= `to`
* Therefore to query for example a day, you will use:
```json
{
"from": "02/07/2021 00:00:00+0700",
"to": "02/07/2021 23:59:59+0700"
}
```
* To query for an hour, you will use:
```json
{
"from": "02/07/2021 00:00:00+0700",
"to": "02/07/2021 00:59:59+0700"
}
```
**Response Parameters**
| Parameter | Data Type | Description |
|------------|-----------|-------------------------|
| total_size | Integer | Total item |
| list | Array | Array of **Game Round** |
| err | String | error code |
**Game Round**
| Parameter | Data Type | Description |
|---------------|-----------|-----------------------------------------------------------------------------------------------|
| round_id | String | Round id |
| end_date | DateTime | Round date |
| start_date | DateTime | Start round date (bet time) |
| balance_after | Decimal | Balance of player after game round |
| bet | Decimal | Bet amount |
| win | Decimal | Win amount |
| status | String | `freespin`: a freespin round<br>`refund`:a round with refunded bet<br>`end`: a complete round |
| game_code | String | Game code |
| game_name | String | Game name |
| username | String | Name player |
**Error Code**
| Error Code | Description |
|------------------------------|----------------------------------------------------------------------------------------------------------------------|
| err:invalid_date_time_format | invalid `from`/`to` datetime format (correct format: `DD/MM/YYYY HH:mm:ssZ`, for example `20/07/2021 09:20:36+0000`) |
| err:json_error | JSON data error. There will be a `data` field with more detail |
*Example of JSON resquest:*
```json
{
"from": "02/07/2021 00:00:00+0700",
"to": "02/08/2021 23:59:59+0700",
"page": 1,
"page_size": 3
}
```
*Example of JSON response:*
```json
{
"total_size": 59,
"list": [
{
"round_id": "BZw1EcaChwcfpZ4",
"end_date": "20/07/2021 09:20:36+0000",
"start_date": "20/07/2021 09:20:36+0000",
"balance_after": "20582412.7238",
"bet": "100",
"win": "200",
"status": "end",
"game_code": "vseldorado",
"game_name": "Eldorado",
"username": "toanto1"
},
{
"round_id": "BegEvLBgWikUyEQ",
"end_date": "20/07/2021 09:20:36+0000",
"start_date": "20/07/2021 09:20:36+0000",
"balance_after": "20582312.7238",
"bet": "100",
"win": "250",
"status": "end",
"game_code": "vseldorado",
"game_name": "Eldorado",
"username": "toanto1"
},
{
"round_id": "MGSN5zLrZzNeT6p",
"end_date": "20/07/2021 09:20:35+0000",
"start_date": "20/07/2021 09:20:35+0000",
"balance_after": "20582162.7238",
"bet": "100",
"win": "250",
"status": "end",
"game_code": "vseldorado",
"game_name": "Eldorado",
"username": "toanto1"
}
],
"err": ""
}
```
## Player History
The Operator can use this API to get a list of the game rounds played by the player during the certain day and (optionally) the specific hour.
Endpoint: `/player_history`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Mandatory | Description |
|-----------|-----------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| username | String | Required | Identifier of the user within the Operator’s system. |
| from | DateTime | Required | From time |
| to | DateTime | Required | To time |
| page | Integer | Optional | The page index (default: 1) |
| page_size | Integer | Optional | Number of item per page (default: 100) |
Note:
* To query this, we will use `from` <= `round_date` <= `to`
* Therefore to query for example a day, you will use:
```json
{
"from": "02/07/2021 00:00:00+0700",
"to": "02/07/2021 23:59:59+0700"
}
```
* To query for an hour, you will use:
```json
{
"from": "02/07/2021 00:00:00+0700",
"to": "02/07/2021 00:59:59+0700"
}
```
**Response Parameters**
| Parameter | Data Type | Description |
|------------|-----------|-------------------------|
| total_size | Integer | Total item |
| list | Array | Array of **Game Round** |
| err | String | error code |
**Game Round**
| Parameter | Data Type | Description |
|---------------|-----------|-----------------------------------------------------------------------------------------------|
| round_id | String | Round id |
| end_date | DateTime | Round date |
| start_date | DateTime | Start round date (bet time) |
| balance_after | Decimal | Balance of player after game round |
| bet | Decimal | Bet amount |
| win | Decimal | Win amount |
| status | String | `freespin`: a freespin round<br>`refund`:a round with refunded bet<br>`end`: a complete round |
| game_code | String | Game code |
| game_name | String | Game name |
**Error Code**
| Error Code | Description |
|------------------------------|----------------------------------------------------------------------------------------------------------------------|
| err:player_not_found | player with this `username` does not exist |
| err:invalid_date_time_format | invalid `from`/`to` datetime format (correct format: `DD/MM/YYYY HH:mm:ssZ`, for example `20/07/2021 09:20:36+0000`) |
| err:json_error | JSON data error. There will be a `data` field with more detail |
*Example of JSON resquest:*
```json
{
"username": "ajinomoto",
"from": "02/07/2021 00:00:00+0700",
"to": "02/08/2021 23:59:59+0700",
"page": 1,
"page_size": 3
}
```
*Example of JSON response:*
```json
{
"total_size": 59,
"list": [
{
"round_id": "BZw1EcaChwcfpZ4",
"end_date": "20/07/2021 09:20:36+0000",
"start_date": "20/07/2021 09:20:36+0000",
"balance_after": "20582412.7238",
"bet": "100",
"win": "200",
"status": "end",
"game_code": "vseldorado",
"game_name": "Eldorado"
},
{
"round_id": "BegEvLBgWikUyEQ",
"end_date": "20/07/2021 09:20:36+0000",
"start_date": "20/07/2021 09:20:36+0000",
"balance_after": "20582312.7238",
"bet": "100",
"win": "250",
"status": "end",
"game_code": "vseldorado",
"game_name": "Eldorado"
},
{
"round_id": "MGSN5zLrZzNeT6p",
"end_date": "20/07/2021 09:20:35+0000",
"start_date": "20/07/2021 09:20:35+0000",
"balance_after": "20582162.7238",
"bet": "100",
"win": "250",
"status": "end",
"game_code": "vseldorado",
"game_name": "Eldorado"
}
],
"err": ""
}
```
## Game Round Detail URL
The Operator can use this API to get a url that when open will show the game round detail of that `round_id`
Endpoint: `/round_detail`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Mandatory | Description |
|-----------|-----------|-----------|----------------------------------------|
| round_id | String | Required | the `round_id` |
**Response Parameters**
| Parameter | Data Type | Description |
| --------- | --------- | --------------------------------- |
| url | String | The URL to open game round detail |
| err | String | error code |
**Error Code**
| Error Code | Description |
|-------------------------|-----------------------------------------------------------------------------------------------------------------------|
| err:round_not_found | Game round with this `round_id` does not exist |
| err:json_error | JSON data error. There will be a `data` field with more detail |
*Example of JSON resquest:*
```json
{
"round_id": "MGSN5zLrZzNeT6p"
}
```
*Example of JSON response:*
```json
{
"url": "https://ajinomoto.vip/public/round_detail/MGSN5zLrZzNeT6p",
"err": ""
}
```
**Note: please don't just replace the round_id in this URL for different game round detail because we can change the base URL in the future**
## Failed Transaction
The Operator can use this API to get a list of the game rounds that have been refunded or needed manual retry.
The Operator does not need to implement this API. The same functionality is available in LitePlay Provider back-office site.
Endpoint: `/failed_transaction`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Mandatory | Description |
|-------------|--------------|-----------|----------------------------------------------------------------------------------------|
| from | DateTime | Required | From time |
| to | DateTime | Required | To time |
| status_list | String Array | Optional | `refund/retry_result/refunded/manual_retry_refund/manual_retry_result`. Empty mean All |
| username | String | Optional | Identifier of the user within the Operator’s system. |
| page | Integer | Optional | The page index (default: 1) |
| page_size | Integer | Optional | Number of item per page (default: 100) |
Note:
* To query this, we will use `from` <= `round_date` <= `to`
* Therefore to query for example a day, you will use:
```json
{
"from": "02/07/2021 00:00:00+0700",
"to": "02/07/2021 23:59:59+0700"
}
```
* To query for an hour, you will use:
```json
{
"from": "02/07/2021 00:00:00+0700",
"to": "02/07/2021 00:59:59+0700"
}
```
* status: `refund/retry_result/refunded/manual_retry_refund/manual_retry_result`
* `refund`: currently in refund process
* `retry_result`: currently in retry result process
* `refunded`: done refund process (bet has been refunded successfully)
* `manual_retry_refund`: waiting to manually retry refund
* `manual_retry_result`: waiting to manually retry result
**Response Parameters**
| Parameter | Data Type | Description |
|------------|-----------|-------------------------|
| total_size | Integer | Total item |
| list | Array | Array of **Game Round** |
| err | String | error code |
**Game Round**
| Parameter | Data Type | Description |
|---------------|-----------|------------------------------------------------------------------------|
| round_id | String | Round id |
| end_date | DateTime | Round date |
| start_date | DateTime | Start round date (bet time) |
| balance_after | Decimal | Balance of player after game round |
| bet | Decimal | Bet amount |
| win | Decimal | Win amount |
| status | String | `refund/retry_result/refunded/manual_retry_refund/manual_retry_result` |
| game_code | String | Game code |
| game_name | String | Game name |
**Error Code**
| Error Code | Description |
|------------------------------|----------------------------------------------------------------------------------------------------------------------|
| err:player_not_found | player with this `username` does not exist |
| err:invalid_date_time_format | invalid `from`/`to` datetime format (correct format: `DD/MM/YYYY HH:mm:ssZ`, for example `20/07/2021 09:20:36+0000`) |
| err:json_error | JSON data error. There will be a `data` field with more detail |
*Example of JSON resquest:*
```json
{
"username": "ajinomoto",
"from": "02/07/2021 00:00:00+0700",
"to": "02/08/2021 23:59:59+0700",
"page": 1,
"page_size": 3
}
```
*Example of JSON response:*
```json
{
"data": {
"total_size": 59,
"list": [
{
"round_id": "BZw1EcaChwcfpZ4",
"end_date": "20/07/2021 09:20:36+0000",
"start_date": "20/07/2021 09:20:36+0000",
"balance_after": "20582412.7238",
"bet": "100",
"win": "0",
"status": "refunded",
"game_code": "vseldorado",
"game_name": "Eldorado"
},
{
"round_id": "BegEvLBgWikUyEQ",
"end_date": "20/07/2021 09:20:36+0000",
"start_date": "20/07/2021 09:20:36+0000",
"balance_after": "20582312.7238",
"bet": "100",
"win": "0",
"status": "refunded",
"game_code": "vseldorado",
"game_name": "Eldorado"
},
{
"round_id": "MGSN5zLrZzNeT6p",
"end_date": "20/07/2021 09:20:35+0000",
"start_date": "20/07/2021 09:20:35+0000",
"balance_after": "20582162.7238",
"bet": "100",
"win": "0",
"status": "refunded",
"game_code": "vseldorado",
"game_name": "Eldorado"
}
]
},
"err": ""
}
```
## Manual Refund/Retry Transaction
The Operator can use this API to manually refund/retry a failed transaction (except refunded transaction).
The Operator does not need to implement this API. The same functionality is available in LitePlay Provider back-office site.
Endpoint: `/resume`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Mandatory | Description |
|-----------|-----------|-----------|----------------------------------------------------------------------------------------|
| round_id | String | Required | The game round id to manually refund/retry |
Note:
* cannot refund/retry `refunded` transaction
**Response Parameters**
| Parameter | Data Type | Description |
|------------|-----------|-------------------------|
| err | String | error code |
**Error Code**
| Error Code | Description |
|-------------------------------------|----------------------------------------------|
| err:round_not_found | game round with this round id is not existed |
| err:cannot_retry_refund_transaction | this round cannot be refunded/retried |
*Example of JSON resquest:*
```json
{
"round_id": "jgid8534jflds"
}
```
*Example of JSON response:*
```json
{
"err": ""
}
```
## Logout
Logout a player. Should not be required for Seamless wallet. Additionally, players can be logged out after a configured session timeout period (set in the Back Office).
**Note**:
* This will logout player from game client, but due to auto reconnect (or player refreshes the game client), an `/auth` request will be sent from LitePlay Provider to Operator, and if this request success, player will be logged in again.
* Therefore, Operator should clear the token before calling `logout`, so for the next `/auth` request, the Operator will response `err:token_not_found` and player cannot log in again.
Endpoint: `/logout`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Mandatory | Description |
| --------- | --------- | --------- | ------------------------------------------------------------------------------------------ |
| username | String | Required | Identifier of the user within the Operator’s system. |
**Error Code**
| Error Code | Description |
|-------------------------|-----------------------------------------------------------------------------------------------------------------------|
| err:player_not_found | player with this `username` does not exist |
| err:json_error | JSON data error. There will be a `data` field with more detail |
*Example of JSON request:*
```json
{
"username": "slot77_john"
}
```
*Example of JSON response:*
```json
{
"err": ""
}
```
## Logout All Players
To logout all logged in players.
**Note**:
* Normally, this API is used during Operator's maintenance, to make sure no player is playing, to prevent receiving `/bet`, `/result`, `/refund` requests during maintenance.
* This will logout player from game client, but due to auto reconnect (or player refreshes the game client), an `/auth` request will be sent from LitePlay Provider to Operator, and if this request success, player will be logged in again.
* If Operator turns on maintenance, then calling `logout`, no more step will need to be taken because `/auth` request from LitePlay Provider to Operator will just fail.
Endpoint: `/logout/all`
Method: `POST`
## Free Spins Bonus API
**Free Spins Bonus** (FSB) allows the player to play a specified number of free spins in a game. Free Spins created via Free Spins API may be configured to be played with a certain bet value specified for each game and currency. During Free Spins gameplay, bets are not deducted from the player's balance, but all wins are collected for the Free Spins Bonus in LitePlay’s system.
* Please note that not all games support FSB.
### Create Free Spin Bonus
The Operator can use this API to create a new Free Spins Bonus with the LitePlay’s games. In case of a network error Operator can send a repeated Create Free Spins requests. The LitePlay system will not create new FSB if there is an active FSB with the same bonus code.
**Note:**
* The `code` is unique and can be used only one time for same player username. Please make sure you’ve integrated the FSB in the proper way and won't reuse/award same `code` values in your logic.
* The total bet for each round is calculated as `bet` (bet per line) * number of lines.
Endpoint: `/api/fsb/create`
Method: `POST`
**Request Paramaters**
| Parameter | Data Type | Mandatory | Description |
| ------------ | --------- | --------- | ---------- |
| name | String | Required | Bonus name within the Operator’s system. No need to check unique within the brand. |
| code | String | Required | Bonus code within the Operator’s system. Should be unique within the brand. |
| start_date | DateTime | Required | Date and time when the free spins bonus will start. |
| end_date | DateTime | Required | Date and time when the free spins will expire.|
| valid_date | DateTime | Optional | Date and time when the bonus gets invalid and is unavailable for the player.|
| brand_id | Integer | Required | Brand active bonus code |
| number_of_spin | Integer | Required | Number of free game spins awarded. |
| game_list | Array | Required | List of **FreeSpinsGame Object** - the games associated with the bonus, with bet per line values for each currency. |
| player_list | Array | Required | List player will get bonus code |
**FreeSpinsGame Object**
| Parameter | Data Type | Mandatory | Description |
| --------- | --------- | --- | ----------------- |
| game_code | String | Required | Unique identifier for the game, e.g. vseldorado, vswanted, vsdogo, etc. associated with the free spins bonus. |
| bet| Decimal | Required | Value of bet per line in the specified currency, which will be applied during free spins |
| currency | String | Required | ISO 4217 currency code. |
**Response Parameters**
| Parameter | Data Type | Description |
| ----------- | --------- | ------------- |
| err | String | Error code.|
**Error Code**
| Error Code | Description |
| ------------------------- | ----------- |
| err:duplicated_bonus_code | Bonus code is already existed. |
| err:invalid_game | The games are not supported. |
| err:duplicate_player_list | Duplicate player list. |
| err:invalid_player_list | Invalid player. |
*Example of JSON request:*
```json
{
"name": "FSB20250305",
"code": "FSB20250305",
"start_date": "04/03/2025 15:30",
"end_date": "04/03/2025 15:30",
"valid_date": "04/03/2025 13:30",
"brand_id": 1,
"game_list": [
{
"game_code": "vshorrornights",
"currency": "IDR",
"bet": 400
}
],
"number_of_spin": 10,
"player_list": [
"huunt"
]
}
```
*Example of JSON response:*
*Success*
```json
{
"data": {},
"success": true
}
```
*Failed*
```json
{
"err": "err:duplicated_bonus_code"
}
```
### Update Free Spin Bonus
The Operator can use this API to update an existing Free Spins Bonus with the LitePlay’s games. In case of a network error Operator can send a repeated update Free Spins requests. The LitePlay system will not update new FSB if there is an active FSB with the same bonus code.
Endpoint: `/api/fsb/{bonus code id}/update`
Method: `POST`
**Response Parameters**
| Parameter | Data Type | Mandatory | Description |
| ------------ | --------- | --------- | ---------- |
| name | String | Required | Bonus name within the Operator’s system. No need to check unique within the brand. |
| code | String | Required | Bonus code within the Operator’s system. Should be unique within the brand. |
| start_date | DateTime | Required | Date and time when the free spins bonus will start. |
| end_date | DateTime | Required | Date and time when the free spins will expire.|
| valid_date | DateTime | Optional | Date and time when the bonus gets invalid and is unavailable for the player.|
| brand_id | Integer | Required | Brand active bonus code |
| number_of_spin | Integer | Required | Number of free game spins awarded. |
| game_list | Array | Required | List of **FreeSpinsGame Object** - the games associated with the bonus, with bet per line values for each currency. |
| player_list | Array | Required | List player will get bonus code |
**FreeSpinsGame Object**
| Parameter | Data Type | Mandatory | Description |
| --------- | --------- | --- | ----------------- |
| game_code | String | Required | Unique identifier for the game, e.g. vseldorado, vswanted, vsdogo, etc. associated with the free spins bonus. |
| bet| Decimal | Required | Value of bet per line in the specified currency, which will be applied during free spins |
| currency | String | Required | ISO 4217 currency code. |
**Response Parameters**
| Parameter | Data Type | Description |
| ----------- | --------- | ------------- |
| err | String | Error code.|
**Error Code**
| Error Code | Description |
| ------------------------- | ----------- |
| err:duplicated_bonus_code | Bonus code is already existed. |
| err:invalid_game | The games are not supported. |
| err:duplicate_player_list | Duplicate player list. |
| err:invalid_player_list | Invalid player. |
*Example of JSON request:*
```json
{
"name": "FSB20250305",
"code": "FSB20250305",
"start_date": "04/03/2025 15:30",
"end_date": "04/03/2025 15:30",
"valid_date": "04/03/2025 13:30",
"brand_id": 1,
"game_list": [
{
"game_code": "vshorrornights",
"currency": "IDR",
"bet": 400
}
],
"number_of_spin": 10,
"player_list": [
"huunt"
]
}
```
*Example of JSON response:*
*Success*
```json
{
"data": {},
"success": true
}
```
*Failed*
```json
{
"err": "err:duplicated_bonus_code"
}
```
### Delete Free Spins Bonus
The Operator can use this API to delete a new Free Spins Bonus in the LitePlay system. Free Spins Bonus will be deleted from the LitePlay system.
Endpoint: `/api/fsb/{bonus code id}/delete`
Method: `POST`
**Response Parameters**
| Parameter | Data Type | Description |
| ----------- | --------- | ------------- |
| err | String | Error code.|
*Example of JSON response*
```jsonld
{
"data": null,
"err": "",
"success": true
}
```
### Cancel Free Spins Bonus
The Operator can use this API to cancel an existing Free Spins Bonus in the LitePlay system. Free Spins Bonus will be canceled in the LitePlay system regardless of whether the player started to play them or not.
Endpoint: `/api/fsb/{bonus code id}/cancel`
Method: `POST`
**Response Parameters**
| Parameter | Data Type | Description |
| ----------- | --------- | ------------- |
| err | String | Error code.|
*Example of JSON response*
```jsonld
{
"data": null,
"err": "err:cannot_cancel_freespin_bonus_status_is_not_in_progress",
"success": false
}
```
### Get Free Spins Bonus List
The Operator can use this API to get all "Free Spins Bonus" from the LitePlay system .
Endpoint: `/api/fsb`
Method: `POST`
**Request Paramaters**
| Parameter | Data Type | Mandatory | Description |
| ----------- | --------- | --------- | -------------------------- |
| page | Integer | Required | Number of pages |
| page_size | Integer | Required | Number of records returned |
| sort_field | String | Required | Name of the field to sort (default: In-progress > Created > Given > Canceled), Start date, End date |
| sort_order | String | Required | Sort type ASC or DESC |
| keyword_search | String | Optional | Keyword search by name or code |
| status_search | String | Optional | Search status created, in-progress, given, canceled, leave blank to get all |
| brand_id | Integer | Required | Brand id to search |
**Response Parameters**
| Parameter | Data Type | Description |
| --------- | --------- | ----------- |
| total_size | Integer | Total Free Spin bonus |
| list | Array | List of all **FSB Object** |
| err | String | Error code. |
**FSB Object**
| Parameter | Data Type | Description |
| --------- | --------- | ----------- |
| id | Integer | Id of Free Spin bonus. |
| code | String | Bonus code that the Free Spins bonus |
| name | String | Bonus name that the Free Spins bonus |
| status | String | Status that the Free Spins bonus |
| brand_id | Integer | Brand active bonus code |
| free_spin_number | Integer | Number of free game spins awarded. |
| player_list | Array | List player will get that bonus code. |
| game_list | Array | List of **FreeSpinsGame Object** - the games associated with the bonus, with bet per line values for each currency. |
| start_date | DateTime | Date and time when the free spins bonus will start. |
| end_date | DateTime | Date and time when the free spins will expire.| |
| validity_date | DateTime | Date and time when the bonus gets invalid and is unavailable for the player |
| total_player_got_fsb | Integer | Total player got that Free Spin bonus |
| total_winning_amount | Integer | Total winning amount that Free Spin bonus |
| total_player_claimed | Integer | Total player claimed that Free Spin bonus |
| total_player_dont_claim | Integer | Total player don't claim Free Spin bonus |
| bet_in_game | decimal | bet in game |
| invalid_date | boolean | true or false |
| total_player_round | Integer | Total player round this Free Spin bonus |
| player_claimed_list | Array | list player claimed bonus code |
**FreeSpinsGame Object**
| Parameter | Data Type | Mandatory | Description |
| --------- | --------- | --- | ----------------- |
| game_code | String | Required | Unique identifier for the game, e.g. vseldorado, vswanted, vsdogo, etc. associated with the free spins bonus. |
| bet| Decimal | Required | Value of bet per line in the specified currency, which will be applied during free spins |
| currency | String | Required | ISO 4217 currency code. |
*Example of JSON request*
```jsonld
{
"page": 1,
"page_size": 30,
"sort_field": "status",
"sort_order": "ASC",
"keyword_search": "",
"status_search": "",
"brand_id":1
}
```
*Example of JSON response*
```jsonld
"data": {
"total_size": 1,
"list": [
{
"id": 4,
"code": "TestFSB",
"name": "Test2504",
"status": "given",
"brand_id": 1,
"free_spin_number": 5,
"player_list": [
"test1",
"test2",
"test3",
"test4"
],
"game_list": [
{
"game_code": "vsliondance",
"currency": "IDR",
"bet": "200"
},
{
"game_code": "vswildwildwest",
"currency": "IDR",
"bet": "200"
},
{
"game_code": "vsairstrikeattack",
"currency": "IDR",
"bet": "200"
}
],
"start_date": "25 Apr 2025 14:50:00",
"end_date": "25 Apr 2025 23:44:00",
"validity_date": "28 Apr 2025 18:44:00",
"total_player_got_fsb": 4,
"total_winning_amount": "0.0763",
"total_player_claimed": 0,
"total_player_dont_claim": 0,
"bet_in_game": "0",
"invalid_date": true,
"total_player_round": 5,
"player_claimed_list": null
}
]
},
"success": true
```
### Get Detail Free Spins Bonus
The Operator can use this API to get all "Free Spins Bonus" from the LitePlay system .
Endpoint: `/api/fsb/{bonus code id}`
Method: `POST`
**Response Parameters**
| Parameter | Data Type | Description |
| --------- | --------- | ----------- |
| data | Object | **FSB Object** |
| err | String | Error code. |
**FSB Object**
| Parameter | Data Type | Description |
| --------- | --------- | ----------- |
| id | Integer | Id of Free Spin bonus. |
| code | String | Bonus code that the Free Spins bonus |
| name | String | Bonus name that the Free Spins bonus |
| status | String | Status that the Free Spins bonus |
| brand_id | Integer | Brand active bonus code |
| free_spin_number | Integer | Number of free game spins awarded. |
| player_list | Array | List player will get that bonus code. |
| game_list | Array | List of **FreeSpinsGame Object** - the games associated with the bonus, with bet per line values for each currency. |
| start_date | DateTime | Date and time when the free spins bonus will start. |
| end_date | DateTime | Date and time when the free spins will expire.| |
| validity_date | DateTime | Date and time when the bonus gets invalid and is unavailable for the player |
| total_player_got_fsb | Integer | Total player got that Free Spin bonus |
| total_winning_amount | Integer | Total winning amount that Free Spin bonus |
| total_player_claimed | Integer | Total player claimed that Free Spin bonus |
| total_player_dont_claim | Integer | Total player don't claim Free Spin bonus |
| bet_in_game | decimal | bet in game |
| invalid_date | boolean | true or false |
| total_player_round | Integer | Total player round this Free Spin bonus |
| player_claimed_list | Array | list player claimed bonus code |
**FreeSpinsGame Object**
| Parameter | Data Type | Mandatory | Description |
| --------- | --------- | --- | ----------------- |
| game_code | String | Required | Unique identifier for the game, e.g. vseldorado, vswanted, vsdogo, etc. associated with the free spins bonus. |
| bet| Decimal | Required | Value of bet per line in the specified currency, which will be applied during free spins |
| currency | String | Required | ISO 4217 currency code. |
*Example of JSON response*
```jsonld
{
"data": {
{
"id": 4,
"code": "TestFSB",
"name": "Test2504",
"status": "given",
"brand_id": 1,
"free_spin_number": 5,
"player_list": [
"test1",
"test2",
"test3",
"test4"
],
"game_list": [
{
"game_code": "vsliondance",
"currency": "IDR",
"bet": "200"
},
{
"game_code": "vswildwildwest",
"currency": "IDR",
"bet": "200"
},
{
"game_code": "vsairstrikeattack",
"currency": "IDR",
"bet": "200"
}
],
"start_date": "25 Apr 2025 14:50:00",
"end_date": "25 Apr 2025 23:44:00",
"validity_date": "28 Apr 2025 18:44:00",
"total_player_got_fsb": 4,
"total_winning_amount": "0.0763",
"total_player_claimed": 0,
"total_player_dont_claim": 0,
"bet_in_game": "0",
"invalid_date": true,
"total_player_round": 5,
"player_claimed_list": null
}
},
"success": true
}
```
### Get List Player Free Spins Bonus
The Operator can use this API to get the list of players of a Free Spins Bonus.
Endpoint: `/api/fsb/{bonus code id}/player/list`
Method: `POST`
**Request Paramaters**
| Parameter | Data Type | Mandatory | Description |
| ---------- | --------- | --------- | ---------- |
| page | Integer | Required | Number of pages |
| page_size | Integer | Required | Number of records returned |
**Response Parameters**
| Parameter | Data Type | Description |
| --------- | --------- | ----------- |
| list | Array | List of all **Player Object** |
| sum | Object | **Sum Object** |
| total_size | integer | total player that Free Spins bonus |
| err | String | Error code. |
**Player Object**
| Parameter | Data Type | Description |
| --------- | --------- | ----------- |
| id | Integer | 0 or 1, 0 is player claimed fsb, 0 is player don't claim fsb |
| fsb_id | Integer | Free Spins Bonus id |
| member_id | Integer | Member id |
| username | String | Name player |
| game_code | String | game code |
| currency | String | Currency player |
| free_spin_rounds | Integer | free spin rounds |
| played_rounds | Integer | played rounds |
| winning_amount | Integer | winning amount USD |
| winning_amount_native | Integer | winning amount currency player |
| end_date | String | end date Free Spins Bonus |
| status | String | status |
**Sum Object**
| Parameter | Data Type | Description |
| --------- | --------- | ----------- |
| id | Integer | 0 or 1, 0 is player claimed fsb, 0 is player don't claim fsb |
| fsb_id | Integer | Free Spins Bonus id |
| member_id | Integer | Member id |
| username | String | Name player |
| game_code | String | game code |
| currency | String | Currency player |
| free_spin_rounds | Integer | free spin rounds |
| played_rounds | Integer | played rounds |
| winning_amount | Integer | winning amount USD|
| winning_amount_native | Integer | winning amount currency player |
| end_date | String | end date Free Spins Bonus |
| status | String | status |
### Add Players
The Operator can use this API to add players to the existing Free Spins Bonus. Free Spins Bonus will be available existing players.
Endpoint: `/api/fsb/{bonus code id}/add_player`
Method: `POST`
**Request Paramaters**
| Parameter | Data Type | Mandatory | Description |
| ---------- | --------- | --------- | ---------- |
| player_list | Array | Required | List of player username to add to the existing Free Spins Bonus, comma separated. |
**Response Parameters**
| Parameter | Data Type | Description |
| ----------- | --------- | ------------- |
| err | String | Error code.|
*Example of JSON request*
```jsonld
{
"player_list": ["ajinomoto","bet88_aurora","02943abd","batu777_240"]
}
```
*Example of JSON response*
```jsonld
{
"data": null,
"err": "err:err_freespin_bonus_not_found",
"success": false
}
```
# Operator Integration APIs
* LitePlay Provider will call these APIs, (LitePlay Provider -> Operator)
* Therefore, LitePlay Provider will give IP Address to Operator to whitelist
* Operator will implement these endpoints, to be called by LitePlay Provider (required)
* /auth
* /bet
* /result
* /refund
* /promo_win
* All APIs are in JSON format (`application/json`), POST method, and in HTTPS
* Authentication: please refer to [Hash Authentication](#Hash-Authentication)
* Fields will be in underscore_
* The timeout in LitePlay Provider is **10s**
* Special data type (apply to request/response data):
* `Integer`: this will use normal number data type from JSON (no quoted)
For example:`{"counter": 12}`
* `String`: use string data type from JSON (quoted)
For example:`{"name": "abc1234"}`
* `Decimal`: for money, rate fields, this use string data type from JSON (quoted)
For example: `{"credit": "2134.34"}`
* `DateTime`: use string data type from JSON (quoted).
Format will be `DD/MM/YYYY HH:mm:ssZ`.
If no `Z` (timezone) specific, the default `+0000` (UTC) will be used.
For example: `{"from": "15/01/2006 15:04:03+0700"}`
* `username` field:
* Identifier of the user within the Operator’s system. <br>Parameter value is case-sensitive
* Example: bet88_anh, 781362, playerABC, playerAbc (playerABC and playerAbc – are two different player accounts within LitePlay Provider system)
* `err` field:
* No `err` field/Empty `err` field means success.
* For list of error code, please see [Error Code List](#Error-Code-List)
* Some error will have additional data in `data` field, please also refer to [Error Code List](#Error-Code-List) for example.
* `data` field (optional):
* For all endpoint, a `data` field with valid json can be sent along for testing/debugging purpose, it will be recorded in LitePlay Provider system.
* Please do not send too much/sensitive data.
* For refund process, please check [Refund/Retry Process](#Refund/Retry-Process)
## Auth
When player goes to game site, LitePlay Provider will call this endpoint to verify player's authentication.<br>
Operator needs to:
* Using `token`, return the correct player data along with balance in response.
* Each player can only have one `currency_code`.
Endpoint: `/auth`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Description |
|------------|-----------|--------------------------------------------------------------------|
| token | String | This is the same `token` that Operator supplied in Launch Game URL |
| ip_address | String | The IP Address of the player |
**Response Parameters**
| Parameter | Data Type | Mandatory | Description |
|---------------|-----------|-----------|-----------------------------------------------------|
| balance | Decimal | Required | Current player balance |
| currency_code | String | Required | ISO 4217 currency code of player. For list of currencies, please see [Appendix B](#Appendix-B-Currencies) |
| username | String | Required | Identifier of the user within the Operator’s system |
| err | String | Optional | Error code |
| data | Object | Optional | Optional data for debug purpose |
**Error Code**
| Error Code | Description |
|-----------------------|--------------------------------------------------------------------------------------------------------------------------|
| err:invalid_signature | Mismatch signature in `HTTP HEADER` with signature generated from request. There will be a `data` field with more detail |
| err:token_not_found | No player is associated with this `token` |
| err:player_not_allow | Player is not allowed to play |
*Example of JSON request:*
```json
{
"token": "vdiswu8493hfdskljfo9ewu2r32joefihf89324u53hrfioqwehf",
"ip_address": "127.0.0.1"
}
```
*Example of JSON response:*<br>
*Success*
```json
{
"balance": "14200.00",
"currency_code": "IDR",
"username": "slot99_tom",
"err": ""
}
```
*Failed*
```json
{
"err": "err:token_not_found"
}
```
## Bet
LitePlay Provider is able to call this endpoint that will be provided by Operator, and send out the bet details to Operator.<br>
Operator needs to:
* Check and if not enough balance, return correct error `err:not_enough_balance`
* Deduct player's balance in Operator's system according to `amount` field and return the updated balance (`balance` field)
* A request with the same `reference` with past request should not be processed (substract player's balance, write to database again etc), and should return same `transaction_id`
* If Operator returns any `err` ***NOT*** in this list the bet will go into [Refund/Retry Process](#Refund/Retry-Process)
* `err:already_refund_transaction`
* `err:not_enough_balance`
* `err:bet_not_allow`
Endpoint: `/bet`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Description |
|-----------|-----------|-----------------------------------------------------|
| username | String | Identifier of the user within the Operator’s system |
| game_code | String | Game identifier for each game |
| round_id | String | Id of the round |
| amount | Decimal | Amount of the bet. Minimum is 0.00 |
| reference | String | Unique reference of this transaction |
| timestamp | DateTime | Bet time |
**Response Parameters**
| Parameter | Data Type | Mandatory | Description |
|----------------|-----------|-----------|--------------------------------------------------|
| balance | Decimal | Required | Real balance of the player after the transaction |
| transaction_id | String | Required | Unique transaction id from Operator side. |
| err | String | Optional | Error code |
| data | Object | Optional | Optional data for debug purpose |
**Error Code**
| Error Code | Description |
|--------------------------------|----------------------------------------------------------------------------------------------------------------|
| err:already_refund_transaction | For if this bet already got refunded. Check [Refund/Retry Process](#Refund/Retry-Process) for more information |
| err:not_enough_balance | Not enough balance for bet |
| err:bet_not_allow | This bet is not allow in Operator's side |
| err:player_not_allow | Player is not allowed to play |
*Example of JSON request:*
```json
{
"username": "slot77_john",
"game_code": "vseldorado01",
"round_id": "fdoerwu349230",
"amount": "1230.58",
"reference": "12344580",
"timestamp": "20/07/2021 09:20:35+0000"
}
```
*Example of JSON response:*
*Success*
```json
{
"transaction_id": "1482429190474",
"balance": "92009.99",
"err": ""
}
```
*Failed*
```json
{
"err": "err:not_enough_balance"
}
```
## Result
LitePlay Provider will use this endpoint to send to the Operator the winning result of a bet.If the Operator needs an endpoint for the loss result of a bet, the LitePlay provider will enable a toggle endpoint for the loss result of a bet.<br>
Operator needs to:
* Increase player's balance in Operator's system according to `amount` field, and return the updated balance (`balance` field)
* A request with the same `reference` with past request should not be processed (add to player's balance, write to database again etc), and should return same `transaction_id`
* If Operator returns any `err` at all, the result will go into [Refund/Retry Process](#Refund/Retry-Process)
Endpoint: `/result`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Description |
|-----------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| username | String | Identifier of the user within the Operator’s system. Parameter value is case-sensitive. |
| game_code | String | Game identifier for each game |
| round_id | String | Id of the round |
| amount | Decimal | Winning amount |
| reference | String | Unique reference of this transaction |
| parent_round_id | String | For Freespin Mode, this is the `round_id` of the origin round that won the free spins |
| timestamp | DateTime | Date and time when the result transaction is processed on the LitePlay Provider side |
| is_last_spin | String | Identifier status each result turns to spin. Each result turn spin will have the status True, For Freespin Mode, each result turn spin has the status False, and the last result has the status True |
**Response Parameters**
| Parameter | Data Type | Mandatory | Description |
|----------------|-----------|-----------|--------------------------------------------------|
| balance | Decimal | Required | Real balance of the player after the transaction |
| transaction_id | String | Required | Unique transaction id from Operator side. |
| err | String | Optional | error code |
| data | Object | Optional | Optional data for debug purpose |
*Example of JSON request:*
```json
{
"username": "slot77_john",
"game_code": "eldorado01",
"round_id": "48gfew443",
"amount": "1230.58",
"reference": "12344580",
"parent_round_id": "fsdkfjklewr",
"is_last_spin": "True",
"timestamp": "20/07/2021 09:20:35+0000"
}
```
*Example of JSON response:*
*Success*
```json
{
"transaction_id": "1482429190474",
"balance": "92009.99",
"err": ""
}
```
*Failed*
```json
{
"err": "something happend in my side (Operator side)"
}
```
## Refund
LitePlay Provider may use this API to rollback a bet transaction on the Operator side, in order to reverse the transaction and adjust player’s balance. When receive a Refund request Operator have to return money back to player’s balance.<br>
Operator needs to:
* Record this bet's `reference` as refund, and give back player's money base on the bet amount in the bet transaction
* If no bet with this `reference` exist, record this `reference` as refunded and return `err:already_refund_transaction` if receive a bet with same `reference` in the future
* Note that if you have not received a bet with this `reference` yet, this mean player's balance does not need to change
* For more information, check out [Refund/Retry Process](#Refund/Retry-Process)
* A request with the same `bet_reference` with past request should not be processed (add to player's balance, write to database again etc), and should return same `transaction_id`
* If Operator returns any `err` at all, the refund will be sent again (more info in [Refund/Retry Process](#Refund/Retry-Process))
Endpoint: `/refund`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Description |
|-----------------|-----------|-----------------------------------------------------------------------------------------|
| username | String | Identifier of the user within the Operator’s system. |
| bet_reference | String | Bet reference that need to be refunded |
| timestamp | DateTime | Date and time when the result transaction is processed on the LitePlay Provider side |
**Response Parameters**
| Parameter | Data Type | Mandatory | Description |
|----------------|-----------|-----------|--------------------------------------------------|
| balance | Decimal | Required | Real balance of the player after the transaction |
| transaction_id | String | Required | Unique transaction id from Operator side. |
| err | String | Optional | Error code |
| data | Object | Optional | Optional data for debug purpose |
*Example of JSON request:*
```json
{
"username": "slot77_john",
"bet_reference": "12344580",
"timestamp": "20/07/2021 09:20:35+0000"
}
```
*Example of JSON response:*
*Success*
```json
{
"transaction_id": "1482429190474",
"balance": "92009.25",
"err": ""
}
```
*Failed*
```json
{
"err": "something happend in my side (Operator side)"
}
```
## Promo Win
LitePlay Provider will use this endpoint to send to the Operator the bonus from event.<br>
Operator needs to:
* Increase player's balance in Operator's system according to `amount` field, and return the updated balance (`balance` field)
* A request with the same `reference` with past request should not be processed (add to player's balance, write to database again etc), and should return same `transaction_id`
* If Operator returns any `err` at all, the result will go into [Refund/Retry Process](#Refund/Retry-Process)
Endpoint: `/promo_win`
Method: `POST`
**Request Parameters**
| Parameter | Data Type | Description |
|-----------------|-----------|-----------------------------------------------------------------------------------------|
| username | String | Identifier of the user within the Operator’s system. Parameter value is case-sensitive. |
| promo_code | String | Game identifier for each game |
| amount | Decimal | Winning amount |
| reference | String | Unique reference of this transaction |
| timestamp | DateTime | Date and time when the result transaction is processed on the LitePlay Provider side |
**Response Parameters**
| Parameter | Data Type | Mandatory | Description |
|----------------|-----------|-----------|--------------------------------------------------|
| balance | Decimal | Required | Real balance of the player after the transaction |
| transaction_id | String | Required | Unique transaction id from Operator side. |
| err | String | Optional | error code |
| data | Object | Optional | Optional data for debug purpose |
*Example of JSON request:*
```json
{
"username": "slot77_john",
"promo_code": "christmas2021",
"amount": "1230.58",
"reference": "12344580",
"timestamp": "20/07/2021 09:20:35+0000"
}
```
*Example of JSON response:*
*Success*
```json
{
"transaction_id": "1482429190474",
"balance": "92009.99",
"err": ""
}
```
*Failed*
```json
{
"err": "something happend in my side (Operator side)"
}
```
# Refund/Retry Process
If a request times out or response with an error code that is not in the [Error Code List](#Error-Code-List), then LitePlay Provider will attempt to reconcile the action
* For an unsuccessful `bet` => `refund`
* For an unsuccessful `result` => `retry`
Please note that we will not have rollback for `result` (We will not claim back win amount after a `result`)
`Promo` request is the same as `Result` request
## Bet
* **If Operator returns any `err` *NOT* in this list the bet will go into refund**
* `err:already_refund_transaction`
* `err:not_enough_balance`
* `err:bet_not_allow`
* Bet will be retried 2 times with 5 seconds delay between attempts
* If bet is still not processed, LitePlay Provider will start the refund process, and an error will be sent to game client for player
## Refund
* This should run independently with the game session
* Will start after unsucessfully retried bet request 2 times
* There will be a delay (minimum 5s) between each refund request, and the delay will increase overtime (increase by 5s per time)
* First time will be a 5s delay
* Second time will be a 10s delay
* Third time will be a 15s delay
* etc
* Operator will return a successful response (empty `err` field) even if the bet has been canceled in the past or the bet has not reached the Operator system
* Operator should record the `bet_reference` in this refund request even though the bet request with this `reference` has not reached the Operator system, and reject future bet request with same `reference`
* This is because the refund request may come before the bet request
* **Response with a not empty `err` field will prompt the refund to be sent again**
* After 24h since the first refund request, the bet will be marked for manual refund
* Error code that will not trigger refund
* `err:not_enough_balance`
* `err:already_refund_transaction`
## Result
* **If Operator returns any `err` at all, the result will go into retry process**
* Result will be retried 2 times with 5 seconds delay between attempts
* If result is still not processed, LitePlay Provider will start the retried result process, and an error will be sent to game client for player
## Retried result
* This should run independently with the game session
* Will start after unsucessfully retried result request 2 times
* There will be a delay (minimum 5s) between each refund request, and the delay will increase over time (increase by 5s per time)
* First time will be a 5s delay
* Second time will be a 10s delay
* Third time will be a 15s delay
* etc
* This is the exact same result request, so Operator should process this the same
* After 24h since the first retried result request, the result will be marked for manual retry
# Hash Authentication
## Private APIs
To access LitePlay Provider APIs, you must create a base string firstly.
The base string is constructed by concatenating (separate by `|`)
* The HTTP method (`POST`)
* The path of the url (the endpoint, for example for request to api.google.com/api/v3/login, the path is `/api/v3/login`)
* The timestamp in unix timestamp
* The body of the request (request body always in JSON, so this is the JSON string. If you sent formatted JSON then this should be formatted too)
Then use the base string as the text and the secret key (issued by LitePlay Provider) as the key to generate the signature using HMAC.SHA256 to encrypt.
*Example in Go:*
```go
baseString := strings.Join([]string{httpMethod, path, timestamp, body}, "|")
mac := hmac.New(sha256.New, []byte(SECRET_KEY))
mac.Write([]byte(baseString))
resultHMAC := mac.Sum(nil)
signature := hex.EncodeToString(resultHMAC)
```
*Example in JavaScript:*
```javascript
var requestData = [httpMethod, requestPath, timestamp, requestBody].join("|");
var signature = CryptoJS.HmacSHA256(requestData, SECRET_KEY).toString();
```
*Example in PHP:*
```php
$requestData = join("|", array($httpMethod, $path, $timestamp, $body));
$signature = hash_hmac('sha256', $requestData, $secretKey);
```
When you have the signature, put into request header these params:<br>
```
signature: <signature>
apikey: <API_KEY> // issued by LitePlay Provider
timestamp: <timestamp> // in unix timestamp like the one we used to create the base string
```
Now you can call Private APIs.
## Operator Integration APIs
You will have to generate the `signature` for incoming request and compare with the signature receive in `HTTP HEADER`.<br>
Request with mismatch signature will have to be rejected with response `{"err":"err:invalid_signature"}`
# Verify API Integration
After finish API integration in Staging Environment, Operator is required to pass a test from LitePlay Provider<br>
Production Account will only be given to Operator that has passed the test.<br>
A test player account's `token` with balance 100 (any valid currency) need to be created from Operator system and sent to LitePlay Provider<br>
The test will cover:
* Hash Authentication (for Operator Integration APIs)
* Not exist `token` in `/auth` will be responded with `err:token_not_found`
* Duplicate `reference` (response with same `transaction_id`, no record/overwrite existing reference)
* Bet with not enough balance (correct response error)
* Bet/PromoWin/Result/Refund's response contains unique `transaction_id`
* Refund after bet (correct `balance` in response)
* Receive same bet (same reference) with already refunded bet will return correct response error
* Refund request comes before bet request
* Result request can have amount 0
# Error Code List
| Error Code | Has `data` field | Description |
|--------------------------------|------------------|-------------------------------------------------------------------------------------------------------------------------|
| err:invalid_signature | no | Mismatch signature in `HTTP HEADER` with signature generated from request. There will be a `data` field with more detail|
| err:invalid_api_key | no | Invalid API key |
| err:invalid_date_time_format | no | invalid `from`/`to` datetime format (correct format: `DD/MM/YYYY HH:mm:ssZ`, for example `20/07/2021 09:20:36+0000`) |
| err:token_not_found | no | No player is associated with this `token` |
| err:invalid_language | no | Language is not supported |
| err:not_enough_balance | no | Not enough balance for bet |
| err:already_refund_transaction | no | This bet has already been refunded |
| err:bet_not_allow | no | This bet is not allowed in Operator side |
| err:player_not_found | no | player with this `username` does not exist |
| err:json_error | yes | JSON data error. There will be a `data` field with more detail |
| err:player_not_allow | no | Player is not allowed to play |
*Example of `err:json_error` response:*
```json
{
"data": {
"username": "want string, got number"
},
"err": "err:json_error",
}
```
# Reports
# Diagrams
## Opening game flow diagram

**Flow**:
1. Player selects a game (is served by LitePlay Provider).
2. Operator generate a token and game URL, then return the game URL to player browser.
3. The game URL is loading in player browser for redirecting player to LitePlay Provider game server.
4. Game Provider verifies token received with URL by calling `/auth` endpoint in Operator server
5. Operator authenticates the player and responses player id and current balance.
6. If Operator responses error, authentication is not successful a player will receive an error message.
7. Game Provider finds player id in the database or creates a new player account using data from Operator's response
8. Provider game site shows the player can play the game.
## Playing game flow diagram

**Flow**:
1. Player clicks Spin button on the game screen.
2. Game Provider calls `/bet` endpoint in Operator server. If the Operator cannot handle the request (e.g. connection problem), Provider server will retry the request 3 times. <br>After that Refund request will be sent to the Operator server for cancelling bet until response from Operator server is received.
3. Operator verifies the request. If player has enough money to make a bet, deducts requested amount from the balance and returns updated player balance in the response. If there is not enough money, Operator returns an error.
4. Game Provider marks the bet as success.
5. Game Provider processes spin - gets new combination on the reels, checks combinations that trigger free spins or bonus game feature, calculates win amount, etc.
6. If player has a win on lines, Game Provider also calls `/result` endpoint in Operator server. If Operator cannot handle the request (e.g. connection problem), Provider server will retry the request until it receives a response from Operator server.
7. Operator verifies the request, adds money to player balance and returns updated player balance.
8. Game Provider marks the game round has ended.
9. Game Provider send result data to game client, containing updated player balance, reels result etc.
## Freespin game flow diagram

**Flow**:
1. Player clicks Spin button on the game screen.
2. Game Provider calls `/bet` endpoint in Operator server. If the Operator cannot handle the request (e.g. connection problem), Provider server will retry the request 3 times. After that Refund request will be sent to the Operator server for cancelling bet until response from Operator server is received.
3. Operator verifies the request. If player has enough money to make a bet, deducts requested amount from the balance and returns updated player balance in the response. If there is not enough money, Operator returns an error.
4. Game Provider marks the bet as success.
5. Game Provider processes spin - gets new combination on the reels, checks combinations that trigger free spins or bonus game feature, calculates win amount, etc.
6. If player has won free spin, Game Provider marks the game round as waiting to finish freespin.
7. Game Provider send result data to game client, containing reels result, amount of freespin won
8. Player continues to spin another round using freespin (this happens automatically in game site)
9. Game Provider processes spin - gets new combination on the reels, checks combinations that trigger free spins or bonus game feature, calculates win amount, etc.
10. Game Provider calls `/result` endpoint in Operator server, containing `payout` 0 and `parent_round_id` (the origin `round_id` that won freespin). If Operator cannot handle the request (e.g. connection problem), Provider server will retry the request until it receives a response from Operator server.
11. If player has a win on lines, it will be added to the payout of the origin `round_id` that won freespin (the result of this origin round has not been sent to Operator server)
12. Game Provider marks the game round (using freespin) has ended.
13. Game Provider send result data to game client, containing reels result etc.
14. Player continues to spin until run out of free spin
15. The last round with freespin, the result of the origin round will be sent to `/result` endpoint, contain total payout of the origin round and all subsequence rounds
16. Operator verifies the request, adds money to player balance and returns updated player balance.
17. Game Provider marks the game round and the origin game round have ended.
18. Game Provider send result data to game client, containing updated player balance, reels result, total payout of all freespin round etc.
# Appendix A: Languages
| Code | Language |
|------|------------|
| en | English |
| id | Indonesian |
| th | Thai |
# Appendix B: Currencies
| Code | Currency |
| ---- | ------------------------- |
| IDR | Indonesia Rupiah (1:1) |
| IDR1 | Indonesia Rupiah (1:1000) |
| THB | Thai Baht |
| MYR | Malaysian Ringgit |
| AUD | Australian Dollar |
| USD | United States Dollar |