# 更新記錄 ### 2024/12/12 - 新增取得分鐘統計資料 api - 更新餘額功能僅接受小數點後2位 # 遊戲API 遊戲相關 API 網址請使用我方提供之 API 網址 # 安全性 ## 存取憑證(token) > **取得進入存取憑證** 每10分鐘會失效 GET ``` /token ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Operator | 字串 | O | 經營方代碼 | | X-Key | 字串 | O | 經營方API密鑰 | - 標頭-範例: ```json { "X-Operator": "op1", "X-key": "aqA12Wsqa341" } ``` - 請求-範例: `http://sample.domain.com/token` ### Success 200 | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 物件[] | O | 產生存取憑證 | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "token": "55xBgeODPYO7q...fNwXlJTsqRU4NZ4bmKLD" } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | Forbidden | X-Operator Or X-Key 錯誤 | 403 | | Unauthorized | 驗證未通過 | 401 | | Bad Request | 提供資料未正確 | 400 | | Token Expired | 密鑰無效 | 401 | | Operator invalid | X-Operator無效 | 401 | | Internal Server Error | 伺服器發生問題 | 500 | | Ip location not allowed | IP位置不允許 | 403 | --- # 進入遊戲流程 ## 註冊 > **註冊新的使用者** POST ``` /register ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | username | 字串 | O | 用戶名.格式: 英數字(禁止使用特殊符號)最小長度: 5, 最大長度:64 | | email | 字串 | X | 使用者郵箱 | | birthday | 日期 | X | 使用者出生日期ISO-8601 格式 | | country | 字串 | X | 國籍代碼預設Taiwan | | fullname | 字串 | X | 使用者於遊戲中顯示之名稱(未設定以username顯示) | | language | 字串 | X | 遊戲語言: zh-cn, zh-tw, en, vn, th (預設為商戶設定之語系)| - 請求-範例: ```json { "username": "myuser123", "country": "China", "fullname": "My User", "language": "zh-cn", "email": "myuser123@test.com", "birthdate": "1992-02-18" } ``` - 回應-成功: ```json HTTP/1.1 200 Created {} ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | Unauthorized | 驗證未通過 | 401 | | Bad Request | 提供資料未正確 | 400 | | Username is required | 用戶名稱必填 | 400 | | Email is required | 用戶email必填 | 400 | | Language not allowed | 未支援語系 | 400 | | user exists | user 已存在 | 400 | | invalid parameter | 提供參數錯誤 | 400 | | Token Expired | 密鑰無效 | 401 | | Internal Server Error | 伺服器發生問題 | 500 | | InternalServerError | 伺服器發生問題 | 500 | --- ## 取得所有供應商 > **取得遊戲供應商資料列表** GET ``` /game-providers ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | rows | 整數 | X | 回傳記錄筆數預設10 | | page | 整數 | X | 頁數預設1 | | sidx | 字串 | X | 排序的欄位名稱預設id | | sord | 字串 | X | 排序樣式預設asc允許值: "asc", "desc" | - 請求-範例: ``` http://sample.domain.com/game-providers http://sample.domain.com/game-providers?page=2 http://sample.domain.com/game-providers?page=1&rows=10 http://sample.domain.com/game-providers?page=1&rows=10&sidx=name&sord=desc ``` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | gameProviders | 物件[] | 遊戲供應商列表 | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "gameProviders": [ { "id": "1", "name": "Game Provider 1", "code": "gp1" }, { "id": "2", "name": "Game Provider 2", "code": "gp2" } ], "meta": { "totalRecords": 2, "totalPages": 2, "currentPage": 1, "hasPrevious": false, "hasNext": true } } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | invalid token | 無效Token | 401 | | forbidden Gameprovider | 遊戲商錯誤 | 401 | | InternalServerError | 內部服務器錯誤 | 500 | --- ## 取得餘額 > **取得用戶在供應商的餘額** GET ``` /game-providers/:providerId/balance ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | providerId | 整數 | O | 遊戲供應商id | ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | username | 字串 | O | 用戶名 | - 請求-範例: `http://sample.domain.com/game-providers/1/balance?username=myuser123` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balance | 字串 | 即時餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balance": "100.00", "status": "Enabled", "playing": "no" } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | invalid token | 無效Token | 401 | | Missing parameter | 參數不可為空 | 403 | | User not found | 會員不存在 | 403 | | Forbidden | 遊戲商錯誤 | 403 | | InternalServerError | 內部服務器錯誤 | 500 | --- ## 更新餘額 > **更新用戶在供應商的餘額** POST ``` /game-providers/:providerId/balance ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | providerId | 整數 | O | 遊戲供應商 id | ### 參數(Body) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | username | 字串 | O | 用戶名 | | balance | 浮點數(小數後2位) | O | 被加或被減數大於0,僅支援小數後2位 | | action | 字串 | O | 提款或取款代碼無效代碼預設成IN允許值: "IN", "OUT" | | transferId | 字串 | O | 經營方轉賬交易單號 | - 請求-範例: ```json { "username": "sampop01", "balance": 500, "action": "out", "transferId": "sampleTransfercode" } ``` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balance | 字串 | 最新余額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balance": "1.00" } } ``` ### 錯誤 | 名稱 | 描述 | HTTP Status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | invalid token | 無效Token | 400 | | invalid parameter | 錯誤參數設定 | 403 | | IncompleteParameter | 參數設定不完整 | 403 | | Prohibited to transfer while game in progress | 遊戲中禁止轉入/出 | 403 | | Missing parameter | 數值不可為空 | 403 | | Only accepts 2 decimal places | 僅接受小數後2位 | 403 | | User not found | 會員不存在 | 404 | | transferId already exists | 交易單號已經存在 | 400 | | forbidden | 遊戲商錯誤 | 500 | | Transfer failed | 轉賬失敗 | 400 | | InternalServerError | 內部服務器錯誤 | 500 | | Internal Server Error | 內部服務器錯誤 | 500 | | User balance has been blocked | 用戶餘額鎖定 | 401 | --- ## 取得遊戲列表 > **取得遊戲列表** GET ``` /games ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | provider | 整數 | O | 遊戲供應商id | | category | 字串 | X | 遊戲分類 | | rows | 整數 | X | 回傳記錄筆數預設50 | | page | 整數 | X | 頁數預設1 | | sidx | 字串 | X | 排序的欄位名稱預設id | | locale | 字串 | X | 篩選指定語言遊戲, 支援 zh-cn, zh-tw, en, jp, vn, th | | sord | 字串 | X | 排序樣式預設asc允許值: "asc", "desc" | | type | 字串 | X | 遊戲類型預設blank允許值: "desktop", "mobile" | - 請求-範例: ``` http://sample.domain.com/games http://sample.domain.com/games?category=slot http://sample.domain.com/games?provider=1 http://sample.domain.com/games?page=2 http://sample.domain.com/games?page=1&rows=10 http://sample.domain.com/games?page=1&rows=10&sidx=name&sord=desc http://sample.domain.com/games?type=desktop ``` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | games | 物件[] | 遊戲列表 | - 回應-成功: - gameType 1: slot, 2: poker, 3: lottery ```json HTTP/1.1 200 OK { "status": "success", "data": { "games": [ { "category": "slot", "name": "天狗祭", "providerId": 4, "code": "tengu-festival", "gameId": 82, "actived": true, "locales": [ "zh-cn", "zh-tw", "en", "jp", "vn" ], "id": 82, "disabled": 0, "gameType": 1, "isNew": false, "isHot": false, "url": "https://play.godeebxp.com/egames/50addb64f3e1285277a4917d71736b94/game/images/platform/zh-tw/game_icon.png" }, { "category": "poker", "name": "搶莊妞妞", "providerId": 4, "code": "banker-bull", "gameId": 68, "actived": true, "locales": [ "zh-cn", "zh-tw", "en", "jp" ], "id": 68, "disabled": 0, "gameType": 2, "isNew": false, "isHot": false, "url": "https://play.godeebxp.com/egames/5ded8101bcdb4fa7864ca42873aac888/game/images/platform/zh-tw/game_icon.png" } ], "meta": { "totalRecords": 2, "totalPages": 2, "currentPage": 1, "hasPrevious": false, "hasNext": true } } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | forbidden | 遊戲商錯誤 | 403 | | InternalServerError | 內部服務器錯誤 | 500 | --- ## 取得遊戲金鑰 > **取得遊戲金鑰** GET ``` /game-providers/:providerId/games/:gameCode/key ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | providerId | 整數 | O | 遊戲供應商 id | | gameCode | 字串 | O | 遊戲代號 | ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | username | 字串 | O | 用戶名 | | fullname | 字串 | X | 使用者於遊戲中顯示名稱(未設定以 username 顯示) | - 請求-範例: `http://sample.domain.com/game-providers/1/games/gmcde/key?username=myuser123` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | key | 字串 | 產生的金鑰 | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "key": "67a17dd934c01fffcf119...beca27acdcc233168efb1cbb3c6a74dc846" } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | invalid token | 無效Token | 401 | | Missing Parameter | 參數不可為空 | 403 | | User not found | 會員不存在 | 401 | | Game not found | 錯誤的遊戲代號 | 401 | | Forbidden | 遊戲商錯誤 | 403 | | InternalServerError | 內部服務器錯誤 | 500 | --- ## 玩遊戲 > **遊戲進入點** GET ``` /game-providers/:providerId/play ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | providerId | 整數 | O | 遊戲供應商 id | ### 參數(Query String) | 參數 | 類型 | 描述 | | --- | --- | --- | | key | 字串 | 遊戲金鑰 | | type | 字串 | 產生鏈接類型預設desktop允許值: "desktop", "mobile" | | locale | 字串 | 語系預設operator經營方語系允許值: "zh-cn", "zh-tw", "en", "vn", "th"(簡,繁,英,越南文,泰文) | - 請求-範例: `http://sample.domain.com/game-providers/1/play?key=67a17dd934c01...4dc846` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | url | 字串[] | 遊戲鏈接 | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "url": "http://testproviderdomain.com/game/playgame?parameter=RTYUFGHJ" } } ``` ### 錯誤 | 名稱 | 描述 | | --- | --- | | In maintenance | 系統維護中 | 400 | | Forbidden | 遊戲商錯誤 | | InternalServerError | 內部服務器錯誤 | --- ## 取得遊戲大廳 > **取得遊戲大廳的連結** GET ``` /game-providers/:providerId/lobby ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | providerId | 整數 | O | 遊戲供應商 id | ### 參數(Query String) | 參數 | 類型 | 描述 | | --- | --- | --- | | username | 字串 | 用戶名 | | headless | 0 or 1 | 是否隱藏表頭, 預設否:0 | | dark | 0 or 1 | 是否暗色風格, 預設否:0 | - 請求-範例: `http://sample.domain.com/game-providers/1/lobby?username=myuser123&headless=1&dark=1` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | url | 字串[] | 遊戲大廳鏈接 | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "url": "http://testproviderdomain.com/egames/lobby/game/?t=..." } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | Forbidden | 遊戲商錯誤 | 403 | | InternalServerError | 內部服務器錯誤 | 500 | --- ## 遊戲地址query string字段說明 > **遊戲地址query string字段說明** ``` http://sample.domain.com/egames/800a4250f7a03739160a549ee65de3a5/? t=4bea87bc4c644c82b1eee7e49ea90532&gn=vampire-hunter&l=zh-cn&ct=slot& gt=slot3&socket_url=socket.game.bx&ts=1581908023924&view_mode=portrait& goback_url=https%3A%2F%2Fmy-goback.url%2Fpath%2Fto%2Fback ``` | Query String | Required | Description | Value | |--------------|----------|-------------|-------| | client_type | 必填 | 用戶端裝置類型,API 取得遊戲地址後會包含此字段,如返回值與實際用戶端不一致,請用戶端 app 修正為正確的值 | ios: ios app<br>android: android app<br>web: 桌上型電腦瀏覽器<br>wap: 手機瀏覽器<br>unknown: 未知 | | goback_url | 選填 | wap/web 返回鏈結 | {Url string} 提供 web/wap 遊戲端點擊離開按鈕時鏈結之 url,未提供 url 遊戲將直接關閉視窗。`goback_url=disable` 時,則使⽤⽆效。 | | uniwebview | 選填 | 是否使用 unity uniwebview 套件 | 1 如用戶端 app 使用 unity uniwebview 需接收需設置此字段,提供遊戲端正確調用開關 | | view_mode | 必填 | 橫屏 / 豎屏 | landscape: 橫屏<br>portrait: 豎屏 | ## Web(電腦瀏覽器) 及 Wap(手機瀏覽器) 離開遊戲 > **當遊戲地址 query string 上的 client_type=wap 或 client_type=web 時,且用戶端在遊戲地址後的 query string 加上 goback_url={YOUR GO BACK URL},用戶點擊離開按鈕後遊戲會直接轉跳至 goback_url。** > > **若未提供 goback_url ,遊戲將直接關閉視窗。** > > **若 goback_url=disable 時,則關閉遊戲內"離開"按鈕功能,使返回無效。** ``` http://play-game.bx/egames/800a4250f7a03739160a549ee65de3a5/? t=4bea87bc4c644c82b1eee7e49ea90532&gn=vampire-hunter&l=zh-cn&ct=slot&qt=slot3&socketunl=socket.game.bx&ts=1581908023924&view_mode=portrait&goback_url=https%3A%2F%2Fmygoback.url%2Fpath&2Fto%2Fback ``` ## Web 及 Wap 中使用 iframe 接入 離開遊戲 > **當遊戲地址 query string 上的 client_type=wap 或 client_type=web 時,且用戶端使用 iframe接入遊戲時,在遊戲地址後的 query string 加上goback_url=javascript:window.parent.location.href="指定轉跳的地址"** ## Android 原生 APP 離開遊戲 > **當遊戲地址 query string 上的 client_type=android 及未設定 uniwebview 時會調用此方法** > > **使用第三方框架 WVJBWebView** > **build.gradle/dependencie** > ![image](https://hackmd.io/_uploads/HJRgoHxK1g.png) > **註冊監聽 TwGameBack, 即可收到 TwGameBack callback** > ![image](https://hackmd.io/_uploads/r1yVjBxtkx.png) ## iOS 原生APP 離開遊戲 > **當遊戲地址 query string 上的 client_type=ios 及未設定 uniwebview 時會調用此方法。** > **實現 WKScriptMessageHandler, 可於 userContentController 接收到 message。** > ![image](https://hackmd.io/_uploads/SkF9jSeFkx.png) > **使用 configuration.userContentController 註冊監聽"TwGameBack"** > ![image](https://hackmd.io/_uploads/SkMpsBlY1g.png) ## Unity - UniWebview 離開遊戲 > **當用戶端使用 Unity3D 開發並使用 UniWebview 套件,且遊戲地址query string 上包含 uniwebview=1 時會調用此方法。** > ![image](https://hackmd.io/_uploads/HkdW2rxt1g.png) ## 強制踢線玩家 > 踢除正在遊戲中的指定玩家或所有玩家 DELETE ``` /play/:username ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | username | 字串 | O | 用戶遊戲帳號(使用 all 為踢除全部線上玩家) | - 請求-範例: ``` http://sample.domain.com/play/myusername http://sample.domain.com/play/all ``` ### Success 200 - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success" } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | Forbidden | 遊戲商錯誤 | 403 | | User not exists | 用戶不存在 | 404 | | InternalServerError | 內部服務器錯誤 | 500 | --- # 獲取數據 ## 取得大獎彩金 > **取得大獎彩金之點數** GET ``` /jackpot ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` - 請求-範例: ``` http://sample.domain.com/jackpot ``` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | jp-mini | 數字(float) | 小獎彩金 | | jp-minor | 數字(float) | 次獎彩金 | | jp-major | 數字(float) | 大獎彩金 | | jp-grand | 數字(float) | 巨獎彩金 | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "jp-minor": 33942.5, "jp-mini": 565856.67, "jp-major": 547010.59, "jp-grand": 993936.18 } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | forbidden | 系統異常 | 400 | --- ## ~~取得指定分鐘範圍統計資料~~ (已廢除) 1. 可查詢的範圍為目前時間14分鐘前,最多可查詢到72小時內,例:目前時間為 2024-12-01 12:14,可查詢範圍為 2024-11-28 12:00 至 2024-12-01 11:59 GET ``` /statistics?start=2024-11-28%2012:00&end=2024-12-01%2011:59 ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | start | 字串(string) | O | 開始時間(yyyy-MM-dd HH:mm) | | end | 字串(string) | O | 結束時間(yyyy-MM-dd HH:mm) | | game | 整數(integer) | X | 遊戲 gameId (從遊戲列表取得) | - 請求-範例: ``` http://sample.domain.com/statistics?start=2024-11-28%2012:00&end=2024-12-01%2011:59 ``` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | totalBet | 數字(float) | 總投注點數(小數後兩位) | | totalWin | 數字(float) | 總贏分主數(小數後兩位) | | totalBetCount | 數字(integer) | 總投注次數 | | totalWinCount | 數字(integer) | 總贏分次數 | | startTime | 字串(string) | 開始時間 | | endTime | 字串(string) | 結束時間 | | featureBet | 數字(float) | 總購買特色遊戲點數 | | featureWin | 數字(float) | 總購買特色遊戲贏分 | | featureCount | 數字(integer) | 總購買特色遊戲次數 | | currency | 字串(string) | 使用幣別(P130: 130比1, P100: 100比1... 以此類推) | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "totalBet": 123456.78, "totalWin": 123456.78, "totalBetCount": 12345, "totalWinCount": 1234, "startTime": '2024-11-01 13:00', "endTime": '2024-11-01 13:10', "currency": 'TWD' } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | forbidden | 系統異常 | 400 | | user not found | 查無用戶 | 400 | | game not found | 查無遊戲 | 400 | | time range too large | 時間範圍過長 | 400 | | invalid time range | 參數的時間範圍 | 400 | --- ## 取得指定日期統計資料 > **取得指定日期統計資料** GET ``` /statistics/:date?time=00 ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | time | 數字(Integer) | X | 指定取得的第幾個小時 (例: 設定為 00 可查詢當日的 00:00 - 00:59 的資料) | | game | 數字(Integer) | X | 遊戲 gameId (從遊戲列表取得) | ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | date | 字串 | O | 指定日期(YYYY-MM-DD) | - 請求-範例: ``` http://sample.domain.com/statistics/2024-05-01 ``` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | totalBet | 數字(float) | 總投注點數 | | totalWin | 數字(float) | 總贏分主數 | | totalBetCount | 數字(integer) | 總投注次數 | | totalWinCount | 數字(integer) | 總贏分次數 | | featureBet | 數字(float) | 總購買特色遊戲點數 | | featureWin | 數字(float) | 總購買特色遊戲贏分 | | featureCount | 數字(integer) | 總購買特色遊戲次數 | | profit | 數字(float) | 淨利潤點數 | | totalPlayerCount | 數字(integer) | 不重複玩家數 | | newPlayerCount | 數字(integer) | 新註冊玩家數(不分遊戲) | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "jp-minor": 33942.5, "jp-mini": 565856.67, "jp-major": 547010.59, "jp-grand": 993936.18 } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | forbidden | 系統異常 | 400 | --- ## 取得未出餘額用戶名單 > **取得未出餘額用戶名單** GET ``` /game-providers/:providerId/balance-users ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | providerId | 整數 | O | 遊戲供應商id | - 請求-範例: ``` http://sample.domain.com/game-providers/:providerId/balance-users ``` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | username | 字串 | 用戶帳號 | | amount | 數字(float) | 餘額小數點後2位 | | status | 字串 | Enabled: 啟用中, Blocked: 鎖定中 | | updatedAt | 數字(integer) | 最後更新時間 utc timestamp(ms) | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "users": [ { "username": "superman", "amount": 12345.67, "updatedAt": 1724059573433 }, { "username": "superwoman", "amount": 12345.67, "updatedAt": 1724059573433 }, ... ] } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | forbidden | 系統異常 | 400 | --- ## 下注記錄 > **利用API取得注單(限3秒內僅能執行一次,查詢區間限制為五分鐘)** POST ``` /transaction ``` ### 注單查詢參數 | 參數 | 類型 | 必要 | 描述 | | ----------------- | ---------- | ---- | ----------------------------------------------------------------------------------- | | Operator | 字串 | O | X-Operator 經營方代碼 | | Key | 字串 | O | X-Key 經營方API金鑰 | | SDate | 時間與日期 | O | 格式 : YYYY-MM-DD HH:mm:ss, 時區為: 經營賬號時區(預設GTM+8) 查詢起始時間(大於等於) | | EDate | 時間與日期 | O | 格式 : YYYY-MM-DD HH:mm:ss, 時區為: 經營賬號時區(預設GTM+8) 查詢結束時間(小於等於,時間範圍最長5分鐘) | | Type | 字串 | X | 注單時間過濾方式 settledate(預設), bettingdate | | Provider | 字串 | X | 遊戲供應商 | | PlayerID | 字串 | X | 玩家賬號 | | TransactionNumber | 字串 | X | 注單編號 | | BetDataGameCode | 字串 | X | 指定 gameCode 返回詳情(僅限特定遊戲),同時指定多個遊戲以","分隔,例: mahjong,bubble-gum | - 成功-回應 ```json HTTP/1.1 200 OK [ { "gameprovider": "p1", // 遊戲供應名稱 {String} "membername": "user1", // 用戶名稱 {String} "gamename": "game1", // 遊戲名稱 {String} "bettingid": "667e6037fff4", // 注單ID {String} "bettingcode": 1124, // 注單編號 {Integer} "bettingdate": "1695474361", // 投注時間 {String} "gameid": 11111, // 遊戲ID {Integer} "gamecode": "bubble-gum", // 遊戲代碼 {String} "roundno": "null", // 遊戲回合(部分遊戲提供) {String} "result": "null", // 注單結果(部分遊戲提供) {String} "bet": "null", // 投注內容(部分遊戲提供) {String} "winloseresult": "W", // 勝負狀態(W: 勝, L: 負) {String} "totalstake": "1.000", // 下注點數 {String} "bettingamount": 1.000, // 打碼點數 {Float} "validbet": "1.000", // 有效注單點數 "winloseamount": 1.000, // 勝負點數 {Float} "balance": "null", // 投注後餘額(部分遊戲提供) {String} "currency": "MYR", // 貨幣 {String} "isfree": "0", // 是否為免費遊戲 0: 否, 1: 是 {String} "isfeature": "0", // 是否為購買特色遊戲 0: 否, 1: 是 {String} "handicap": "null", // 讓分(部分遊戲提供) {String} "status": "close", // 狀態(close: 已結算, open: 未結算, refund: 退款, cancel: 撤單) {String} "gamecategory": "slot", // 遊戲類別(lottery: 彩票, slot: 老虎幾, poker: 棋牌, arcade: 街機小遊戲) {String} "settledate": "1695474361", // 結算時間(Unix timestamp second) {String} "remark": "null", // 備註 {String} "betdata": "json string", // 注單詳情(特定遊戲,以 jsonstring 返回) {String}, 預設值為 "null" "replayurl": "string" // 該注單的重播連結(部份遊戲提供) {String} } ] ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | (Operator name) must be provided | 必要入operator | 403 | | (Operator Key) must be provided | 必要入Key | 403 | | (Start Date) must be provided | 時間格式錯誤 | 403 | | (End Date) must be provided | 時間格式錯誤 | 403 | | SDate cannot be greater than EDate | SDate 大於 EDate 時間條件錯誤 | 403 | | Transaction is no allowed for over then 5 minuntes | 抄單時間範圍不得超過5分鐘 | 403 | | Request time limit. Try again latter. | 抄單頻率過快,預設兩次間隔不得少於3秒 | 405 | --- ## 轉賬記錄 > **利用API取得額度轉換(限3秒內僅能執行一次)** POST > FORM-DATA ``` /transfer ``` ### 查詢參數 | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | Operator | 字串 | O | X-Operator 經營方代碼 | | Key | 字串 | O | X-Key 經營方API金鑰 | | SDate | 時間與日期 | O | 格式 : YYYY-MM-DD HH:MM:SS, 時區為 : 經營賬號時區(預設GTM+8) "查詢區間限制為十分鐘" | | EDate | 時間與日期 | O | 格式 : YYYY-MM-DD HH:MM:SS, 時區為 : 經營賬號時區(預設GTM+8) "查詢區間限制為十分鐘" | | Provider | 字串 | X | 遊戲供應商 | | PlayerID | 字串 | X | 玩家賬號 | | TransferCode | 字串 | X | 交易紀錄編號(客戶提供的備註或系統生成皆可) | | Exact | 布林 | X | 預設TrueTrue - PlayerID 精確查詢False - PlayerID 模糊查詢允許值: "True", "False" | - 成功-回應 ```json HTTP/1.1 200 OK [ { "provider": "p1", "id": "10", "username": "user1", "amount": "112", "currency": "MYR", "actions": "IN", "balance": "50", "transfercode": "mytransfercode", "createtime": "1695474361" } ] ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | (Operator name) must be provided | 必要入operator | 403 | | (Operator Key) must be provided | 必要入Key | 403 | | (Start Date) must be provided | 時間格式錯誤 | 403 | | (End Date) must be provided | 時間格式錯誤 | 403 | --- ## 單筆轉賬記錄 > **以 transferId 取得單筆交易記錄** GET ``` /Transfer/:transferId ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 域名(Parameters) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | transferId | 字串 | O | 交易id | - 請求-範例: ``` http://sample.domain.com/Transfer/223120810qPPlSr ``` - 成功-回應 ```json HTTP/1.1 200 OK { "status": "success", "data": { "provider": "p1", "id": "10", "username": "user1", "amount": "112", "currency": "TWD", "actions": "IN", "balance": "50", "transfercode": "223120810qPPlSr", "createtime": "2022-11-08T08:10:36.233Z" } } ``` ### 錯誤 ```json HTTP/1.1 404 Not Found { "status": 404, "message": "Record not found." } ``` | 名稱 | 描述 | HTTP Status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | Transfer in progress | 交易處理中 | 403 | | Internal Server Error | 內部服務器錯誤 | 500 | | Record not found. | 查無相關記錄 | 404 | --- ## 取得注單下載連結 > **提供注單檔案連結,匯出 CSV 檔並壓縮成 ZIP(12分鐘後的注單,存活時間最長二小時)** > **商戶需提出申請,才能使用此功能** GET ``` /transaction/link ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` - 回應-成功: ```json HTTP/1.1 200 OK { "status": 200, "message": "success", "data": { "list": [ { "startTime": 1762999140000, "endTime": 1762999199999, "betCount": 2, "link": "https://abc.com/1762999140000.zip" } ] } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | invalid token | 無效Token | 401 | | Forbidden | 遊戲商錯誤 | 403 | | InternalServerError | 內部服務器錯誤 | 500 | --- ## 登記注單匯出任務 > **提供登記注單下載任務,匯出完成後,在 取得注單下載連結 可取得連結** > **商戶需提出申請,才能使用此功能** POST ``` /transaction/link/register ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 注單查詢參數 | 參數 | 類型 | 必要 | 描述 | | ----------------- | ---------- | ---- | ----------------------------------------------------------------------------------- | | startTime | Timestamp(13碼) | O | 預設GTM+8 | | endTime | Timestamp(13碼) | O | 預設GTM+8 | - 回應-成功: ```json HTTP/1.1 200 OK { "status": 200, "message": "success" } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | invalid token | 無效Token | 401 | | Forbidden | 遊戲商錯誤 | 403 | | InternalServerError | 內部服務器錯誤 | 500 | | Start time is require | 開始時間為必填 | 400 | | End time is require | 結束時間為必填 | 400 | | End time must be greater than start time | 結束時間必需大於開始時間 | 400 | | Time range must not be greater than 2 hours | 時間範圍最長二小時 | 400 | --- # 其他 ## 取得所有玩家 > **取得玩家列表** GET ``` /players ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | X-Token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "X-Token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | rows | 整數 | X | 回傳記錄筆數預設10 | | page | 整數 | X | 頁數預設1 | | sidx | 字串 | X | 排序的欄位名稱預設id | | sord | 字串 | X | 排序樣式預設asc允許值: "asc", "desc" | - 請求-範例: ``` http://sample.domain.com/players http://sample.domain.com/players?page=2 http://sample.domain.com/players?page=1&rows=10 http://sample.domain.com/players?page=1&rows=10&sidx=name&sord=desc ``` ### Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | players | 字串[] | 玩家列表 | - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success", "data": { "players": [ { "id": 1, "username": "DUMMYACCT2X", "fullname": "DUMMY ACCT 2ND", "email": "DUMMY.ACCT2@TEST.COM", "country": "PHILIPPINES", "currency": "CNY", "birthdate": "1992-02-18T00:00:00.000Z", "operatorId": 2, "createdAt": "2017-06-01T21:07:05.000Z", "updatedAt": "2017-06-01T21:07:05.000Z" }, { "id": 2, "username": "DUMMYACCT3X", "fullname": "DUMMY ACCT 3RD", "email": "DUMMY.ACCT3@TEST.COM", "country": "JAPAN", "currency": "CNY", "birthdate": "1990-05-18T00:00:00.000Z", "operatorId": 2, "createdAt": "2017-06-01T21:07:05.000Z", "updatedAt": "2017-06-01T21:07:05.000Z" } ], "meta": { "totalRecords": 5, "totalPages": 2, "currentPage": 2, "hasPrevious": true, "hasNext": false } } } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | invalid token | 無效Token | 401 | | Forbidden | 遊戲商錯誤 | 403 | | InternalServerError | 內部服務器錯誤 | 500 | --- # 單一錢包 (建議使用V2版本) 此版本即將棄用,建議使用V2版本可提升執行效率 ## 說明 1. 由貴方提供「單一錢包交易API」, 讓我方串接進行餘額異動。 2. 當貴方收到我方發出 API 請求時,需將 headers 中的 token 及 body 中的 data,先發送驗証請求到我方的「[驗証錢包參數](#wallet-token)」API,確認 token 及資料完整性,token 為一次性,驗証完即失效。 3. body 中的 data,解密方式為 AES 128 CBC,key 及 iv 長度皆為 16 碼,不足16位,後面補0,超過16位就取前16位。 4. 當我方呼叫貴方的 API, 如果網路出現異常(例如:Timeout),我方會重試三次,每次間隔 50 ms,此 n 次請求的 token 皆相同,可用於判斷是否重覆請求。 ### 營運商需提供以下資訊 | 參數 | 類型 | 描述 | | --- | --- | --- | | url | 字串 | API base url | ### AES 解密資訊 | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | iv | 字串(16 碼) | O | 經營方代碼(X-Operator) | | key | 字串(16 碼) | O | 經營方API密鑰(X-Key) | - JavaScript 範例: ```JavaScript const decrypt = (key, iv, str) => { const key2 = key.slice(0, 16) const iv2 = iv.padEnd(16, '0') const crypted = Buffer.from(str, 'base64').toString('binary') const decipher = crypto.createDecipheriv('aes-128-cbc', key2, iv2) let decoded = decipher.update(crypted, 'binary', 'utf8') decoded += decipher.final('utf8') return decoded } ``` - PHP 範例: ```php function decrypt($key, $iv, $str) { // 將 key 截取為前 16 個字符 $key2 = substr($key, 0, 16); // 將 iv 補充為 16 個字符 $iv2 = str_pad($iv, 16, '0'); // 將 base64 字符串轉換為二進制數據 $crypted = base64_decode($str); // 使用 openssl_decrypt 進行解密 $decoded = openssl_decrypt($crypted, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA, $iv2); // 返回解密後的字符串 return $decoded; } // 測試 $key = "your_key_here"; $iv = "your_iv_here"; $str = "your_encrypted_string_here"; echo decrypt($key, $iv, $str); ``` --- ## 取得餘額 > **取得用戶在營運商的餘額** GET ``` {單一錢包交易API網址}/balance ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | 交易驗証憑證 | - 標頭-範例: ```json { "token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | username | 字串 | O | 用戶名 | - 請求-範例: `https://sample.domain.com/balance?username=myuser123` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balance | 浮點數 | 即時餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balance": 500 } } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "data": { "message": "錯誤訊息" } } ``` --- ## 下注扣款 > **用戶在營運商的下注扣款** POST ``` {單一錢包交易API網址}/betting ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 解壓後資料(data) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | uuid | 字串 | O | 識別碼 | | betId | 字串 | O | 注單ID | | gameCode | 字串 | O | 遊戲代碼 | | username | 字串 | O | 用戶名 | | amount | 浮點數 | O | 下注點數 | - 請求-範例: ```json { "uuid": "664ee129a697acf53d3b6e14", "betId": "6661868717e794f36effc59a", "gameCode": "climb-stairs", "username": "myuser123", "amount": 100 } ``` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balanceOld | 浮點數 | 扣款前餘額 | | balance | 浮點數 | 扣款後餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balanceOld": 500, "balance": 400 } } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "data": { "message": "錯誤訊息" } } ``` --- ## 結算派獎 > **用戶在營運商的結算派獎** > **如玩家斷線,系統有自動關單機制,請勿限制玩家離線時不可結算派獎** POST ``` {單一錢包交易API網址}/settlement ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 解壓後資料(data) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | uuid | 字串 | O | 識別碼 | | betId | 字串 | O | 注單ID | | gameCode | 字串 | O | 遊戲代碼 | | username | 字串 | O | 用戶名 | | amount | 浮點數 | O | 贏分點數 | - 請求-範例: ```json { "uuid": "664ee129a697acf53d3b6e14", "betId": "6661868717e794f36effc59a", "gameCode": "climb-stairs", "username": "myuser123", "amount": 100 } ``` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balanceOld | 浮點數 | 派獎前餘額 | | balance | 浮點數 | 派獎後餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balanceOld": 400, "balance": 500 } } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "data": { "message": "錯誤訊息" } } ``` --- ## 退款 > **用戶在營運商的退款,此為彩票類遊戲使用,如開獎異常或和局時,遊戲自行判斷退款** > **例如:賽馬的百家樂下莊閒,開和局時,會觸發退款** POST ``` {單一錢包交易API網址}/refund ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | 產生存取憑證 | - 標頭-範例: ```json { "token": "aqA12Wsqa341...ASDasd123asd" } ``` ### 解壓後資料(data) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | uuid | 字串 | O | 識別碼 | | betId | 字串 | O | 注單ID | | gameCode | 字串 | O | 遊戲代碼 | | username | 字串 | O | 用戶名 | | amount | 浮點數 | O | 退款點數 | - 請求-範例: ```json { "uuid": "664ee129a697acf53d3b6e14", "betId": "6661868717e794f36effc59a", "gameCode": "climb-stairs", "username": "myuser123", "amount": 100 } ``` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balanceOld | 浮點數 | 退款前餘額 | | balance | 浮點數 | 退款後餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balanceOld": 400, "balance": 500 } } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "data": { "message": "錯誤訊息" } } ``` --- ## 驗証錢包參數 <a id="wallet-token"></a> > 驗証營運商單一錢包所回傳的 token 及 data POST ``` /wallet/authorize ``` ### 參數(Query String) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | wallet token | | data | 字串 | X | 單一錢包所傳送的資料(如 GET 不需傳 data) | - 請求-範例: ```json { "token": "664ee129a697acf53d3b6e14", "data": "aofYPahYUsANEuXfhwBjeWTUgYtIFRlw0PErKZexkVw=" } ``` ### Success 200 - 回應-成功: ```json HTTP/1.1 200 OK { "status": "success" } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "message": "錯誤訊息" } ``` ### 錯誤 | 名稱 | 描述 | HTTP status | | --- | --- | --- | | In maintenance | 系統維護中 | 400 | | Internal Server Error | 伺服器發生問題 | 500 | | Forbidden | 驗証錢包 token 錯誤或過期 | 403 | --- # 單一錢包 V2 ## 說明 1. 由貴方提供「單一錢包交易API」, 讓我方串接進行餘額異動。 2. 當貴方收到我方發出 API 請求時,需執行 token 的驗証,以確保資料無誤。 2.1 取出 headers 中的 timestamp,以及 body 中的 data 跟 iv 字串相接後做 md5 編碼,與 token 是否相符,範例:token === md5(iv + timestamp + data)。 2.2 timestamp 為有效期限,判斷 timestamp 未過期時,再處理此封包,範例:now() < timestamp。 3. body 中的 data,解密方式為 AES 128 CBC,key 及 iv 長度皆為 16 碼,不足16位,後面補0,超過16位就取前16位。 4. 當我方呼叫貴方的 API, 如果網路出現異常(HTTP Status code:5xx),我方會重試三次,每次間隔 50 ms,此 n 次請求的 token 皆相同,可用於判斷是否重覆請求。 5. 我方呼叫 API 的 Timeout 設定值為 10 秒,如果呼叫逾時,不會觸發重試機制。 ### 營運商需提供以下資訊 | 參數 | 類型 | 描述 | | --- | --- | --- | | url | 字串 | API base url | ### AES 解密資訊 | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | iv | 字串(16 碼) | O | 經營方代碼(X-Operator) | | key | 字串(16 碼) | O | 經營方API密鑰(X-Key) | - JavaScript 範例: ```JavaScript const decrypt = (key, iv, str) => { const key2 = key.length > 16 ? key.slice(0, 16) : key.padEnd(16, '0') const iv2 = iv.length > 16 ? iv.slice(0, 16) : iv.padEnd(16, '0') const crypted = Buffer.from(str, 'base64').toString('binary') const decipher = crypto.createDecipheriv('aes-128-cbc', key2, iv2) let decoded = decipher.update(crypted, 'binary', 'utf8') decoded += decipher.final('utf8') return decoded } ``` - PHP 範例: ```php function decrypt($key, $iv, $str) { $key2 = strlen($key) > 16 ? substr($key, 0, 16) : str_pad($key, 16, '0'); $iv2 = strlen($iv) > 16 ? str_pad($iv, 16, '0') : str_pad($iv, 16, '0'); // 將 base64 字符串轉換為二進制數據 $crypted = base64_decode($str); // 使用 openssl_decrypt 進行解密 $decoded = openssl_decrypt($crypted, 'AES-128-CBC', $key2, OPENSSL_RAW_DATA, $iv2); return $decoded; } ``` --- ## 解密範例 加密所需參數 | 參數 | 值 | | --- | --- | | iv | iv1 | | key | key1 | | timestamp | 1733797877 | 加密後參數 | 參數 | 值 | | --- | --- | | token | f0a7a81001350206304b370684de63b2 | | data | Ce6M+q7tjSab7lrIvzgYd9EEM8YzvoS4IhaSxLHieebcrD15YJWfKNC2EzoJ1Yjm3AvoWtYZUMnQKqEJHyL5u9oLSHC9lILuQUj67/XO0/U= | 解密後參數 | 參數 | 值 | | --- | --- | | uuid | b99ad91c19004e28a37c1771c625b3c5 | | username | username1 | - curl 範例: ```curl curl -X POST http://localhost/balance -H 'Content-Type: application/json' -H 'token: f0a7a81001350206304b370684de63b2' -H 'timestamp: 1733797877' -d '{"data":"Ce6M+q7tjSab7lrIvzgYd9EEM8YzvoS4IhaSxLHieebcrD15YJWfKNC2EzoJ1Yjm3AvoWtYZUMnQKqEJHyL5u9oLSHC9lILuQUj67/XO0/U="}' ``` - JavaScript 解密範例: ```JavaScript const decryptData = async (token, timestamp, data) => { const md5 = crypto.md5(`${iv}${timestamp}${data}`) if (token !== md5) { console.log('check token error') } const now = moment().unix() if (now > parseInt(timestamp)) { console.log('timestamp expried') } const decryptedStr = aes.decrypt(key, iv, data) const decrypted = JSON.parse(decryptedStr) return decrypted } ``` --- ## 取得餘額 > **取得用戶在營運商的餘額** POST ``` {單一錢包交易API網址}/balance ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | 交易驗証憑證 | | timestamp | 整數(10碼) | O | 有效期限 | - 標頭-範例: ```json { "token": "667e60419dc6d6428a99ee0e", "timestamp": 1704070800 } ``` ### 解壓後資料(data) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | uuid | 字串 | O | 識別碼 | | username | 字串 | O | 用戶名 | - 請求-範例: ```json { "uuid": "664ee129a697acf53d3b6e14", "username": "myuser123" } ``` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balance | 浮點數 | 即時餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balance": 500 } } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "data": { "message": "錯誤訊息" } } ``` --- ## 下注扣款 > **用戶在營運商的下注扣款** POST ``` {單一錢包交易API網址}/betting ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | 產生存取憑證 | | timestamp | 整數(10碼) | O | 有效期限 | - 標頭-範例: ```json { "token": "667e60419dc6d6428a99ee0e", "timestamp": 1704070800 } ``` ### 解壓後資料(data) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | uuid | 字串 | O | 識別碼 | | betId | 字串 | O | 注單ID | | gameCode | 字串 | O | 遊戲代碼 | | username | 字串 | O | 用戶名 | | amount | 浮點數 | O | 下注點數 | - 請求-範例: ```json { "uuid": "664ee129a697acf53d3b6e14", "betId": "6661868717e794f36effc59a", "gameCode": "climb-stairs", "username": "myuser123", "amount": 100 } ``` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balanceOld | 浮點數 | 扣款前餘額 | | balance | 浮點數 | 扣款後餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balanceOld": 500, "balance": 400 } } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "data": { "message": "錯誤訊息" } } ``` --- ## 結算派獎 > **用戶在營運商的結算派獎** > **如玩家斷線,系統有自動關單機制,請勿限制玩家離線時不可結算派獎** POST ``` {單一錢包交易API網址}/settlement ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | 產生存取憑證 | | timestamp | 整數(10碼) | O | 有效期限 | - 標頭-範例: ```json { "token": "667e60419dc6d6428a99ee0e", "timestamp": 1704070800 } ``` ### 解壓後資料(data) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | uuid | 字串 | O | 識別碼 | | betId | 字串 | O | 注單ID | | gameCode | 字串 | O | 遊戲代碼 | | username | 字串 | O | 用戶名 | | amount | 浮點數 | O | 贏分點數 | - 請求-範例: ```json { "uuid": "664ee129a697acf53d3b6e14", "betId": "6661868717e794f36effc59a", "gameCode": "climb-stairs", "username": "myuser123", "amount": 100 } ``` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balanceOld | 浮點數 | 派獎前餘額 | | balance | 浮點數 | 派獎後餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balanceOld": 400, "balance": 500 } } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "data": { "message": "錯誤訊息" } } ``` --- ## 退款 > **用戶在營運商的退款,此為彩票類遊戲使用,如開獎異常或和局時,遊戲自行判斷退款** > **例如:賽馬的百家樂下莊閒,開和局時,會觸發退款** POST ``` {單一錢包交易API網址}/refund ``` ### 標頭(Header) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | token | 字串 | O | 產生存取憑證 | | timestamp | 整數(10碼) | O | 有效期限 | - 標頭-範例: ```json { "token": "667e60419dc6d6428a99ee0e", "timestamp": 1704070800 } ``` ### 解壓後資料(data) | 參數 | 類型 | 必要 | 描述 | | --- | --- | --- | --- | | uuid | 字串 | O | 識別碼 | | betId | 字串 | O | 注單ID | | gameCode | 字串 | O | 遊戲代碼 | | username | 字串 | O | 用戶名 | | amount | 浮點數 | O | 退款點數 | - 請求-範例: ```json { "uuid": "664ee129a697acf53d3b6e14", "betId": "6661868717e794f36effc59a", "gameCode": "climb-stairs", "username": "myuser123", "amount": 100 } ``` ### 成功 Success 200 | 參數 | 類型 | 描述 | | --- | --- | --- | | balanceOld | 浮點數 | 退款前餘額 | | balance | 浮點數 | 退款後餘額 | - 回應-成功 ```json HTTP/1.1 200 OK { "status": "success", "data": { "balanceOld": 400, "balance": 500 } } ``` - 回應-失敗 ```json HTTP/1.1 200 OK { "status": "fail", "data": { "message": "錯誤訊息" } } ```