Merchant Platform OpenAPI Documentation

Before You Start

Become a MiniGame Merchant

Ensure that you have completed the registration of the MiniGame merchant account and can log in to the merchant platform. If not, please complete the registration and login first.

Create a Channel

Create the corresponding channel based on the domain, template, and monetization strategy.
image.png

image.png


Obtain Access Keys

image.png

API Request Instructions

Request Frequency

Each merchant is limited to 10 requests per second. Excess requests will be rejected with:

{
    "code": 429,
    "reason": "RATELIMIT",
    "message": "service unavailable due to rate limit exceeded",
    "metadata": {}
}

Signature Mechanism

The OpenAPI service performs security verification on all API requests using a key-based signature mechanism. Details are as follows:

Key Acquisition

Refer to the "Obtain Access Keys" section above to retrieve the merchant's access keys.

Signature Rules

Parameter Concatenation

All API request parameters (including the header timestamp in ts )must be concatenated into a signable string (sign_string) following these rules:

  • Parameter Concatenation

  1. URL query parameters (for GET requests: the ?key=value part)

  2. POST/PUT request body parameters (e.g., application/json format)

  3. ts timestamp in the HTTP Header (must be included in the signature)

  • Concatenation Format

Parameters are joined in the format key=value, with multiple parameters separated by &.

  • Sorting Rule

All parameters (including ts) must be sorted in ASCII ascending order (lexicographical order) and then concatenated in sequence.

Signature Generation

The concatenated string is prefixed with theaccess key, then hashed using SHA256. The resulting string is the signature.

Example:

const crypto = require('crypto');
const https = require('https');
const { URL } = require('url');

// Configuration parameters
const config = {
  secretKey: 'xxxx', // Access key — replace with actual value; it's recommended to use environment variables
  clientId: '1234', // Merchant ID — replace with actual value; it's recommended to use environment variables
  baseUrl: 'https://openapi.minigame.com', // API address
};

/**
 * Generate signature string
 * @param {string} domain - Channel domain
 * @returns {object} containing timestamp and signature string
 */
function generateSignature(domain) {
  // Get current timestamp (millisecond precision)
  const timestamp = new Date().getTime();

  // Strict concatenation following Java implementation rules
  // Note: Adjust concatenation order and format according to your business rules
  const signData = `${config.secretKey}domain=${domain}&ts=${timestamp}`;

  // Generate SHA256 signature
  const sign = crypto.createHash('sha256').update(signData).digest('hex');

  console.log('=== Signature Generation Debug Info ===');
  console.log('Secret key used:', config.secretKey);
  console.log('Original signature string:', signData);
  console.log('Generated signature:', sign);
  console.log('Current timestamp:', timestamp);
  console.log('Merchant ID:', config.clientId);
  console.log('Channel domain:', domain);

  return { timestamp, sign };
}

Response Description

Successful Response

A successful request to the OpenAPI service returns HTTP status code 200, with the response body in JSON format.

Example:

{
    "links": [
        {
            "app_id": "xingchenqiyuan-ceshi",
            "link": "https://tgm.minigamebm.com/game/xingchenqiyuan-ceshi/play"
        },
        {
            "app_id": "before-the-divine-register",
            "link": "https://tgm.minigamebm.com/game/before-the-divine-register/play"
        }
    ]
}

Error Response

A successful request to the OpenAPI service returns a non-200 HTTP status code, with the response body in JSON format.

  • Parameter Details

NameDescriptionTypeRequiredExampleNotes
codeInteger error codeintYes429Not recommended for applications to handle OpenAPI errors using this field.
reasonString error codestringYesRATELIMITRecommended for applications to handle OpenAPI errors using this field.
messageError messagestringYesRATELIMITNot recommended for applications to handle OpenAPI errors using this field.

Example:

