商户平台OpenAPI文档
开发前须知
成为微游商户
确保已经完成了微游商户的账号注册,可以登录商户平台。若尚未完成,请先完成注册流程。
创建渠道
请根据域名、业务信息、变现策略与模板样式,提交对应的渠道链接申请。



获取访问密钥

API请求说明
请求访问频次
单商户每秒钟请求数上限为10
。超过该上限的请求将被服务拒绝,并且返回如下内容:
{
"code": 429,
"reason": "RATELIMIT",
"message": "service unavailable due to rate limit exceeded",
"metadata": {}
}
签名机制
OpenAPI服务会对所有的API接口请求进行基于密钥签名机制的安全校验。以下为签名机制的详细说明。
密钥获取
参照上面“获取访问密钥”步骤说明获取商户的访问密钥。
签名规则
参数拼接
所有API请求参数(包括 header
中的 ts
时间戳)需按照以下规则进行拼接,最终生成待签名字符串(sign_string)。
URL查询参数(GET 请求的 ?key=value 部分)
POST/PUT 请求体参数(如 application/json 格式)
HTTP Header 中的 ts 时间戳(需纳入签名计算)
参数按 参数名=参数值 的形式拼接,多个参数之间用 & 分隔符连接。
所有参数(包括 ts)需按 参数名的 ASCII 码从小到大排序(字典序),再按顺序拼接。
签名生成
上述拼接后的字符串,前面追加访问密钥
进行SHA256运算,生成的字符串即为签名字符串。
示例:
const crypto = require('crypto');
const https = require('https');
const { URL } = require('url');
const config = {
secretKey: 'xxxx',
clientId: '1234',
baseUrl: 'https://openapi.minigame.com',
};
function generateSignature(domain) {
const timestamp = new Date().getTime();
const signData = `${config.secretKey}domain=${domain}&ts=${timestamp}`;
const sign = crypto.createHash('sha256').update(signData).digest('hex');
console.log('=== 签名生成调试信息 ===');
console.log('使用的密钥:', config.secretKey);
console.log('签名原始字符串:', signData);
console.log('生成签名:', sign);
console.log('当前时间戳:', timestamp);
console.log('商户ID:', config.clientId);
console.log('渠道域名:', domain);
return { timestamp, sign };
}
返回说明
成功返回
请求OpenAPI服务成功返回HTTP.STATUS为200
,body为json格式数据内容。
示例:
{
"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"
}
]
}
错误返回
请求OpenAPI服务成功返回HTTP.STATUS为非200
,body为json格式数据内容。
名称 | 描述 | 类型 | 是否必须 | 示例 | 备注 |
---|
code | 整型错误码 | int | 是 | 429 | 应用如果需要对OpenAPI错误进行处理,不推荐使用 本字段。 |
reason | 字符串错误码 | string | 是 | RATELIMIT | 应用如果需要对OpenAPI错误进行处理,推荐使用 本字段。 |
message | 错误信息 | string | 是 | RATELIMIT | 应用如果需要对OpenAPI错误进行处理,不推荐使用 本字段。 |
示例:
{
"code": 429,
"reason": "RATELIMIT",
"message": "service unavailable due to rate limit exceeded",
"metadata": {}
}
错误码定义
错误码 | 描述 | 备注 |
---|
RATELIMIT | 访问频次到达上限。 | 目前的访问频次限制为商户级别,为10次/秒,超过该频次将有可能返回RATELIMIT 错误。 请合理规划访问频次。 |
UNAUTHORIZED | 未授权。 | 请检查: 请求头x-md-global-cid 是否正确指定了商户唯一标识 ; 请求头sign 是否正确指定了签名; |
SERVER_INTERNAL | 服务器内部错误。 | 请联系平台管理员进行处理。 |
MERCHANT_OPEN_API_INVALID | 商户open-api不可用。 | 请求异常,请联系平台管理员进行处理。 |
MERCHANT_OPEN_API_CHANNEL_NOT_FOUND | 商户渠道不存在。 | 请确认请求指定的渠道是否存在。 |
MERCHANT_OPEN_API_CHANNEL_FORBIDDEN | 商户渠道禁止访问。 | 请确认是否有权限访问指定的渠道。 |
MERCHANT_OPEN_API_GAME_NOT_FOUND | 游戏未找到。 | 请确认是否请求指定的游戏是否存在。 |
API列表
API概览
名称 | 描述 | 功能 |
---|
GetChannelGameLinks | 获取渠道的游戏链接列表 | 调用本接口根据渠道域名获取指定渠道的游戏链接列表 |
GetChannelGameDetail | 获取渠道的游戏详情 | 调用本接口根据渠道域名获取指定渠道的游戏详情 |
GetChannelGameLinks
根据渠道域名获取渠道的游戏链接列表。
请求格式
请求头
名称 | 描述 | 类型 | 是否必须 | 示例 |
---|
sign | 签名 | string | 是 | ca25acec11d7b89259f277b557c0841b9ae68391dd3e35bb3cda7f0c9a790e9e 此值仅为示例,实际值以应用实际请求为准 |
ts | Unix时间戳(毫秒级,13位整数) | int | 是 | 1749193616816 此值仅为示例,实际值以应用实际请求为准 |
x-md-global-cid | 商户唯一标识 | int | 是 | 205150566760842225 此值仅为示例,实际值以应用实际请求为准 |
请求参数
名称 | 描述 | 类型 | 是否必须 | 示例 |
---|
domain | 渠道域名 | string | 是 | emu3lg.minigame.com 此值仅为示例,实际值以应用实际请求为准 |
返回参数
名称 | 描述 | 类型 | 是否必须 |
---|
links | 渠道游戏链接列表 | 结构数组。 每个元素为如下结构: { "app_id":游戏的app_id, "link":游戏在渠道内链接 } | 是 |
示例:
{
"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"
}
]
}
示例代码 (开发语言为javascript)
const crypto = require('crypto');
const https = require('https');
const { URL } = require('url');
const config = {
secretKey: 'xxxx',
clientId: '1234',
baseUrl: 'https://openapi.minigame.com',
};
function generateSignature(domain) {
const timestamp = new Date().getTime();
const signData = `${config.secretKey}domain=${domain}&ts=${timestamp}`;
const sign = crypto.createHash('sha256').update(signData).digest('hex');
console.log('=== 签名生成调试信息 ===');
console.log('使用的密钥:', config.secretKey);
console.log('签名原始字符串:', signData);
console.log('生成签名:', sign);
console.log('当前时间戳:', timestamp);
console.log('商户ID:', config.clientId);
console.log('渠道域名:', domain);
return { timestamp, sign };
}
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();
});
}
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');
}
main().catch(console.error);
GetChannelGameDetail
根据渠道域名和游戏id(app_id)获取渠道的游戏详情。
请求格式
请求头
名称 | 描述 | 类型 | 是否必须 | 示例 |
---|
sign | 签名 | string | 是 | ca25acec11d7b89259f277b557c0841b9ae68391dd3e35bb3cda7f0c9a790e9e 此值仅为示例,实际值以应用实际请求为准 |
ts | Unix时间戳(毫秒级,13位整数) | int | 是 | 1749193616816 此值仅为示例,实际值以应用实际请求为准 |
x-md-global-cid | 商户唯一标识 | int | 是 | 205150566760842225 此值仅为示例,实际值以应用实际请求为准 |
请求参数
名称 | 描述 | 类型 | 是否必须 | 示例 |
---|
domain | 渠道域名 | string | 是 | emu3lg.minigame.com 此值仅为示例,实际值以应用实际请求为准 |
id | 游戏id(app_id) | string | 是 | im-a-game 此值仅为示例,实际值以应用实际请求为准 |
返回参数
名称 | 描述 | 类型 | 是否必须 |
---|
id | 游戏id(app_id) | string | 是 |
detail | 游戏信息结构: name,游戏名称 type,游戏类型,枚举定义参见“游戏类型定义” how_to_play,游戏玩法 description,游戏简介 icon,游戏图标,结构定义参见“素材结构定义” big_icon,游戏大图标,结构定义参见“素材结构定义” banner,游戏Banner宣传图,结构定义参见“素材结构定义” flash,游戏闪屏图,结构定义参见“素材结构定义” link,游戏渠道内链接 | 结构 | 是 |
游戏类型定义
枚举值 | 描述 |
---|
1 | 超休 |
2 | 冒险 |
3 | 音乐 |
4 | 模拟 |
5 | 纸牌 |
6 | 棋类 |
7 | 体育 |
8 | 竞速 |
9 | 益智 |
10 | 策略 |
11 | 动作 |
12 | 战斗 |
13 | 跑酷 |
14 | 射击 |
15 | 装扮 |
16 | 塔防 |
17 | 合成 |
18 | 突破 |
19 | 化妆 |
20 | 博彩 |
21 | 教育 |
22 | 街机 |
23 | 休闲竞技 |
24 | 经营 |
素材结构定义
字段 | 描述 |
---|
uri | 素材uri |
size | 素材尺寸 width,宽度,单位:像素 height,高度,单位:像素 |
示例:
{
"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"
}
}
示例代码 (开发语言为javascript)
const crypto = require('crypto');
const https = require('https');
const { URL } = require('url');
const config = {
secretKey: 'xxxx',
clientId: '1234',
baseUrl: 'https://openapi.minigame.com',
};
function generateSignature(domain, gameId) {
const timestamp = new Date().getTime();
const signData = `${config.secretKey}domain=${domain}&id=${gameId}&ts=${timestamp}`;
const sign = crypto.createHash('sha256').update(signData).digest('hex');
console.log('=== 签名生成调试信息 ===');
console.log('使用的密钥:', config.secretKey);
console.log('签名原始字符串:', signData);
console.log('生成签名:', sign);
console.log('当前时间戳:', timestamp);
console.log('商户ID:', config.clientId);
console.log('渠道域名:', domain);
console.log('游戏ID:', gameId);
return { timestamp, sign };
}
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();
});
}
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',
'crazy-ball',
);
}
main().catch(console.error);
------------------------------------------------------ END ---------------------------------------------------------------------------