The Seamless (single wallet) test suite contains 14 test cases, executed by the TestKit in the selected order. API reference: https://doc.sgo-extension.com/swam/
Merchant callbacks support two request formats. Use the switch above to view the request examples for your integration — JSON is shown by default. Responses and assertions are identical in both formats.
| Step type | Direction | Endpoint |
|---|---|---|
login | TestKit → StakeGO platform (STG) | {SGO_API_URL}/api/login (GET, params in query string) |
balance / deduct / deposit / rollback | TestKit (acting as the platform) → merchant callbacks | The Balance / Deduct / Deposit / Rollback URLs configured on the page |
Request format (JSON mode). Every callback is a POST with Content-Type: application/json and a JSON body. The bets field is a native JSON array. When a token is configured, every callback request also carries the token field (which is included in the signature); the examples below use token=mock_123. The login request never carries a token.
Request format (Form mode). Callbacks are POST with Content-Type: application/x-www-form-urlencoded, except balance, which becomes a GET with the parameters in the query string. Form values are strings, so the bets array is serialized to a JSON string inside the bets field — the merchant must JSON-parse it again. Form mode never sends a token field. The form examples below show the decoded field values; on the wire they are URL-encoded.
Signature (identical in both formats). Every request carries a sign parameter (MD5): lowercase the key names, drop empty values plus the sign and bets fields, sort keys in ascending ASCII order, join as k=v&...&key={secretKey} (values are not URL-encoded), then take the MD5 hex digest.
• Each step asserts Number(response.result) === expected_result_code (every step in this suite expects 0).
• For steps with an expected balance change, the executor calls the merchant Balance endpoint before and after the step and asserts the delta (tolerance 0.005).
• login additionally requires a non-empty openurl; balance additionally requires a numeric balance field.
• All steps within one test case share the same serialnumber (they refer to the same bet). Each entry in bets has its own id/serialnumber; gameroundno equals the case's serialnumber.
• Every notification carries a fresh notifyid. Duplicate-notification cases (the second send in 004, 006, and 011) resend the same notifyid.
• A rollback notification uses its own new notifyid and locates the original transaction via serialnumber + type.
All examples below use appid=your_appid, username=player01, currency=THB; sign and the id fields are placeholders. A full request body is shown only the first time it appears; later cases describe the differences.
Verify that /api/login returns the game lobby link. If login fails, subsequent tests may also fail. The login request is the same in both formats.
{
"appid": "your_appid",
"username": "player01",
"iscreate": "1",
"clienttype": "1",
"language": "2",
"currency": "THB",
"sign": "0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b"
}
{
"result": 0,
"openurl": "https://stg-lobby.example.com/?token=xxxx"
}
The platform calls the merchant Balance endpoint; expect result = 0 and a numeric balance.
{
"appid": "your_appid",
"username": "player01",
"token": "mock_123",
"notifyid": "25081111203512345",
"sign": "0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b"
}
GET {Balance_url}?appid=your_appid&username=player01¬ifyid=25081111203512345&sign=0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b
{
"result": 0,
"balance": 100.00
}
The platform notifies the merchant to deduct a bet (type=1, negative amount).
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
{
"appid": "your_appid",
"username": "player01",
"token": "mock_123",
"notifyid": "25081111203512345",
"type": "1",
"amount": "-1.00",
"currency": "THB",
"serialnumber": "1754882501123456",
"bets": [
{
"id": "1754882501123888",
"serialnumber": "1754882501123888",
"userid": "0",
"username": "player01",
"gametype": 4,
"gameid": 1,
"gameroundno": "1754882501123456",
"choosebankpoint": "",
"betpoint": "PLAYER",
"betamount": "1.00",
"winlost": "0",
"commamount": "0",
"commratio": "",
"createtime": "2026-08-11 11:20:35",
"state": 0
}
],
"sign": "0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b"
}
appid=your_appid
username=player01
notifyid=25081111203512345
type=1
amount=-1.00
currency=THB
serialnumber=1754882501123456
bets=[{"id":"1754882501123888","serialnumber":"1754882501123888","userid":"0","username":"player01","gametype":4,"gameid":1,"gameroundno":"1754882501123456","choosebankpoint":"","betpoint":"PLAYER","betamount":"1.00","winlost":"0","commamount":"0","commratio":"","createtime":"2026-08-11 11:20:35","state":0}]
sign=0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b
{
"result": 0,
"balance": 99.00,
"orderno": "M20260811001"
}
The same deduct notification is sent twice (same serialnumber and notifyid). The merchant must not deduct twice and must respond result = 0 both times (idempotency).
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
| 2 | Deduct | 1 | -1.00 | 0 | 0 (no second deduction) |
Request/response are identical to 003; step 2 is an exact resend of step 1.
A bet deduct (type=1) followed by a settle deposit (type=9) for the same serialnumber.
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
| 2 | Deposit | 9 | +2.00 | 0 | +2.00 |
{
"appid": "your_appid",
"username": "player01",
"token": "mock_123",
"notifyid": "25081111203698765",
"type": "9",
"amount": "2.00",
"currency": "THB",
"serialnumber": "1754882501123456",
"bets": [
{
"id": "1754882501123888",
"serialnumber": "1754882501123888",
"userid": "0",
"username": "player01",
"gametype": 4,
"gameid": 1,
"gameroundno": "1754882501123456",
"choosebankpoint": "",
"betpoint": "PLAYER",
"betamount": "1.00",
"winlost": "1.00",
"commamount": "1.00",
"commratio": "",
"createtime": "2026-08-11 11:20:35",
"state": 1
}
],
"sign": "0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b"
}
appid=your_appid
username=player01
notifyid=25081111203698765
type=9
amount=2.00
currency=THB
serialnumber=1754882501123456
bets=[{"id":"1754882501123888","serialnumber":"1754882501123888","userid":"0","username":"player01","gametype":4,"gameid":1,"gameroundno":"1754882501123456","choosebankpoint":"","betpoint":"PLAYER","betamount":"1.00","winlost":"1.00","commamount":"1.00","commratio":"","createtime":"2026-08-11 11:20:35","state":1}]
sign=0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b
{
"result": 0,
"balance": 101.00,
"orderno": "M20260811002"
}
The same settle deposit notification is sent twice (same serialnumber and notifyid). The merchant must not credit the winnings twice and must respond result = 0 both times (idempotency).
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
| 2 | Deposit | 9 | +2.00 | 0 | +2.00 |
| 3 | Deposit | 9 | +2.00 | 0 | 0 (no second credit) |
Request/response are identical to 005; step 3 is an exact resend of step 2.
A bet deduct followed by a void-bet deposit (type=7) returning the stake.
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
| 2 | Deposit | 7 | +1.00 | 0 | +1.00 |
Step 2 has the same structure as the Deposit in 005, with these differences: type="7", amount="1.00", and the bet carries winlost="1.00", commamount="1.00", state=1. The response format is the same as Deposit.
Bet deduct, settle deposit, then a re-settle correction deposit (type=10) for the same bet.
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
| 2 | Deposit | 9 | +2.00 | 0 | +2.00 |
| 3 | Deposit | 10 | +0.50 | 0 | (not verified) |
Step 3 has the same structure as Deposit, with these differences: type="10", amount="0.50", and the bet carries winlost="1.50", state=2. The response format is the same as Deposit.
A deduct notification is assumed lost, so the platform sends a rollback (type=1). The merchant must return the deducted amount and respond result = 0.
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
| 2 | Rollback | 1 | +1.00 | 0 | +1.00 |
{
"appid": "your_appid",
"username": "player01",
"token": "mock_123",
"notifyid": "25081111204055555",
"type": "1",
"amount": "1.00",
"serialnumber": "1754882501123456",
"errmsg": "timeout",
"sign": "0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b"
}
appid=your_appid
username=player01
notifyid=25081111204055555
type=1
amount=1.00
serialnumber=1754882501123456
errmsg=timeout
sign=0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b
{
"result": 0,
"balance": 100.00
}
A settle deposit notification is assumed lost, so the platform sends a rollback (type=9). The merchant must remove the deposited amount and respond result = 0.
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
| 2 | Deposit | 9 | +2.00 | 0 | +2.00 |
| 3 | Rollback | 9 | 2.00 | 0 | -2.00 |
Step 3 has the same structure as the Rollback in 009, with these differences: type="9", amount="2.00". The response format is the same.
The same rollback notification is sent twice (same notifyid, type and serialnumber). The merchant must only return the deducted amount once and must respond result = 0 both times (idempotency).
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -1.00 | 0 | -1.00 |
| 2 | Rollback | 1 | +1.00 | 0 | +1.00 |
| 3 | Rollback | 1 | +1.00 | 0 | 0 (no second rollback) |
Request/response are identical to 009; step 3 is an exact resend of step 2.
A rollback for a serialnumber the merchant never processed. Per the spec the merchant must do nothing and still respond result = 0.
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Rollback | 1 | 1.00 | 0 | 0 (no balance movement) |
The request has the same structure as the Rollback in 009 (with a brand-new serialnumber).
{
"result": 0,
"balance": 100.00
}
The player tips the dealer; the platform notifies the merchant to deduct with type=28 (no bets).
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 28 | -0.50 | 0 | -0.50 |
{
"appid": "your_appid",
"username": "player01",
"token": "mock_123",
"notifyid": "25081111204233333",
"type": "28",
"amount": "-0.50",
"currency": "THB",
"serialnumber": "1754882599654321",
"sign": "0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b"
}
appid=your_appid
username=player01
notifyid=25081111204233333
type=28
amount=-0.50
currency=THB
serialnumber=1754882599654321
sign=0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b
{
"result": 0,
"balance": 99.50,
"orderno": "M20260811003"
}
One deduct notification carrying multiple bets from the same player; amount equals the total of all bets.
| Step | Endpoint | type | amount | Expected result | Balance change |
|---|---|---|---|---|---|
| 1 | Deduct | 1 | -3.00 | 0 | -3.00 |
{
"appid": "your_appid",
"username": "player01",
"token": "mock_123",
"notifyid": "25081111204577777",
"type": "1",
"amount": "-3.00",
"currency": "THB",
"serialnumber": "1754882650111222",
"bets": [
{ "id": "1754882650111001", "serialnumber": "1754882650111001", "betpoint": "PLAYER", "betamount": "1.00", "...": "remaining fields as in 003" },
{ "id": "1754882650111002", "serialnumber": "1754882650111002", "betpoint": "BANKER", "betamount": "1.00", "...": "remaining fields as in 003" },
{ "id": "1754882650111003", "serialnumber": "1754882650111003", "betpoint": "TIED", "betamount": "1.00", "...": "remaining fields as in 003" }
],
"sign": "0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b"
}
appid=your_appid
username=player01
notifyid=25081111204577777
type=1
amount=-3.00
currency=THB
serialnumber=1754882650111222
bets=[{"id":"1754882650111001","betpoint":"PLAYER","betamount":"1.00",...},{"id":"1754882650111002","betpoint":"BANKER","betamount":"1.00",...},{"id":"1754882650111003","betpoint":"TIED","betamount":"1.00",...}]
sign=0d8f2e0b8a5c4f1e9c7a6b5d4e3f2a1b
{
"result": 0,
"balance": 97.00,
"orderno": "M20260811004"
}