{
    "code": 429,
    "reason": "RATELIMIT",
    "message": "service unavailable due to rate limit exceeded",
    "metadata": {}
}
Error Code Definitions
Error CodeDescriptionNotes
RATELIMITRequest rate limit reached.The current rate limit is 10 requests/second per merchant. Requests exceeding this limit may return a RATELIMIT error. Please plan your request frequency accordingly.
UNAUTHORIZEDUnauthorized.Please check: x-md-global-cidheader contains the correct merchant ID; sign header contains a valid signature;
SERVER_INTERNALInternal server error.Contact platform administrators for assistance.
MERCHANT_OPEN_API_INVALIDMerchant open-api unavailable.Abnormal request. Contact platform administrators.
MERCHANT_OPEN_API_CHANNEL_NOT_FOUNDMerchant channel does not exist.Verify if the specified channel exists.
MERCHANT_OPEN_API_CHANNEL_FORBIDDENMerchant channel access forbidden.Confirm permissions for the target channel.
MERCHANT_OPEN_API_GAME_NOT_FOUNDGame not found.Verify if the specified game exists.

API List

API Overview

NameDescriptionFunction
GetChannelGameLinksGet game link list for a channelRetrieves the list of game links for a specified channel based on the channel domain
GetChannelGameDetailGet game details for a channelRetrieves detailed game information for a specified channel based on the channel domain

Retrieves the list of game links for a channel based on the channel domain.

Request Format

Request Headers

NameDescriptionTypeRequiredExample
signSignaturestringYesca25acec11d7b89259f277b557c0841b9ae68391dd3e35bb3cda7f0c9a790e9e
Example only. The actual value should be based on the actual request.
tsUnix timestamp (millisecond precision, 13-digit integer)intYes1749193616816
Example only. The actual value should be based on the actual request
x-md-global-cidMerchant unique identifierintYes205150566760842225
Example only. The actual value should be based on the actual request.

Request Parameters

NameDescriptionTypeRequiredExample
domainChannel domainstringYesemu3lg.minigame.com
Example only. The actual value should be based on the actual request.

Response Parameters

NameDescriptionTypeRequired
linksList of channel game linksStructural array.
Structure of each array element:
{
"app_id": "Game's app_id",
"link": "Game URL within the channel"
}
Yes

Example:

{
    "links": [
        {
            "app_id": "xingchenqiyuan-ceshi",
            "link": "https://tgm.minigamebm.com/game/xingchenqiyuan-ceshi/play"
        },
        {
            "app_id": "before-the-divine-register",
            "link": "https://tgm.minigamebm.com/game/before-the-divine-register/play"
        }
    ]
}

Sample Code (javascript)

const crypto = require('crypto');
const https = require('https');
const { URL } = require('url');

// Configuration parameters
const config = {
  secretKey: 'xxxx', // Access key — replace with actual value; it's recommended to use environment variables
  clientId: '1234', // Merchant ID — replace with actual value; it's recommended to use environment variables
  baseUrl: 'https://openapi.minigame.com', // API address
};

/**
 * Generate signature string
 * @param {string} domain - Channel domain
 * @returns {object} containing timestamp and signature string
 */
function generateSignature(domain) {
  // Get current timestamp (millisecond precision)
  const timestamp = new Date().getTime();

  // Strict concatenation following Java implementation rules
  // Note: Adjust concatenation order and format according to your business rules
  const signData = `${config.secretKey}domain=${domain}&ts=${timestamp}`;

  // Generate SHA256 signature
  const sign = crypto.createHash('sha256').update(signData).digest('hex');

  console.log('=== Signature Generation Debug Info ===');
  console.log('Secret key used:', config.secretKey);
  console.log('Original signature string:', signData);
  console.log('Generated signature:', sign);
  console.log('Current timestamp:', timestamp);
  console.log('Merchant ID:', config.clientId);
  console.log('Channel domain:', domain);

  return { timestamp, sign };
}

/**
 * Encapsulated HTTPS request function
 * @param {string} url - Request URL
 * @param {object} headers - Request Headers(Request Headers)
 * @returns {Promise} Response parameters
 */
