Veto Play API Guide
Controller Base Path: /api/game-client
Document Scope: This integration includes 4 APIs: 2 provided by Veto Play and 2 that must be provided by the client.
/game-list does not require encryption. For /launch, /balance, and /coin-transaction, keep wrapper fields such as clientUid and timestamp in plain text and encrypt only the inner payload.
Base URL
https://api.example.com/api/game-client
Integration Overview
| No. | Method | API | Provided By | Purpose |
|---|---|---|---|---|
| 1 | GET | /game-list |
Veto Play | Returns the available game list for the client. |
| 2 | POST | /launch |
Veto Play | Launches the selected game and returns the game launch URL. |
| 3 | POST | /balance |
Client | Checks the player's exact balance from the client before bet deduction logic runs. |
| 4 | POST | /coin-transaction |
Client | Requests player coin deduction or addition and returns either the updated balance on success or a failure response. |
Usage Flow
| Step | Method | Endpoint | Provided By | Encryption | Purpose |
|---|---|---|---|---|---|
| 1 | GET | /game-list |
Veto Play | Not required | Fetch the available game list using required clientUid. |
| 2 | POST | /launch |
Veto Play | Required for payload only |
Launch the selected game and receive the session token and launch URL. |
| 3 | POST | /balance |
Client | Client defined | Fetch the player's exact balance from the client before bet deduction. |
| 4 | POST | /coin-transaction |
Client | Client defined | Send the debit request when the player clicks play and return success with balance or failure. |
| 5 | POST | /coin-transaction |
Client | Client defined | After the game result, send the credit request only when the win amount is greater than 0 and return success with balance or failure. |
1. Get Games
Method: GET
Endpoint: /api/game-client/game-list?clientUid=<YOUR_PURCHASED_CLIENT_UID>
Encryption: Not required
Purpose: Returns the configured game list.
Required Query Param: clientUid
Sample Request:
GET /api/game-client/game-list?clientUid=<YOUR_PURCHASED_CLIENT_UID>
Sample Response:
{
"success": true,
"http_status": 200,
"game_type": "all",
"total": 21,
"games": [
{
"game_uuid": "pyramid_slot",
"game_icon": "https://cdn.example.com/games/slot1.png",
"game_name": "Pyramid Slot",
"game_category": "slot",
"status": 1
},
{
"game_uuid": "pirates_slot",
"game_icon": "https://cdn.example.com/games/slot1.png",
"game_name": "Pirates Slot",
"game_category": "slot",
"status": 1
}
]
}
2. Launch Game
Method: POST
Endpoint: /api/game-client/launch
Encryption: Required for the inner payload
Plain Payload Before Encryption
{
"user_name": "Veto_user_name",
"user_name_to_display": "player_name",
"game_uuid": "pyramid_slot",
"coins": 1000.00,
"redirect_url": "https://client.example.com/game-exit"
}
Request Body After Encryption
{
"clientUid": "<YOUR_PURCHASED_CLIENT_UID>",
"payload": "<encrypted payload>"
}
Request Rules
| Field | Required | Description |
|---|---|---|
clientUid |
Yes | Client identifier sent in plain text. |
payload |
Yes | Encrypted string created from the inner JSON payload. |
Inner Payload Fields
| Field | Required | Description |
|---|---|---|
user_name |
Yes | Unique user ID. |
game_uuid |
Yes | Unique game ID. Example: pyramid_slot |
user_name_to_display |
Yes | Player name shown inside the game. |
coins |
Yes | Player coin balance. |
redirect_url |
Yes | Failover URL used when the game exits or cannot continue. |
Encryption Note
Convert the inner payload JSON to a string, encrypt it using AES-256-GCM and your assigned 32-byte key, then place the encrypted result into the outer payload field.
Sample Response
{
"success": true,
"http_status": 200,
"session_token": "e0cbb392f715482580df8177ad19c058",
"game_uuid": "pushpa_rani",
"user_name": "test_player_01",
"user_name_to_display": "player_name",
"game_launch_url": "https://games.example.com/launch?token=e0cbb392f715482580df8177ad19c058",
"coins": 7657.8
}
Response Fields
| Field | Required | Description |
|---|---|---|
success |
Yes | Returns true when the game launch request is successful. |
http_status |
Yes | HTTP status code. Example: 200 |
session_token |
Yes | Session token generated for the launched game session. |
game_uuid |
Yes | Unique game ID. |
user_name |
Yes | Unique user ID. |
user_name_to_display |
Yes | Display player name shown inside the game. |
game_launch_url |
Yes | Game launch URL returned by the API. |
coins |
Yes | Player coin balance returned in the launch response. |
3. Client API - Balance
Method: POST
Endpoint: /balance
Direction: This API must be provided by the client end.
Purpose: Checks the player's exact balance from the client before bet deduction logic runs.
Behavior: This endpoint is used only to read the current balance. It must not deduct or add coins.
Request Body
{
"clientUid": "<YOUR_PURCHASED_CLIENT_UID>",
"timestamp": "1744112345678",
"payload": "<AES_ENCRYPTED_BASE64>"
}
Outer Request Body Fields
| Field | Required | Description |
|---|---|---|
clientUid |
Yes | Client identifier sent in plain text. |
timestamp |
Yes | Request timestamp in milliseconds. |
payload |
Yes | AES-256-GCM encrypted inner JSON payload encoded in Base64. |
Decrypted Payload
{
"user_name": "player_001",
"game_round": "pyramid_slot_26-04-08-12:00_abc123",
"currency_code": "INR",
"timestamp": "1744112345678",
"mode": "balance",
"coins": 0
}
Note: For /balance, send mode as balance and coins as 0.
Decrypted Payload Fields
| Field | Required | Description |
|---|---|---|
user_name |
Yes | Unique player ID. |
game_round |
Yes | Game round reference sent by the game server. |
currency_code |
Yes | Currency code. Example: INR |
timestamp |
Yes | Current timestamp in milliseconds. |
mode |
Yes | Always send balance for this endpoint. |
coins |
Yes | Send 0 for balance requests. |
Expected Response
{
"payload": "<AES_ENCRYPTED_BASE64>"
}
Outer Response Body Fields
| Field | Required | Description |
|---|---|---|
payload |
Yes | Encrypted response payload containing the current balance. |
Decrypted Response Payload
{
"balance": 10000.0
}
Decrypted Response Payload Fields
| Field | Required | Description |
|---|---|---|
balance |
Yes | Current player coin balance after processing the request. |
4. Client API - Coin Transaction
Method: POST
Endpoint: /coin-transaction
Direction: This API must be provided by the client end.
Purpose: Sends a debit or credit request to the client to deduct or add player coins, and each response must return either success with the updated balance or a failure response.
Behavior: When the player clicks play, Veto Play sends a debit request with the bet amount. If the client returns success, the round proceeds. After the result, Veto Play sends a credit request only when the win amount is greater than 0.
Request Body
{
"clientUid": "<YOUR_PURCHASED_CLIENT_UID>",
"timestamp": "1744112345678",
"payload": "<AES_ENCRYPTED_BASE64>"
}
Outer Request Body Fields
| Field | Required | Description |
|---|---|---|
clientUid |
Yes | Client identifier sent in plain text. |
timestamp |
Yes | Request timestamp in milliseconds. |
payload |
Yes | AES-256-GCM encrypted inner JSON payload encoded in Base64. |
Decrypted Payload
{
"user_name": "player_001",
"game_round": "pyramid_slot_26-04-08-12:00_abc123",
"currency_code": "INR",
"timestamp": "1744112345678",
"mode": "debit",
"coins": 100
}
Note: For /coin-transaction, use mode as debit or credit. coins is the transaction amount.
Credit Request Example
{
"user_name": "player_001",
"game_round": "pyramid_slot_26-04-08-12:00_abc123",
"currency_code": "INR",
"timestamp": "1744112356789",
"mode": "credit",
"coins": 250
}
Credit Rule: After the game result, send coins as the win amount only when the win amount is greater than 0. If the player did not win, do not call the credit API.
Decrypted Payload Fields
| Field | Required | Description |
|---|---|---|
user_name |
Yes | Unique player ID. |
game_round |
Yes | Game round reference sent by the game server. |
currency_code |
Yes | Currency code. Example: INR |
timestamp |
Yes | Current timestamp in milliseconds. |
mode |
Yes | Transaction type. Use debit when deducting the bet amount and credit after the result. |
coins |
Yes | Transaction amount. For debit, send the bet amount. For credit, send the win amount only when it is greater than 0. |
Success Response
{
"payload": "<AES_ENCRYPTED_BASE64>"
}
Success Rule: Both debit and credit responses must return success with the latest balance.
Outer Response Body Fields
| Field | Required | Description |
|---|---|---|
payload |
Yes | Encrypted response payload containing the updated balance for a successful transaction. |
Decrypted Response Payload
{
"success": true,
"balance": 9900.0
}
Decrypted Response Payload Fields
| Field | Required | Description |
|---|---|---|
success |
Yes | Returns true when the coin transaction is completed successfully. |
balance |
Yes | Updated player coin balance after the debit or credit transaction. |
Failure Response - Bet Rejected
If a debit request cannot be completed because the player has insufficient balance, return this failure response instead of a success balance response:
{
"success": false,
"http_status_code": 100118,
"message": "Bet rejected due to insufficient balance"
}
Failure Rule: If the debit call fails, the bet must not proceed. If a credit call fails, return a failure response instead of success.
Encryption Logic
This section shows cross-language AES-256-GCM encryption and decryption examples for the payload field used by POST /launch, /balance, and /coin-transaction.
Encryption Standard
Algorithm: AES-256-GCM
| Component | Size |
|---|---|
| Key | 32 bytes (256 bits) |
| IV (Nonce) | 12 bytes |
| Authentication Tag | 16 bytes |
| Payload Format | Base64(IV + Ciphertext + Tag) |
Shared Key Example (32 bytes):
0123456789abcdef0123456789abcdef
Payload Structure
After encryption the payload format is:
Base64(
IV (12 bytes)
+ Ciphertext
+ AuthTag (16 bytes)
)
Example API Request:
{
"payload": "Base64EncodedEncryptedData"
}
JavaScript (Node.js) Implementation
Encrypt:
const crypto = require("crypto");
const key = Buffer.from("0123456789abcdef0123456789abcdef");
function encrypt(data) {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
let encrypted = cipher.update(JSON.stringify(data), "utf8");
encrypted = Buffer.concat([encrypted, cipher.final()]);
const tag = cipher.getAuthTag();
const payload = Buffer.concat([iv, encrypted, tag]).toString("base64");
return payload;
}
// Example
console.log(encrypt({amount:5000,currency:"INR"}));
Decrypt:
function decrypt(payload) {
const data = Buffer.from(payload, "base64");
const iv = data.slice(0,12);
const tag = data.slice(data.length-16);
const ciphertext = data.slice(12,data.length-16);
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
decipher.setAuthTag(tag);
let decrypted = decipher.update(ciphertext);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
Java Implementation (Core Java)
Encrypt:
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
import java.nio.ByteBuffer;
public class AESUtil {
private static final byte[] KEY =
"0123456789abcdef0123456789abcdef".getBytes();
public static String encrypt(String text) throws Exception {
byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(KEY,"AES");
cipher.init(Cipher.ENCRYPT_MODE,keySpec,
new GCMParameterSpec(128,iv));
byte[] encrypted = cipher.doFinal(text.getBytes());
ByteBuffer buffer =
ByteBuffer.allocate(iv.length + encrypted.length);
buffer.put(iv);
buffer.put(encrypted);
return Base64.getEncoder().encodeToString(buffer.array());
}
}
Decrypt:
public static String decrypt(String payload) throws Exception {
byte[] decoded = Base64.getDecoder().decode(payload);
byte[] iv = new byte[12];
System.arraycopy(decoded,0,iv,0,12);
byte[] cipherTag = new byte[decoded.length - 12];
System.arraycopy(decoded,12,cipherTag,0,cipherTag.length);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(KEY,"AES");
cipher.init(Cipher.DECRYPT_MODE,keySpec,
new GCMParameterSpec(128,iv));
byte[] plaintext = cipher.doFinal(cipherTag);
return new String(plaintext);
}
PHP Implementation
Encrypt:
function encrypt($plaintext,$key){
$iv = random_bytes(12);
$ciphertext = openssl_encrypt(
$plaintext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
$payload = base64_encode($iv.$ciphertext.$tag);
return $payload;
}
$key="0123456789abcdef0123456789abcdef";
echo encrypt("Hello API",$key);
Decrypt:
function decrypt($payload,$key){
$data = base64_decode($payload);
$iv = substr($data,0,12);
$tag = substr($data,-16);
$ciphertext = substr($data,12,-16);
return openssl_decrypt(
$ciphertext,
'aes-256-gcm',
$key,
OPENSSL_RAW_DATA,
$iv,
$tag
);
}
Example Cross-Language Flow
JavaScript Client | | encrypt request v API Request payload = Base64(IV + ciphertext + tag) | v Java Server decrypt(payload) process request encrypt(response) | v PHP Client decrypt(response)
Security Best Practices
- Always use AES-256-GCM.
- Generate a new IV for every encryption.
- Store keys in environment variables or a secure vault.
- Never expose encryption keys in frontend code.
- Always use HTTPS (TLS) in addition to payload encryption.
Summary
| Item | Value |
|---|---|
| Encryption | AES-256-GCM |
| Key Length | 32 bytes |
| IV Length | 12 bytes |
| Tag Length | 16 bytes |
| Payload Format | Base64(IV + Ciphertext + Tag) |
Error Codes
| http_status | Meaning |
|---|---|
200 |
Success |
100110 |
Invalid clientUid or partner disabled. |
100111 |
AES payload decryption failed. |
100112 |
game_uuid not found in game list. |
100113 |
Duplicate active bet. |
100114 |
Missing required field in request. |
100115 |
Session token invalid or expired. |
100116 |
Input validation failed. |
100117 |
Internal server error or partner callback failed. |
100118 |
Bet rejected due to insufficient balance. |
Error Format
When the API returns an error, the response format is:
{
"success": false,
"http_status_code": 100115,
"message": "Invalid or expired session token"
}