Communication Protocol
Environment Address
- Interface address prefix: Please contact the official team to obtain
Access Authorization
Merchants need to apply for access authorization from the official team before integration, including the following:
- Basic information
- Interface domain
- Whitelist IP
After the application is approved, the official team will issue access authorization to merchants, including:
- Merchant ID (merchant-id): Unique numeric identifier
- Merchant authorization private key (secret): Protocol encryption key, 32-character length string
The above authorization information will be used in interface interactions between merchant servers and official servers. Merchants need to keep it secure, and the secret key information should only exist on the server.
If authorization information is lost or leaked, you can apply to the official team for replacement. Replacing authorization does not affect the use of existing data (users, funds, orders, etc.)
Communication Standards
Encryption Algorithm
1. Overview
The encryption scheme used in game integration APIs adopts AES-256-CBC mode combined with PKCS7 padding for data encryption and decryption. In API requests, all business data needs to be encrypted and passed through parameter x.
2. Encryption Algorithm Details
- Encryption Algorithm: AES (Advanced Encryption Standard)
- Key Length: 256 bits (32 bytes)
- Encryption Mode: CBC (Cipher Block Chaining)
- Padding Method: PKCS7
- **Initialization Vector (IV)**: 16 bytes, needs to be passed with each request or generated using agreed method
3. Request Format Description
3.2 Request Body Format
All request headers must contain the following parameters:
merchant-id: Merchant ID, used to identify the integrated merchant identity
All request bodies must contain the following common parameters before encryption:
timestamp: int64 type, represents current timestamp, accurate to milliseconds, 13 digitsrequest_id: string type, unique request ID
These common parameters together with business parameters form a JSON object, which is encrypted and sent through the single parameter x:
{
"x": "Encrypted Base64 string"
}3.2 Example Process
- Set request headers:
merchant-id: M202405120001- Prepare original request data:
{
"timestamp": 1650123456789,
"request_id": "abcd-1234-abcd-1234",
"username": "game001",
"user_id": "user123",
"amount": 100
}- After encrypting the original JSON, get the request body:
{
"x": "hG7bVwMRV0Gq+Lh5HvdkE1jBJxHIQcm9z3r4XBY/5r8tXKr1xU0MCvTgn12..."
}4. Encryption Process
- Prepare complete JSON data containing common parameters and business parameters
- Use PKCS7 padding method to pad data to multiples of 16 bytes
- Use 32-bit key and initialization vector (IV, first 16 bits of the key) to encrypt data through AES-CBC mode
- Encode the encrypted data with Base64 to get the value of parameter
x - Construct the final request body
{"x": "Encrypted Base64 string"} - Add merchant-id to HTTP headers
5. Decryption Process
- Extract the value of parameter
xfrom the request body - Decode the ciphertext with Base64
- Use the same 32-bit key and initialization vector (IV, first 16 bits of the key) to decrypt data through AES-CBC mode
- Remove PKCS7 padding to get the original JSON data
- Parse JSON data to extract common parameters and business parameters
6. Code Examples
6.1 Java Implementation
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class APIRequestExample {
private static final String SECRET_KEY = "32-bit key, needs to be consistent with server";
private static final String IV = "16-bit initialization vector";
private static final String MERCHANT_ID = "M202405120001";
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static void sendRequest(String apiUrl, Map<String, Object> businessParams) throws Exception {
// Add common parameters
businessParams.put("timestamp", System.currentTimeMillis());
businessParams.put("request_id", generateRequestId());
// Convert complete parameters to JSON
String jsonData = OBJECT_MAPPER.writeValueAsString(businessParams);
// Encrypt
String encryptedData = encrypt(jsonData, SECRET_KEY, IV);
// Construct final request body
Map<String, String> requestBody = new HashMap<>();
requestBody.put("x", encryptedData);
String finalRequestBody = OBJECT_MAPPER.writeValueAsString(requestBody);
// Send HTTP request
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(apiUrl);
// Set request headers
httpPost.setHeader("Content-Type", "application/json");
httpPost.setHeader("merchant-id", MERCHANT_ID);
// Set request body
StringEntity entity = new StringEntity(finalRequestBody);
httpPost.setEntity(entity);
// Execute request
httpClient.execute(httpPost);
}
}
private static String encrypt(String plainText, String key, String iv) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes("UTF-8"));
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encrypted);
}
private static String generateRequestId() {
return "req_" + System.nanoTime();
}
public static void main(String[] args) throws Exception {
Map<String, Object> params = new HashMap<>();
params.put("game_id", "game001");
params.put("user_id", "user123");
params.put("amount", 100);
sendRequest("https://api.example.com/game/action", params);
}
}6.2 PHP Implementation
function sendRequest($apiUrl, $businessParams) {
// Add common parameters
$businessParams['timestamp'] = round(microtime(true) * 1000);
$businessParams['request_id'] = 'req_' . uniqid();
// Convert to JSON
$jsonData = json_encode($businessParams);
// Encrypt
$key = "32-bit key, needs to be consistent with server";
$iv = "16-bit initialization vector";
$encryptedData = encrypt($jsonData, $key, $iv);
// Construct final request body
$requestBody = ['x' => $encryptedData];
$finalRequestBody = json_encode($requestBody);
// Set HTTP headers
$headers = [
'Content-Type: application/json',
'merchant-id: M202405120001'
];
// Send request
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $finalRequestBody);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
function encrypt($plaintext, $key, $iv) {
$method = "AES-256-CBC";
$encrypted = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($encrypted);
}
// Usage example
$params = [
'game_id' => 'game001',
'user_id' => 'user123',
'amount' => 100
];
$response = sendRequest("https://api.example.com/game/action", $params);
echo $response;6.3 Node.js Implementation
const crypto = require('crypto')
const axios = require('axios')
async function sendRequest(apiUrl, businessParams) {
// Add common parameters
businessParams.timestamp = Date.now()
businessParams.request_id = 'req_' + Date.now() + Math.random().toString(36).substring(2, 10)
// Convert to JSON
const jsonData = JSON.stringify(businessParams)
// Encrypt
const key = '32-bit key, needs to be consistent with server'
const iv = '16-bit initialization vector'
const encryptedData = encrypt(jsonData, key, iv)
// Construct final request body
const requestBody = { x: encryptedData }
// Set HTTP headers
const headers = {
'Content-Type': 'application/json',
'merchant-id': 'M202405120001',
}
// Send request
try {
const response = await axios.post(apiUrl, requestBody, { headers })
return response.data
} catch (error) {
console.error('Request failed:', error)
throw error
}
}
function encrypt(plaintext, key, iv) {
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), Buffer.from(iv))
let encrypted = cipher.update(plaintext, 'utf8', 'base64')
encrypted += cipher.final('base64')
return encrypted
}
// Usage example
async function test() {
const params = {
game_id: 'game001',
user_id: 'user123',
amount: 100,
}
try {
const response = await sendRequest('https://api.example.com/game/action', params)
console.log('Response:', response)
} catch (error) {
console.error('Error:', error)
}
}
test()7. Important Notes
- HTTP request headers must contain
merchant-idmerchant ID - Common parameters
timestampandrequest_idare required timestampmust be a 13-digit millisecond timestamprequest_idmust ensure uniqueness- Key length must be 32 bytes (256 bits)
- IV length must be 16 bytes (128 bits)
- Ensure all business parameters are encrypted together with common parameters
- The final request body only contains the single parameter
x - For GET request interfaces, if they are route parameters, the final encrypted data needs URL encoding
8. Error Handling
Common errors and handling methods:
- Incorrect key - Confirm if the merchant key is correct
- Incorrect IV - Confirm if the IV is correct
- merchant-id doesn't exist - Confirm if HTTP headers are set correctly
- Timestamp expired - Ensure system time is accurate
- Duplicate request ID - Ensure each request generates a unique ID
Response Examples
All interfaces provided by Hash Game use the following standard response format.
{
"code": 0,
"msg": "success",
"data": {}
}- code: Response code, 0 means success, non-zero means an error occurred.
- msg: Response message, when code != 0, msg contains error information.
- data: When successful response contains data content, it will exist in the data property as an object or array; when no data needs to be returned, the data property will not exist.

