---
# System prepended metadata

title: SV88 Cockfighting
tags: [SingleWallet, '  TransferWallet']

---

---
title: SV88 Cock API
tags: SingleWallet,  TransferWallet
version: 202429047
---
# Catalog

# share online
## Build Results After Minification

| File Type | Before Minify | After Minify | Reduction |
|-----------|---------------|--------------|-----------|
| JS | 9.9MB | 3.6MB | 🔻 ~63% |
| CSS | 2.378MB | 1.6MB | 🔻 ~31% |
| HTML | 4.8KB | 2.7KB | 🔻 ~44% |
| Polyfills | 80KB | 79KB | 🔻 ~1.4% |
| Sw-toolbox | 14.9KB | 14KB | 🔻 ~6% |
| **Total** | **12.377MB** | **5.295MB** | **🔻 ~57.2%** |



- [General Guideline](#General-Guideline) 
    - [Language](#Language)
    - [Currency](#Currency)
    - [Time zone and Date/Time](#Time-zone-and-Date/Time)
    - [Error Handling](#Error-Handling)
    - [Logging](#Logging)
    - [Postman APIs](#Postman-APIs)

- [Player](#Player) 
    - [Create Player](#CreatePlayer)
    - [Player Login](#PlayerLogin)
    - [Player Logout](#PlayerLogout)
- [TransferWallet](#TransferWallet)
    - [Balance](#Balance)
    - [Deposit](#Deposit)
    - [Withdraw](#Withdraw)
    - [Orders Status](#OrdersStatus)

- [SingleWallet](#SingleWallet)
    - [API](#API)
    - [Balance](#Balance)
    - [Bet](#Bet)
    - [Cancel](#Cancel)
    - [Settle](#Settle)
<style color=''>
    - [Resettle](#Resettle)
</style>

- [Bet Log](#BetLog)
    - [Bet History](#BetHistory)
- [Appendix](#Appendix) 
    - [Language](#Language-List)
    - [ErrorCode](#ErrorCode)
    - [BetStatus](#BetStatus)
    - [TransactonStatus](#TransactonStatus)
    - [TransactonType](#TransactonType)
    - [Currency](#Currency-List)   
    - [Suggestions for handling special issues of single wallet integration](#Single-wallet-integration-issues)            


# General Guideline 

## Language 
- System default language is English. Default language is applied when language is not 
specified.
## Currency 
-  Operator must provide the currency when request for the Operator Code. 
- Each OpCode support one type of currency only. 
- IDR and VND currency ratio is 1:1000 
- Available currency – MYR, CNY, IDR, THB, VND, KRW and JPY

**Note**
- If you need to integrate other currencies or games, please notify our business personnel and confirm terms and other details for cooperation. If you integrate other currencies or games without notification with us and generate data, we will see as you're in operation and calculate in the bill, please be noted, thank you.
## Time zone and Date/Time
- API: By uer time zone
- Backoffice: By user time zone
- Platform: By user time zone
- Request date and time format must include time zone: yyy-MM-dd'T'HH:mm:ssXXX
    - `yyyy`: Year in four digits (e.g., 2024).
    - `MM`: Month in two digits (01-12).
    - `dd`: Day of the month in two digits (01-31).
    - `'T'`: Literal character separating the date and time.
    - `HH`: Hour of the day in two digits (00-23).
    - `mm`: Minutes in two digits (00-59).
    - `ss`: Seconds in two digits (00-59).
    - `XXX`: Time zone offset from UTC (e.g., +07:00), indicating the difference in hours and minutes from Coordinated Universal Time (UTC). 
    * **Example**: 2024-06-02T00:00:00+07:00

## Error Handling

- All response should have error status to indicate whether there is error happened

**Common response**
```json

Succcess
{
     "errorCode": 0,
     "message": "Successfully executed"
}

Succcess with data
{
    "errorCode": 0,
    "message": "Successfully executed",
    "data": {
        "balance": 998665.75,
        "account": "lt001"
    }
}

Fail
{
     "errorCode": 16,
     "message": "INSUFFICIENT_BALANCE"
}

```

- In general, error code is 0 means “no error”. While all error Id others than 0 meanssome error happens.

## Logging
- All requests and response include server errors are logged into the database. URL, IP address and timestamp will be logged. The logs can be view via Backend Office web site. It is useful for check and verify the operation of the API service.

## Postman APIs
[Download Postman Transfer APIs](https://ssv88.net/imageok/TransferAPIs)


# Player
## CreatePlayer
##### URL: /api/merchant/players
##### Method: POST
**Request**
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| account | String | 32 | Y | Limit: Just allow alphanumeric [a-z, A-Z, 0-9, _ ] characters. | 
| password | String | 16 | Y | Player Password |  
| name | String | 32 | Y | Player Nickname<br>Limit: Not allow emoji characters|  
 

**Request sample**

```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "account":"playerAccount",
  "password":"[passWord]",
  "name":"playerName"
  }' \
  https://[SERVER]/api/merchant/players
```

**Response**

| Field Name | Type | Max Length | Mandatory | description |
| ------ | ------ | ------ | ------ | ------ |  
| errorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message |  

**Response sample**
```json
Success
{
    "errorCode": 0,
    "message": "Successfully executed"
}

Account is required
{
    "errorCode": 10,
    "message": "Account is required"
}

Player Name is required
{
    "errorCode": 12,
    "message": "Player Name is required"
}

Password is required
{
    "errorCode": 11,
    "message": "Password is required"
}

Unauthorized access
{
    "errorCode": "02",
    "message": "Unauthorized access"
}

Account exists
{
    "errorCode": 13,
    "message": "Account exists"
}

``` 
## PlayerLogin
##### URL: /api/merchant/player/login
##### Method: POST
**Request**

| Field Name | Type | Max Length | Mandatory | Description | 
| ------ | ------ | ------ | ------ | ------ | 
| account | String | 32 | Y | Player ID  | 
| password | String | 16 | Y | Player Password | 
| lang | String | 16 | N | Language code


:::info
If the agent has specified the language, use the language, otherwise log in with the default language.
:::

```json
//Login by default language
{
  "account":"playerAccount",
  "password":"[passWord]",
}
//Login by specific language
{
  "account":"playerAccount",
  "password":"[passWord]",
  "lang":"[player language]"
}
``` 


**Request sample**

```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "account":"playerAccount",
  "password":"[passWord]"
  }' \
  https://[SERVER]/api/merchant/player/login
```

**Response**

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ | 
| code | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error description | 
| data | Object |  | N |   Store the response data |

Data Structure

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| token | String | 255 | Y | player login token | 
| game_link | text | - | Y | game link | 

**Response sample**

```json
Login success
{
    "errorCode": 0,
    "message": "Successfully executed",
    "data": {
        "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJkZW1vIiwiZXhwIjoxNzIyMzA4MTc2LCJhdXRoIjoiUExBWUVSIiwiaWF0IjoxNzIyMjIxNzc2fQ.sz0M8xLXBVU5tYsbptghSgWtO9dfGp9eNnjA_eaUES7CoAKw5-1jCHeya6rpLMxC9vP1Pv9_1tl8g6j6liOFtw",
        "game_link": "https://ssv88.net?token=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJkZW1vIiwiZXhwIjoxNzIyMzA4MTc2LCJhdXRoIjoiUExBWUVSIiwiaWF0IjoxNzIyMjIxNzc2fQ.sz0M8xLXBVU5tYsbptghSgWtO9dfGp9eNnjA_eaUES7CoAKw5-1jCHeya6rpLMxC9vP1Pv9_1tl8g6j6liOFtw&lang=vi"
    }
}


Invalid username or password
{
    "errorCode": 17,
    "message": "Invalid username or password."
}

``` 
## PlayerLogout
##### URL: /api/merchant/player/logout
##### Method: POST
##### Request
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| account | String | 32 | N | Player ID  | 


**Request sample**

```shell
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "account":"playerAccount"
  }' \
  https://[SERVER]/api/merchant/player/logout
```

**Response**

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| errorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message |  

**Response sample**
```json
Logout success
{
    "errorCode": 23,
    "message": "Player already logout"
}

Account doesn't exist
{
    "errorCode": 14,
    "message": "Account doesn't exist"
}

```

---

# TransferWallet

## Balance
##### URL: /api/merchant/player/balance
##### Method: POST
##### Request
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| account | String | 32 | Y | Player account  | 

**Request sample**

```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "account":"[account]]"
  }' \
  https://[SERVER]/api/merchant/player/balance
```

**Response**

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| erorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message | 
| data | Object |  |  N |   Store the response data |

Data Structure

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| balance | Decimal | 18,2 | Y | Player balance |
| account | String | 32 | Y |  Player account |


**Response sample**
```json
Query Success
{
    "errorCode": 0,
    "message": "Successfully executed",
    "data": {
        "balance": 998665.75,
        "account": "lt001"
    }
}

Account is required
{
    "errorCode": 0,
    "message": "Account is required"
}

Unauthorized access
{
    "errorCode": 2,
    "message": "Unauthorized access"
}
``` 

##  Deposit
##### URL: /api/merchant/player/deposit
##### Method: POST
##### Request
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| account | String | 32 | Y | Player Account  | 
| merchantOrderNo | String | 32 | Y |  Merchant transaction id| 
| amount | Decimal | 18,2 | Y | Amount <br>Limit: 18 digits decimal. 2 digits after the decimal point. |  

**Request sample**

```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "account":"playerAccount",
  "merchantOrderNo":"[merchantOrderNo]",
  "amount":"[amount]"
  }' \
  https://[SERVER]/api/merchant/player/deposit
```

**Response**

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| code | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message |  
| data | Object |  |  N |   Store the response data |

Data Structure
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| merchantOrderNo | String | 32 | Y | Merchant transaction id |
| amount | Decimal | 18,2 | Y | Deposit amount |
| beforeAmount | Decimal | 18,2 | Y | Player beforeAmount |
| afterAmount | Decimal | 18,2 | Y | Player afterAmount |
| balanceType | String | 10 | Y | Refer to Transaction type|
| status | String | 10 | Y | Refer to Transaction status|

**Response sample**
```json
Success
{
    "errorCode": "00",
    "message": "Successfully executed",
    "data": {
        "merchantOrderNo": "merchantOrderNo1",
        "amount": 10000,
        "beforeAmount": 60000.00,
        "afterAmount": 70000.00,
        "balanceType": "DEPOSIT",
        "status": "SUCCESS"
    }
}

Amount is required
{
    "errorCode": 19,
    "message": "Amount is required"
}

Merchant Order Num is required
{
    "errorCode": 21,
    "message": "Merchant Order Num is required"
}

Amount must be greater than 0
{
    "errorCode": 20,
    "message": "Amount must be greater than 0"
}

Account doesn't exist
{
    "errorCode": 14,
    "message": "Account doesn't exist"
}

Merchant Order Num has existed
{
    "errorCode": 15,
    "message": "Merchant Order Num has existed"
}

Unauthorized access
{
    "errorCode": 2,
    "message": "Unauthorized access"
}

``` 

## Withdraw
##### URL: /api/merchant/player/withdraw
##### Method: POST
##### Request
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| account | String | 32 | Y | Player account | 
| merchantOrderNo | String | 32 | Y |  Merchant transaction id| 
| amount | Decimal | 18,2 | Y | Amount <br>Limit: Must be negative. 18 digits decimal. 2 digits after the decimal point. |  
 
**Request sample**

```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "account":"playerAccount",
  "merchantOrderNo":"[merchantOrderNo]",
  "amount":"-1000"
  }' \
  https://[SERVER]/api/merchant/player/withdraw
```

Response

| Field Name | Parameter Type | Max Length | Mandatory | Description | 
| ------ | ------ | ------ | ------ | ------ |  
| errorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message |  
| data | Object |  |  N |   Store the response data |

Data Structure
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| merchantOrderNo | String | 32 | Y | Merchant transaction id |
| amount | Decimal | 18,2 | Y | Deposit amount |
| beforeAmount | Decimal | 18,2 | Y | Player beforeAmount |
| afterAmount | Decimal | 18,2 | Y | Player afterAmount |
| balanceType | String | 10 | Y | Refer to Transaction Type|
| status | String | 10 | Y | Refer to Transaction Status|

**Response sample**
```json
Success
{
    "errorCode": 0,
    "message": "Successfully executed",
    "data": {
        "merchantOrderNo": "merchantOrderNoW1",
        "amount": 100,
        "beforeAmount": 9700.00,
        "afterAmount": 9600.00,
        "balanceType": "WITHDRAW",
        "status": "SUCCESS"
    }
}


Amount is required
{
    "errorCode": 19,
    "message": "Amount is required"
}

Merchant Order Num is required
{
    "errorCode": 21,
    "message": "Merchant Order Num is required"
}

Amount must be greater than 0
{
    "errorCode": 20,
    "message": "Amount must be greater than 0"
}

Account doesn't exist
{
    "errorCode": 14,
    "message": "Account doesn't exist"
}

Merchant Order Num has existed
{
    "errorCode": 15,
    "message": "Merchant Order Num has existed"
}


Account balance is not enough
{
    "errorCode": 16,
    "message": "Account balance is not enough"
}

Unauthorized access
{
    "errorCode": 2,
    "message": "Unauthorized access"
}

``` 

## OrdersStatus
##### URL: /api/merchant/player/check
##### Method: GET
:::info
* Order check restriction: After completing an order, please wait for 3 seconds before checking to avoid any issues of 'order does not exist'.<br/>
:::
##### Request
| Field Name | Parameter Type | Max Length | Mandatory | Description | 
| ------ | ------ | ------ | ------ | ------ |  
| merchantOrderNo | String | 32 | Y |  Merchant transaction id | 
 
**Request sample**

```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request GET \
  --data '{
  "merchantOrderNo":"[merchantOrderNo]"
  }' \
  https://[SERVER]/api/merchant/player/check
```

**Response**

| Field Name | Parameter Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ----------- |  
| errorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message |
| data | Object |  |  N |   Store the response data |

Data Structure
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| merchantOrderNo | String | 32 | Y | Merchant transaction id |
| amount | Decimal | 18,2 | Y | Deposit amount |
| beforeAmount | Decimal | 18,2 | Y | Player beforeAmount |
| afterAmount | Decimal | 18,2 | Y | Player afterAmount |
| balanceType | String | 10 | Y | Refer to Transaction Type|
| status | String | 10 | Y | Refer to Transaction Status|

**Response sample**
```json
Success
{
    "errorCode": 0,
    "message": "Successfully executed",
    "data": {
        "merchantOrderNo": "merchantOrderNoW11",
        "amount": 100,
        "beforeAmount": 9600.00,
        "afterAmount": 9500.00,
        "balanceType": "WITHDRAW",
        "status": "SUCCESS"
    }
}

Order doesn't exist
{
    "errorCode": 22,
    "message": "Order doesn't exist"
}

Unauthorized access
{
    "errorCode": 2,
    "message": "Unauthorized access"
}
``` 


# SingleWallet

## API
```shell
https://{merchant_server}/{action}
```



## Balance

* This function can help game providers to sync player’s balance periodically.
##### URL: /balance
##### Method: POST 

:::info
* Connection Timeout: 5 seconds
* Read Timeout: 5 seconds
:::


##### Request
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| account | String | 32 | Y | Player account  | 



**Request sample**

```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "account":"[account]]"
  }' \
  https://[SERVER]/api/merchant/player/balance
```

**Response**

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| erorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message | 
| data | Object |  |  N |   Store the response data |

Data Structure

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| balance | Decimal | 18,2 | Y | Player balance |
| account | String | 32 | Y |  Player account|

**Response sample**
```json
Success
{
    "errorCode": 0,
    "message": "Successfully executed",
    "data": {
        "balance": 998665.75,
        "account": "lt001"
    }
}

Fail
{
    "errorCode": 99,
    "message": "Internal server error",
}
```

## Bet
- Sending bet information to single wallet site.Every bet request needs response balance parameter to update player balance on the page.
- PlaceBet action will be start up after the player press "Confirm" button.
##### URL: /bet
##### Method: POST 
:::info
* Connection Timeout: 5 seconds
* Read Timeout: 6 seconds
:::
##### Request
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| balanceChangeId | String | 50| Y | Transaction Id  | 
| betId | String | 50 | Y | Bet Id  | 
| account | String | 32 | Y | Player account  | 
| amount | Decimal | 18,2| Y| Player amount  | 
| balanceType | String | 10 | Y | Refer to Transaction type|


**Request sample**
```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "balanceChangeId": "BCB240729153234F1LF",
  "betId": "B2407291532343P4L",
  "account": "lt001",
  "amount": -50,
  "balanceType": "BET"
}' \
  https://[SERVER]/api/merchant/player/bet
```


**Response**

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| erorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message | 
| data | Object |  |  N |   Store the response data |

Data Structure
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| balanceChangeId | String | 50| Y | Transaction Id  |
| betId | String | 50 | Y | Bet Id  | 
| account | String | 32 | Y | Player account  | 
| amount | Decimal | 18,2| Y| Player amount  | 
| beforeAmount | Decimal | 18,2 | Y | Player beforeAmount |
| afterAmount | Decimal | 18,2 | Y | Player afterAmount |


**Response sample**
```json
Success
{
    
  "errorCode": 0,
  "message": "Success",    
  "data": {
    "balanceChangeId": "abc123",
    "betId": "bet456",
    "account": "lt001",
    "amount": 100,
    "beforeAmount": 150,
    "afterAmount": 50
  }
}

Fail
{
  "errorCode": '16',
  "message":"Account balance is not enough"
}

Fail
{
  "errorCode": '62',
  "message":"Invalid Bet"
}


Fail
{
  "errorCode": '99',
  "message":"Internal server error"
}
```

## Cancel
* Sending cancel bet information to single wallet site.
* Cancelbet may be triggered because your response for "bet" is timeout
* Canbet will retry until success or operator returns error or retry expires
* Canbet retry policy: 5 retries with 1 min delay in between -> 10 retries
with 5 min delay in between -> 24 retries with 10 min delay in between
##### URL: https://{merchant_server}/cancel
##### Method: POST
:::info
* Connection Timeout: 5 seconds
* Read Timeout: 12 seconds
:::
##### Request
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| balanceChangeId | String | 50| Y | Transaction Id  | 
| betId | String | 50 | Y | Bet Id  | 
| account | String | 32 | Y | Player account  | 
| amount | Decimal | 18,2| Y| Player amount  | 
| balanceType | String | 10 | Y | Refer to Transaction type|


**Request sample**
```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "balanceChangeId": "BCB240729153234F1LF",
  "betId": "B2407291532343P4L",
  "account": "lt001",
  "amount": 50,
  "balanceType": "CANCEL"
}' \
  https://[SERVER]/api/merchant/player/cancel
```


**Response**

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| erorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message | 
| data | Object |  |  N |   Store the response data |

Data Structure
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| balanceChangeId | String | 50| Y | Transaction Id  |
| betId | String | 50 | Y | Bet Id  | 
| account | String | 32 | Y | Player account  | 
| amount | Decimal | 18,2| Y| Player amount  | 
| beforeAmount | Decimal | 18,2 | Y | Player beforeAmount |
| afterAmount | Decimal | 18,2 | Y | Player afterAmount |


**Response sample**
```json
Success
{
  "errorCode": 0,
  "message": "Success",    
  "data": {
    "balanceChangeId": "abc123",
    "betId": "bet456",
    "account": "lt001",
    "amount": 50,
    "beforeAmount": 200,
    "afterAmount": 150
  },
}


Fail
{
  "errorCode": '99',
  "message":"Internal server error"
}
```

## Settle
* This function is to send those transactions which are settled. Operator need to update player's balance based on updated transactions.
* Settle retry may be triggered because your response for "settle" is timeout. settle will retry until success or operator returns error or retry expires
* Settle retry policy: 4 retries with 1 min delay in between -> 10 retries
with 5 min delay in between -> 24 retries with 10 min delay in between.
##### URL: /settle
##### Method: POST

:::info
* Connection Timeout: 5 seconds
* Read Timeout: 12 seconds
:::
##### Request


| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| data | Array |  |  N |   Store the request arrray data |

Data structure
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| balanceChangeId | String | 50| Y | Transaction Id  | 
| betId | String | 50 | Y | Bet Id  | 
| account | String | 32 | Y | Player account  | 
| amount | Decimal | 18,2| Y| Player amount  | 
| balanceType | String | 10 | Y | Refer to Transaction type|


**Request sample**
```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request POST \
  --data '{
  "data": [
    {
      "balanceChangeId": "BCB240729153234F1LA",
      "betId": "B2407291532343P4A",
      "account": "lt001",
      "amount": 50,
      "balanceType": "SETTLED"
    },
    {
      "balanceChangeId": "BCB240729153234F1LF",
      "betId": "B2407291532343P4L",
      "account": "lt002",
      "amount": 20,
      "balanceType": "SETTLED"
    }
  ]
}
' \
  https://[SERVER]/api/merchant/player/settle
```


**Response**

| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| erorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message | 
| data | Array |  |  N |   Store the request arrray data |
| errors | Array |  |  N |   Store the request arrray data |

Data Structure
| Field Name | Type | Max Length | Mandatory | Description |
| ------ | ------ | ------ | ------ | ------ |  
| balanceChangeId | String | 50| Y | Transaction Id  |
| betId | String | 50 | Y | Bet Id  | 
| account | String | 32 | Y | Player account  | 
| amount | Decimal | 18,2| Y| Player amount  | 
| beforeAmount | Decimal | 18,2 | Y | Player beforeAmount |
| afterAmount | Decimal | 18,2 | Y | Player afterAmount |


**Response sample**
```json
Success
{
  "errorCode": 0,
  "message": "Success",    
  "data": [
    {
      "balanceChangeId": "BCB240729153234F1LA",
      "betId": "B2407291532343P4A",
      "account": "lt001",
      "amount": 50,
      "beforeAmount": 200,
      "afterAmount": 250
    },
    {
      "balanceChangeId": "BCB240729153234F1LF",
      "betId": "B2407291532343P4L",
      "account": "lt002",
      "amount": 20,
      "beforeAmount": 200,
      "afterAmount": 220
    }
  ]

}


Fail
{
    
  "errorCode": 60,
  "message": "Success but content failed"    
  "data": [
    {
      "balanceChangeId": "BCB240729153234F1LA",
      "betId": "B2407291532343P4A",
      "account": "lt001",
      "amount": 50,
      "beforeAmount": 200,
      "afterAmount": 250
    }
  ],
  "errors": [
    {
      "balanceChangeId": "BCB240729153234F1LF",
      "betId": "B2407291532343P4L",
      "account": "lt002",
      "amount": 20,
      "beforeAmount": 200,
      "afterAmount": 200
    }
  ]
}


Fail
{
  "errorCode": '99',
  "message":"Internal server error"
}
```

### Settle & Cancel：

##### Please note: The 'Settlement' and 'Cancel' APIs only reflect the bet status on our platform. Merchants should determine on their own, whether the corresponding transactions should be charged or canceled. Our platform does not specify nor influence the handling method on the merchant side.




# BetLog

## BetHistory
##### URL: /api/merchant/bets
##### Method: GET

:::info
* Limit Frequency: request once every 10 seconds
* Interval: Maximum 1 hour (interval between start_time and end_time)
* Date limit: Maximum 100 days
:::

##### Params data
| Field Name | Parameter Type | Max Length | Mandatory | Description | 
| ------ | ------ | ------ | ------ | ------ |  
| time_type | String | 16 | N | Searching time type ，<br>(Default is "bet_at", ["bet_at", "settled_at"]) |
| start_time | datetime | 20 | Y | Start_time of date searching <br> Time with timezone <br> Format: yyyy-MM-dd'T'HH:mm:ssXXX <br> Example: 2024-06-02T00:00:00+07:00 | 
| end_time | datetime | 20 | Y | End_time of date searching <br> Time with timezone <br> Format: yyyy-MM-dd'T'HH:mm:ssXXX <br> Example: 2024-06-02T00:00:00+07:00  | 
| page | integer | 11 | Y | Search Page  | 
| account | String | 32 | N | Player account | 
| page_size | integer | 11 | N | Number of data per page（Default value = 500，Max = 10000） | 


**Request sample**

```json
curl --header "Content-Type:application/json" \
  --header "Accept: application/json" \
  --header "X-API-KEY:[apiPrivateKey]" \
  --request GET \
  --data '{
  "start_time":"2021-08-20T00:00:00Z",
  "end_time":"2021-08-20T01:00:00Z",
  "account": "[player_account]",
  "page":1
  }' \
  https://[SERVER]/api/merchant/bets
```

**Response**
| Field Name | Parameter Type | Max Length | Mandatory | Description | 
| ------ | ------ | ------ | ------ | ----------- |  
| errorCode | Integer|  | Y | Error code | 
| message | String | 255 | Y | Error message |  
| current_page | Integer|  | Y | Current page | 
| total_page | Integer|  | Y | Total page | 
| total_count | Integer|  | Y | Total count | 
| data | array | - | N | bets data |  

Data structure

| Field Name | Parameter Type | Max Length | Description | 
| ------ | ------ | ------ | ----------- |  
| orderNo | String | 255 | Bet Id  (unique)|
| fightNo | Integer | 5 | Fight number |  
| betOn | String | 10 | Bet on MERON, BDD, WALA |  
| account | String | 32 |  Player Account | 
| status | String | 5 | Bet status|
| odd | Decimal | 5,2 | Odd | 
| betAmount | Decimal | 18,2  | Bet Amount | 
| winLose | Decimal | 18,2  | Net income  | 
| betReturn | Decimal | 18,2  | betReturn  = <br>betAmount + winLose <br><br>Note: When status is `BETTED` the betReturn is `null`  | 
| validAmount | Decimal | 18,2  | Valid amount |
| winner | String | 10 | Game result MERON, BDD, TBD, WALA <br><br>  When game haven't been finished, the result is `null`|  
| createdAt | datetime | 6 | Bet Time | 
| settledAt | datetime| 6 | Settle Time |

**Response sample**
```json
Success
{
  "errorCode": 0,
  "message": "Successfully executed",
  "current_page": 1,
  "total_page": 1,
  "total_count": 4,
  "data": [
        {
        {
            "orderNo": "B2407020627237UW4",
            "fightNo": 3,
            "betOn": "MERON",
            "account": "demo",
            "status": "SETTLED",
            "odd": 0.95,
            "betAmount": 100.00,
            "winLose": 95.00,
            "betReturn": 195.00,
            "validAmount": 100.00,
            "winner": "MERON",
            "createdAt": "2024-07-02T13:27:23.009501+07:00",
            "settledAt": "2024-07-02T13:30:25.205669+07:00"
        }
    ]
}

Fail
{
    "errorCode": 41,
    "message": "Start time is required"
}

Fail
{
    "errorCode": 42,
    "message": "End time is required"
}

Fail
{
    "errorCode": 43,
    "message": "Page is required"
}

Fail
{
    "errorCode": 2,
    "message": "Unauthorized access"
}


``` 
 
```json

BETTED
{
    "orderNo": "B24070214014635ME",
    "fightNo": 5,
    "betOn": "MERON",
    "account": "demo",
    "status": "BETTED",
    "odd": 0.95,
    "betAmount": 20.00,
    "winLose": null,
    "betReturn": null,
    "validAmount": 20.00,
    "winner": null,
    "createdAt": "2024-07-02T21:01:46.882307+07:00",
    "settledAt": null
}

SETTLED
{
    "orderNo": "B2407020627237UW4",
    "fightNo": 3,
    "betOn": "MERON",
    "account": "demo",
    "status": "SETTLED",
    "odd": 0.95,
    "betAmount": 100.00,
    "winLose": 95.00,
    "betReturn": 195.00,
    "validAmount": 100.00,
    "winner": "MERON",
    "createdAt": "2024-07-02T13:27:23.009501+07:00",
    "settledAt": "2024-07-02T13:30:25.205669+07:00"
}

CANCEL
{
    "orderNo": "B2407020627237UW3",
    "fightNo": 3,
    "betOn": "MERON",
    "account": "demo",
    "status": "SETTLED",
    "odd": 0.95,
    "betAmount": 100.00,
    "winLose": 95.00,
    "betReturn": 195.00,
    "validAmount": 100.00,
    "winner": "MERON",
    "createdAt": "2024-07-02T13:27:23.009501+07:00",
    "settledAt": "2024-07-02T13:30:25.205669+07:00"
}

FAILED
{
    "orderNo": "B2407020627237UW6",
    "fightNo": 3,
    "betOn": "MERON",
    "account": "demo",
    "status": "FAILED",
    "odd": 0.95,
    "betAmount": 100.00,
    "winLose": 95.00,
    "betReturn": 195.00,
    "validAmount": 100.00,
    "winner": "MERON",
    "createdAt": "2024-07-02T13:27:23.009501+07:00",
    "settledAt": "2024-07-02T13:30:25.205669+07:00"
}




```


# Appendix

## Language List

| Code | Language |
| ------ | ------ |
| en | English |
| cn | 中文 |
| vi | Tiếng Việt |
| jp | 日本語 |
| th | ไทย |
| es | ESPAÑOL |
| ms | Malay |
| id | Indonesia |
| kh | Khmer |


## ErrorCode

| Code | Error code |Error message | Error type |
|------|-------|---------|-----------|
| SUCCESS | 0 | Successfully executed | ALL |
| INVALID_TOKEN | 2 | Unauthorized access | ALL |
| INVALID_IP | 3 | Check permission failed | ALL |
| SYSTEM_MAINTENANCE | 4 | System is under maintenance | ALL |
| ACCOUNT_REQUIRED | 10 | Account is required | ALL |
| PASSWORD_REQUIRED | 11 | Password is required | ALL |
| NAME_REQUIRED | 12 | Player Name is required | ALL |
| ACCOUNT_EXIST | 13 | Account exists | ALL |
| ACCOUNT_DOES_NOT_EXIST | 14 | Account doesn't exist | ALL |
| ORDER_NUM_EXISTS | 15 | Merchant Order Num has existed | ALL |
| INSUFFICIENT_BALANCE | 16 | Account balance is not enough | ALL |
| INVALID_LOGIN | 17 | Invalid username or password | ALL |
| NO_SUCH_LANGUAGE | 18 | No this language | ALL |
| AMOUNT_REQUIRED | 19 | Amount is required | TRANSFER |
| AMOUNT_INVALID | 20 | Amount must be greater than 0 | TRANSFER |
| ORDER_NUM_REQUIRED | 21 | Merchant Order Num is required | TRANSFER |
| ORDER_NOT_EXIST | 22 | Order doesn't exist | TRANSFER |
| PLAYER_ALREADY_LOGGED_OUT | 23 | Player already logout | SEAMLESS |
| TIME_TYPE_NOT_EXIST | 40 | Time type doesn't exist | ALL |
| START_TIME_REQUIRED | 41 | Start time is required | ALL |
| END_TIME_REQUIRED | 42 | End time is required | ALL |
| PAGE_REQUIRED | 43 | Page is required | ALL |
| INVALID_START_TIME_FORMAT | 44 | Start time must format yyyy-MM-dd'T'HH:mm:ssXXX | ALL |
| INVALID_END_TIME_FORMAT | 45 | End time must format yyyy-MM-dd'T'HH:mm:ssXXX | ALL |
| PAGE_SIZE_INVALID | 46 | Page Size must be between 1 and 10000 | ALL |
| PAGE_NUMBER_INVALID | 47 | Page must be greater than 0 | ALL |
| SUCCESS_BUT_CONTENT_FAILED | 60 | Success but content failed | SEAMLESS |
| ACCOUNT_IS_LOCKED | 61 | Account is locked | SEAMLESS |
| INVALID_BET | 62 | Invalid Bet | SEAMLESS |
| OTHER_EXCEPTIONS | 100 | Internal server error | ALL |

## BetStatus


| Status  | Description                                     | Type |
|---------|-------------------------------------------------|------|
| INIT    | The bet has been created but not yet processed. | SEAMLESS  |
| FAILED  | The bet has failed due to an error or invalid conditions. | SEAMLESS  |
| BETTED  | The bet has been successfully placed.           | ALL  |
| SETTLED | The bet has been settled and the outcome determined. | ALL  |
| CANCEL  | The bet has been cancelled.                     | ALL  |



## TransactonStatus

| Status  | Description                                     | Type |
|---------|-------------------------------------------------|------|
| INIT    | The balance operation has been initiated but not yet processed. | SEAMLESS  |
| PENDING | The balance operation is currently pending because bet timeout or settle timeout and awaiting retry action. | SEAMLESS  |
| FAILED  | The balance operation has failed due to an error return from operator | SEAMLESS  |
| EXPIRED | The balance operation has expired retry and awaiting manual retry action. | SEAMLESS  |
| SUCCESS | The balance operation has been successfully completed. | ALL  |
| ERROR   | An error occurred during the balance operation | SEAMLESS  |

## TransactonType

| Status   | Description                                     | Type |
|----------|-------------------------------------------------|------|
| CANCEL   | Cancel bet        | SEAMLESS  |
| BET      | The balance operation is related to a bet.      | ALL  |
| SETTLED  | The balance operation is related to a settled bet. | ALL  |
| DEPOSIT  | The balance operation is a deposit.             | ALL  |
| WITHDRAW | The balance operation is a withdrawal.          | ALL  |


## Currency List

| Currency ID | ISO Code | ISO Name           |
|-------------|----------|--------------------|
| 1           | SGD      | Singapore Dollar   |
| 2           | MYR      | Malaysian Ringgit  |
| 3           | USD      | US Dollar          |
| 4           | THB      | Thai Baht          |
| 5           | HKD      | Hong Kong Dollar   |
| 6           | EUR      | Euro               |
| 9           | AUD      | Australian Dollar  |
| 12          | GBP      | British Pound      |
| 13          | RMB      | Chinese Renminbi   |
| 15          | IDR      | Indonesia Rupiah   |
| 32          | JAP      | Japan Yen          |
| 41          | CHF      | Swiss Franc        |
| 45          | WON      | Korean Won         |
| 46          | BND      | Brunei Dollar      |
| 49          | MXN      | Mexican Peso       |
| 50          | CAN      | Canadian Dollar    |
| 51          | VND      | Vietnamese Dong    |
| 52          | DKK      | Danish Krone       |
| 53          | SEK      | Swedish Krona      |
| 54          | NOK      | Norwegian Krone    |
| 55          | RUB      | Russian Ruble      |
| 56          | PLN      | Polish Zloty       |
| 57          | CZK      | Czech Koruna       |
| 58          | RON      | Romanian Leu       |
| 61          | INR      | Indian Rupee       |
| 70          | MMK      | Myanmar Kyat       |

# Single wallet integration issues

There are some situations you might encounter in the production environment. We provide corresponding suggestions for each case below so that your technical team can prepare solutions in advance.

## A. Financial Data Disputes

If any issue causing financial data dispute occurs and cannot be handled immediately due to technical difficulties from your side in the production environment, you need to accept the final decision from our side if a consensus cannot be reached.

## B. Continuous Transaction Issues

If any production issue occurs and causes continuous transaction loss and transaction stuck due to technical difficulties from your side, and we cannot reach your technical team immediately for effective responses and solutions, please be informed that we will stop your single wallet service to avoid worse situations that affect player experiences until the technical problem is solved.

## Real Case Scenarios

Regarding our API notification practices in real cases, you might have situations as below. Please confirm that you can handle them correctly.

| No.  | Description | Details |
| ---- | ----------- | ------- |
| 1    | **Normal Case**: You will receive a bet request first then receive cancelBet. | **Situation**: If SV88 did not receive the correct response of bet request within the limit time from the Operator (response timeout).<br><br>**Solution**: If the bet transaction has been accepted by the operator (the balance was debited), the cancelBet for the transaction (with the same transactionId/balanceChangeId) must be processed. The balance should be credited based on the bet amount. |
| 2    | **Exceptional Case**: You receive cancelBet first then only receive bet. | **Situation**: This case might happen because the network is not stable.<br><br>**Example**:<br>1. SV88 sent a bet request to your side.<br>2. Network is not stable.<br>3. Your response for bet to SV88 was timeout.<br>4. SV88 sent a cancelBet request.<br>5. Network problem, you received cancelBet first but no bet request yet.<br><br>**Solution**: If a cancelBet is received with a transactionId/balanceChangeId that does not match any stored bet transaction, the bet may still come at a later point to be reversed. Therefore, the operator must hold onto this cancelBet until a matching bet call does arrive or store it the same time you specify to keep the bet transaction. One way to solve this issue is by storing this transactionId/balanceChangeId along with other transactionId/balanceChangeIds that have already been processed. This way, if a bet is received with the same transactionId/balanceChangeId, it will not process. |
| 3    | **Exceptional Case**: You receive cancelBet first but there is no bet for it. | **Situation**: This case might happen when the network has a problem.<br><br>**Example**:<br>1. SV88 sent a bet request to your side.<br>2. Network is not stable, bet requests disappear.<br>3. Your response for bet to SV88 was timeout.<br>4. SV88 sent a cancelBet request.<br>5. Network problem, you received cancelBet first but no bet request yet.<br><br>**Solution**: In this case, we recommend that you handle this in the same way as Case 2. |
| 4    | **Retry Attempts for cancelBet** | **Situation**: If we are failing to get an expected response of cancelBet from you, we will keep sending retries to you until you receive.<br><br>**Solution**: Please make sure your system can handle it and cancel the bet transaction using the same transactionId/balanceChangeId with cancelBet, then responding successfully to us after you verify.<br><br>**Expected response from Operator**:<br>``[cancelBet]``<br>``errorCode: 0``
| 5    | **Failed Bets Due to Insufficient Balance** | **Situation**: If the bets failed due to balance being insufficient or other limits of bet on your side, SV88 will not request cancelBet in other ways.<br><br>**Solution**: Please confirm that your system can store and verify these Bets Failed Transactions automatically.<br><br>**SV88 will request cancelBet in these situations**:<br>1. Response for bet from Operator is timeout.<br>2. Game providers sent cancelBet requests to SV88.<br>3. Your bet response for cancelBet is not timeout, but HTTP code from your side is not 200, SV88 will request cancelBet. |
| 6    | **Duplicate Requests** | **Situation**: If you received a duplicate request which has already been successfully replied to SV88 (except for bet, which won’t be retried).<br><br>**Solution**: Please make sure that your system can receive it and will not update the balance again, and respond with status: 0 to us. Any other status than 0000, SV88 will recognize this response as invalid, and we will keep sending retry requests to you until you receive.<br><br>**Expected response from Operator**:<br>``status: 0`` |

Please help to confirm if you have prepared the storage environment completely. In other words, you can receive and store any request from SV88. If not, please build it up first.

The reason is for you to have real-time monitoring through abnormal logs and a backup solution to let you restore data you need from your log file.

**Example:** You can ensure that your system log will save correctly while you receive bet then respond 0 and balance to us. There will be no drop or deleted transactions from bet, so that it can be helpful for not losing any data of settle / bet / cancel, etc.





