Skip to content

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 digits
  • request_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:

json
{
  "x": "Encrypted Base64 string"
}
3.2 Example Process
  1. Set request headers:
TEXT
merchant-id: M202405120001
  1. Prepare original request data:
json
{
  "timestamp": 1650123456789,
  "request_id": "abcd-1234-abcd-1234",
  "username": "game001",
  "user_id": "user123",
  "amount": 100
}
  1. After encrypting the original JSON, get the request body:
json
{
  "x": "hG7bVwMRV0Gq+Lh5HvdkE1jBJxHIQcm9z3r4XBY/5r8tXKr1xU0MCvTgn12..."
}

4. Encryption Process

  1. Prepare complete JSON data containing common parameters and business parameters
  2. Use PKCS7 padding method to pad data to multiples of 16 bytes
  3. Use 32-bit key and initialization vector (IV, first 16 bits of the key) to encrypt data through AES-CBC mode
  4. Encode the encrypted data with Base64 to get the value of parameter x
  5. Construct the final request body {"x": "Encrypted Base64 string"}
  6. Add merchant-id to HTTP headers

5. Decryption Process

  1. Extract the value of parameter x from the request body
  2. Decode the ciphertext with Base64
  3. Use the same 32-bit key and initialization vector (IV, first 16 bits of the key) to decrypt data through AES-CBC mode
  4. Remove PKCS7 padding to get the original JSON data
  5. Parse JSON data to extract common parameters and business parameters

6. Code Examples

6.1 Java Implementation
java
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
php
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
javascript
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

  1. HTTP request headers must contain merchant-id merchant ID
  2. Common parameters timestamp and request_id are required
  3. timestamp must be a 13-digit millisecond timestamp
  4. request_id must ensure uniqueness
  5. Key length must be 32 bytes (256 bits)
  6. IV length must be 16 bytes (128 bits)
  7. Ensure all business parameters are encrypted together with common parameters
  8. The final request body only contains the single parameter x
  9. For GET request interfaces, if they are route parameters, the final encrypted data needs URL encoding

8. Error Handling

Common errors and handling methods:

  1. Incorrect key - Confirm if the merchant key is correct
  2. Incorrect IV - Confirm if the IV is correct
  3. merchant-id doesn't exist - Confirm if HTTP headers are set correctly
  4. Timestamp expired - Ensure system time is accurate
  5. Duplicate request ID - Ensure each request generates a unique ID

Response Examples

All interfaces provided by Hash Game use the following standard response format.

json
{
  "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.