function httpsRequest(url, headers = {}) {
  return new Promise((resolve, reject) => {
    const urlObj = new URL(url);

    const options = {
      hostname: urlObj.hostname,
      port: urlObj.port || 443,
      path: urlObj.pathname + urlObj.search,
      method: 'GET',
      headers: headers,
    };

    const req = https.request(options, (res) => {
      let data = '';

      res.on('data', (chunk) => {
        data += chunk;
      });

      res.on('end', () => {
        try {
          const parsedData = JSON.parse(data);
          resolve({
            status: res.statusCode,
            data: parsedData,
          });
        } catch (error) {
          resolve({
            status: res.statusCode,
            data: data,
          });
        }
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.end();
  });
}

/**
 * Get game list
 * @param {string} domain  - Channel domain
 */
async function getGames(domain) {
  try {
    console.log(`\n=== Requesting ${domain} game list ===`);

    const { timestamp, sign } = generateSignature(domain);

    const url = `${config.baseUrl}/openapi/v2/channel/${domain}/game/links`;
    const response = await httpsRequest(url, {
      sign: sign,
      ts: timestamp.toString(),
      'x-md-global-cid': config.clientId,
    });

    console.log(url);

    console.log('Response status:', response.status);
    console.log('Response data:', JSON.stringify(response.data, null, 2));
  } catch (error) {
    console.error('Request failed:', error.message);
  }
}

async function main() {
  console.log('Starting API requests...\n');

  await getGames('minigame.com'); // Replace with actual channel domain
}

main().catch(console.error);

GetChannelGameDetail

Retrieve game details for a channel based on the channel domain and game ID (app_id).

Request Format

Request Headers

NameDescriptionTypeRequiredExample
signSignaturestringYesca25acec11d7b89259f277b557c0841b9ae68391dd3e35bb3cda7f0c9a790e9e
Example only. The actual value should be based on the actual request.
tsUnix timestamp (millisecond precision, 13-digit integer)intYes1749193616816
Example only. The actual value should be based on the actual request.
x-md-global-cidMerchant unique identifierintYes205150566760842225
Example only. The actual value should be based on the actual request.

Request Parameters

NameDescriptionTypeRequiredExample
domainChannel domainstringYesemu3lg.minigame.com
Example only. The actual value should be based on the actual request.
idGame id(app_id)stringYesim-a-game
Example only. The actual value should be based on the actual request.

Response Parameters

NameDescriptionTypeRequired
idGame id(app_id)stringYes
detailGame information structure:
name,Game name
type,Game type (see “Game Type Definitions” for enum values)
how_to_play,How to play
description,Game description
icon,Game icon (see “Asset Structure Definition”)
big_icon,Large game icon (see “Asset Structure Definition”)
banner,Promotional banner image (see“Asset Structure Definition”)
flash,Splash screen image (see “Asset Structure Definition”)
link,In-channel game URL
structureYes

Game Type Definitions

Enum ValueDescription
1Casual
2Adventure
3Music
4Simulation
5Card
6Board
7Sports
8Racing
9Puzzle
10Strategy
11Action
12Battle
13Parkour
14Shooting
15Dress Up
16Tower Defense
17Synthesis
18Break Through
19Make Up
20Casino
21Education
22Arcade
23.io
24Operate

Asset Structure Definition

FieldDescription
uriAsset uri
sizeMaterial size
width:Width (in pixels)
height:Height (in pixels)

Example:

{
    "id": "xingchenqiyuan-ceshi",
    "detail": {
        "name": "poxiaoxulie-658song7tian.danshi",
        "type": 3,
        "how_to_play": "",
        "description": "",
        "icon": {
            "uri": "https://asset.minigamecloud.com/minicloud-open/developer/uuppii_icon.png",
            "size": {
                "width": 256,
                "height": 256
            }
        },
        "big_icon": {
            "uri": "https://asset.minigamecloud.com/minicloud-open/developer/popstone2_big_icon.png",
            "size": {
                "width": 512,
                "height": 512
            }
        },
        "banner": {
            "uri": "https://asset.minigamecloud.com/minicloud-open/developer/game/cp/108872806854295552/04ab6803-3dfb-45fe-8f36-d87390edfded.png",
            "size": {
                "width": 580,
                "height": 390
            }
        },
        "flash": {
            "uri": "https://asset.minigamecloud.com/minicloud-open/developer/game/cp/108872806854295552/cd0d7487-3a6d-4af0-99b2-7fd237c28a50.png",
            "size": {
                "width": 720,
                "height": 1280
            }
        },
        "link": "https://tgm.minigamebm.com/game/xingchenqiyuan-ceshi/play"
    }
}

Sample Code (JavaScript)

const crypto = require('crypto');
const https = require('https');
const { URL } = require('url');

// Configuration parameters
const config = {
  secretKey: 'xxxx', // Access key — replace with actual value; it's recommended to use environment variables
  clientId: '1234', // Merchant ID — replace with actual value; it's recommended to use environment variables
  baseUrl: 'https://openapi.minigame.com', // API address
};

/**
 * Generate signature string
 * @param {string} domain - Channel domain
 * @param {string} gameId - Game ID(app_id)
 * @returns {object} containing timestamp and signature string
 */
function generateSignature(domain, gameId) {
  // Get current timestamp (millisecond precision)
  const timestamp = new Date().getTime();

  // Strict concatenation following Java implementation rules
  // Note: Adjust concatenation order and format according to your business rules
  const signData = `${config.secretKey}domain=${domain}&id=${gameId}&ts=${timestamp}`;

  // Generate SHA256 signature
  const sign = crypto.createHash('sha256').update(signData).digest('hex');

  console.log('=== Signature Generation Debug Info ===');
  console.log('Secret key used:', config.secretKey);
  console.log('Original signature string:', signData);
  console.log('Generated signature:', sign);
  console.log('Current timestamp:', timestamp);
  console.log('Merchant ID:', config.clientId);
  console.log('Channel domain:', domain);
  console.log('Game ID:', gameId);

  return { timestamp, sign };
}

/**
 * Encapsulated HTTPS request function
 * @param {string} url - Request URL
 * @param {object} headers - Request Headers(Request Headers)
 * @returns {Promise} Response parameters
 */
function httpsRequest(url, headers = {}) {
  return new Promise((resolve, reject) => {
    const urlObj = new URL(url);

    const options = {
      hostname: urlObj.hostname,
      port: urlObj.port || 443,
      path: urlObj.pathname + urlObj.search,
      method: 'GET',
      headers: headers,
    };

    const req = https.request(options, (res) => {
      let data = '';

      res.on('data', (chunk) => {
        data += chunk;
      });

      res.on('end', () => {
        try {
          const parsedData = JSON.parse(data);
          resolve({
            status: res.statusCode,
            data: parsedData,
          });
        } catch (error) {
          resolve({
            status: res.statusCode,
            data: data,
          });
        }
      });
    });

    req.on('error', (error) => {
      reject(error);
    });

    req.end();
  });
}

/**
 * Get game details
 * @param {string} domain - Channel domain
 * @param {string} gameId - Game ID(app_id)
 */
async function getGameInfo(domain, gameId) {
  try {
    console.log(`\n=== Requesting ${domain} game ${gameId} details ===`);

    const { timestamp, sign } = generateSignature(domain, gameId);

    const response = await httpsRequest(
      `${config.baseUrl}/openapi/v2/channel/${domain}/game/${gameId}/detail`,
      {
        sign: sign,
        ts: timestamp.toString(),
        'x-md-global-cid': config.clientId,
      },
    );

    console.log('Response status:', response.status);
    console.log('Response data:', JSON.stringify(response.data, null, 2));
  } catch (error) {
    console.error('Request failed:', error.message);
  }
}

async function main() {
  console.log('Starting API requests...\n');

  await getGameInfo(
    'minigame.com', // Please replace with the actual channel domain name
    'crazy-ball', // Replace with actual game ID(app_id)
  );
}

main().catch(console.error);

------------------------------------------------------ END ---------------------------------------------------------------------------

Business Development
Business Development
Official Account
Official Account