API 文档
用程序读取商品、查询库存、自动下单和取货。适合把本站商品接到你自己的网站、机器人或管理系统。
快速开始
- 登录后打开 个人资料,复制
API-ID和API密钥。 - 按 签名算法 计算签名,调用 账号信息 接口。返回
code: 200就说明已接通。 - 调用 商品列表 拿到 SKU 的
id、你的进货价和下单需要填写的控件。 - 充值账户余额。下单时直接从余额扣款,没有单独的支付步骤。
- 调用 下单 接口。自动发货的商品会在返回的
contents里直接给出内容。
API密钥 等同于账户的扣款权限,只能放在服务器上,不要写进网页、App 或公开的代码仓库。调用约定
| 项目 | 说明 |
|---|---|
| 接口地址 | https://maitg.com |
| 请求方法 | 全部使用 POST,其他方法返回 HTTP 405 |
| 参数格式 | application/x-www-form-urlencoded 表单。不支持 JSON 请求体,发 JSON 会提示签名验证失败 |
| 字符编码 | UTF-8 |
请求头 Api-Id | 你的 API-ID,也就是用户 ID |
请求头 Api-Signature | 32 位小写 MD5 签名 |
返回格式
所有接口都返回 JSON。请以 code 判断成败:200 成功,0 失败,失败原因在 msg 里。业务失败时 HTTP 状态码同样是 200。
{"code": 200, "msg": "success", "data": {}}
{"code": 0, "msg": "签名验证失败"}签名算法
- 取本次 POST 的全部参数,去掉
sign、值为空字符串的参数和数组参数。 - 按参数名升序排序,用
参数名=参数值的形式以&连接。这里的值用原文,不做 URL 编码。 - 在末尾加上
&key=你的API密钥。 - 对整个字符串做 MD5,结果放进请求头
Api-Signature。
示例
API 密钥为 your_api_secret,参数为 sku_id=92、quantity=1、trade_no=2611040a1b2c3d4e5f60718293a4b5c6d7e8f9:
待签名:quantity=1&sku_id=92&trade_no=2611040a1b2c3d4e5f60718293a4b5c6d7e8f9&key=your_api_secret 签名: 3eb7b4b2f1dc144e15561365049c3021
没有任何参数时(如账号信息接口),待签名字符串就是 &key=your_api_secret,签名为 a9b1ca478d18596e13ab947246104ae8。
<、> 等 HTML 字符。服务器会先过滤这些字符再验签,签名会对不上。代码示例
<?php
function sign(array $params, string $secret): string
{
unset($params['sign']);
ksort($params);
$pairs = [];
foreach ($params as $key => $value) {
if ($value !== '' && !is_array($value)) {
$pairs[] = $key . '=' . $value;
}
}
return md5(implode('&', $pairs) . '&key=' . $secret);
}
$params = ['page' => 1, 'limit' => 20];
$ch = curl_init('https://maitg.com/plugin/open-api/items');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_HTTPHEADER => [
'Api-Id: 你的API-ID',
'Api-Signature: ' . sign($params, '你的API密钥'),
],
]);
$result = json_decode(curl_exec($ch), true);import hashlib
import requests
def sign(params, secret):
pairs = [f"{k}={params[k]}" for k in sorted(params)
if k != "sign" and params[k] != "" and not isinstance(params[k], (list, dict))]
return hashlib.md5(("&".join(pairs) + "&key=" + secret).encode("utf-8")).hexdigest()
params = {"page": 1, "limit": 20}
result = requests.post(
"https://maitg.com/plugin/open-api/items",
data=params,
headers={"Api-Id": "你的API-ID", "Api-Signature": sign(params, "你的API密钥")},
timeout=30,
).json()const crypto = require('crypto');
function sign(params, secret) {
const pairs = Object.keys(params).sort()
.filter((k) => k !== 'sign' && params[k] !== '' && typeof params[k] !== 'object')
.map((k) => k + '=' + params[k]);
return crypto.createHash('md5').update(pairs.join('&') + '&key=' + secret, 'utf8').digest('hex');
}
const params = { page: 1, limit: 20 };
const response = await fetch('https://maitg.com/plugin/open-api/items', {
method: 'POST',
headers: { 'Api-Id': '你的API-ID', 'Api-Signature': sign(params, '你的API密钥') },
body: new URLSearchParams(params),
});
const result = await response.json();API_ID='你的API-ID' API_KEY='你的API密钥' SIGN=$(printf '%s' "limit=20&page=1&key=$API_KEY" | md5sum | cut -d' ' -f1) curl -X POST 'https://maitg.com/plugin/open-api/items' \ -H "Api-Id: $API_ID" \ -H "Api-Signature: $SIGN" \ -d 'page=1' -d 'limit=20'
账号信息
/plugin/open-api/connect无参数。常用来检查密钥是否正确和读取当前余额。
{"code": 200, "msg": "success", "data": {"username": "demo", "balance": "100.00"}}商品列表
/plugin/open-api/items返回当前账号可以进货的全部商品,价格已按你的用户组、等级和专属价计算。商品多时请使用分页。
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
page | 否 | int | 页码,从 1 开始,最大 1000 |
limit | 否 | int | 每页数量,1~100,只传 page 时默认 100 |
两个参数都不传时返回全部商品,这种方式每 5 秒只能调用一次。分页时 data 不足 limit 条不一定代表已到末页,因为没有可售 SKU 的商品会被隐藏,请翻到 data 为空为止。
商品字段
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 商品 ID,用于 商品详情 |
name | string | 商品名称 |
introduce | string | 商品介绍,HTML 格式 |
picture_url / picture_thumb_url | string | 商品图和缩略图 |
widget | string | 下单控件,JSON 字符串,需要再解析一次,见 下单控件 |
attr | string | 商品属性,JSON 字符串 |
repertory_category_id | int | 分类 ID |
category | object | 分类信息:id、name、icon |
sku | array | 规格列表,下单用的是这里的 id |
SKU 字段
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | SKU ID,下单和查库存时传给 sku_id |
name | string | 规格名称 |
stock_price | string | 你的进货单价 |
stock | string | 库存(缓存值)。可能是数字,也可能是“充足”这类文字 |
picture_url / picture_thumb_url | string | 规格图和缩略图 |
message | string | null | 规格备注 |
market_control | bool | 是否启用了控价和限购。为 true 时下面几项才生效 |
market_control_min_price / market_control_max_price | string | 允许的最低、最高售价 |
market_control_min_num / market_control_max_num | int | 单次最少、最多购买数量,0 表示不限 |
market_control_only_num | int | 累计限购数量,0 表示不限 |
返回示例
{
"code": 200,
"msg": "success",
"data": [{
"id": 71,
"name": "示例商品",
"introduce": "<p>商品介绍</p>",
"widget": "[]",
"attr": "[]",
"picture_url": "/favicon.ico",
"picture_thumb_url": "/favicon.ico",
"repertory_category_id": 8,
"category": {"id": 8, "name": "默认分类", "icon": "/favicon.ico"},
"sku": [{
"id": 92,
"name": "默认规格",
"stock_price": "3.5",
"stock": "22",
"message": null,
"market_control": false,
"market_control_min_num": 0,
"market_control_max_num": 0,
"market_control_only_num": 0
}]
}]
}下单控件
有些商品下单时要填写内容,比如充值账号。把 widget 解析成数组后,每个控件的 name 就是下单时要多传的参数名。设置了 regex 的控件必填,不符合规则时下单会失败,提示内容就是 error。
[{"name": "account", "title": "充值账号", "type": "text", "placeholder": "请输入账号", "regex": "^\\d+$", "error": "账号格式不正确"}]商品详情
/plugin/open-api/item| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
id | 是 | int | 商品 ID,不是 SKU ID |
data 是单个商品对象,字段同 商品列表。商品不存在或你无权进货时返回“货源不存在”。
SKU 库存
/plugin/open-api/sku/stock| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
sku_id | 是 | int | SKU ID |
{"code": 200, "msg": "success", "data": {"stock": "22"}}stock 是字符串,可能是数字,也可能是“充足”这类文字,由商品的库存显示设置决定,而且是缓存值,可能有短暂延迟。
SKU 是否可买
/plugin/open-api/sku/state| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
sku_id | 是 | int | SKU ID |
quantity | 否 | int | 购买数量,默认 1 |
{"code": 200, "msg": "success", "data": {"state": true}}true。批量购买前请用 SKU 库存 里的数字核对。下单
/plugin/open-api/trade从账户余额扣款并发货。
| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
sku_id | 是 | int | SKU ID |
quantity | 否 | int | 购买数量,默认 1 |
trade_no | 是 | string | 你自己生成的订单号:6 位日期 + 32 位字母数字(共 38 位),如 2611040a1b2c3d4e5f60718293a4b5c6d7e8f9。历史的 24 位订单号也可以用 |
async_url | 否 | string | 接收 异步通知 的地址,必须是可公网访问的 http 或 https 地址,不支持内网地址,也不跟随跳转 |
| 控件参数 | 视商品 | string | 参数名取自 下单控件 的 name |
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
contents | string | 发货内容,多张卡密用换行分隔。未发货时是提示文字,请结合 status 判断 |
status | int | 订单状态,见 订单状态 |
trade_no | string | 本站系统生成的订单号 |
item_trade_no | string | 你传入的 trade_no |
amount | string | 实际扣款金额 |
trade_time | string | 下单时间 |
{
"code": 200,
"msg": "success",
"data": {
"contents": "CARD-0001\nCARD-0002",
"status": 1,
"trade_no": "261104YfSD460SEsnHwa8fSPcEfnjO2iSWbyZl",
"item_trade_no": "2611040a1b2c3d4e5f60718293a4b5c6d7e8f9",
"amount": "3.00",
"trade_time": "2026-11-04 18:24:40"
}
}务必注意
code: 200只代表订单已创建并已扣款,不代表已发货。一定要再判断status。- 库存不足时直接拒单。下单时按实际购买数量校验库存,不够就返回
code: 0,不扣款、不生成订单。这个订单号没有被占用,补货后可以继续使用。 - 订单号不能重复。重复提交会返回“订单号已存在”,不会再次扣款。如果请求超时、不确定结果,请用同一个
trade_no调用 查询订单 确认后再决定是否重下。 - 余额不足、商品下架、控件校验不通过时同样返回
code: 0,不会扣款。 - 多人同时抢购时可能返回“当前下单繁忙”(
code: 0),同样不扣款,稍后用同一个trade_no重试即可。 - 库存校验通过后,如果上游发货出错,订单已经创建并扣款:返回
code: 200、未发货的status,contents是提示文字,请联系客服或申请售后。
查询订单
/plugin/open-api/query| 参数 | 必填 | 类型 | 说明 |
|---|---|---|---|
trade_no | 是 | string | 下单时你传入的订单号,不是返回的系统订单号 |
{"code": 200, "msg": "success", "data": {"contents": "CARD-0001", "status": 1, "trade_time": "2026-11-04 18:24:39"}}只能查询自己账号下的订单,查不到时返回“订单不存在”。
异步通知
下单时传了 async_url,之后订单状态变化(如人工发货、退款)时,本站会向这个地址发一次 POST 表单。
| 字段 | 类型 | 说明 |
|---|---|---|
status | int | 订单状态 |
contents | string | 发货内容 |
item_trade_no | string | 你的订单号 |
trade_no | string | 本站系统订单号 |
amount | string | 订单金额 |
trade_time | string | 下单时间 |
验证来源
请求头 Api-Signature 是用你的 API 密钥按 相同算法 对上面字段计算的签名。收到通知后请先验签,再处理订单。同一笔订单可能收到多次通知,请按 item_trade_no 和 status 去重。
<?php
$signature = $_SERVER['HTTP_API_SIGNATURE'] ?? '';
if (!hash_equals(sign($_POST, '你的API密钥'), strtolower($signature))) {
http_response_code(403);
exit('invalid signature');
}
// 处理订单 $_POST['item_trade_no']
echo 'ok';订单状态
| status | 含义 | 建议处理 |
|---|---|---|
0 | 等待发货 | 人工发货、上游处理中,或上游发货出错。稍后查询,长时间不变请联系客服 |
1 | 已发货 | 读取 contents |
2 | 发货失败 | 联系客服或申请售后 |
3 | 已退款 | 款项已退回,结束订单 |
频率限制
按账号计算。所有接口合计每秒最多 30 次,单个接口的限制如下。超出后返回 HTTP 429,Retry-After 响应头是需要等待的秒数。
| 接口 | 限制 |
|---|---|
/items 分页 | 每秒 2 次 |
/items 不分页 | 每 5 秒 1 次 |
/item | 每秒 10 次 |
/sku/stock、/sku/state | 各每秒 15 次 |
/trade | 每秒 10 次 |
/query | 每秒 20 次 |
/connect | 每秒 10 次 |
站点在高负载时还有整体保护,同样返回 HTTP 429。请按 Retry-After 等待后重试,不要循环猛刷。
错误处理
| HTTP | 提示 | 原因和处理 |
|---|---|---|
| 401 | 鉴权参数无效 | 缺少 Api-Id 或 Api-Signature,或格式不对 |
| 405 | 请求方法不允许 | 没有使用 POST |
| 429 | 请求过于频繁 | 见 频率限制 |
| 200 | 签名验证失败 | 对照 示例 检查排序、空值、密钥,以及是否误发了 JSON |
| 200 | 未找到该用户 | Api-Id 填错 |
| 200 | 您的账号暂不可用 | 账号被停用,请联系客服 |
| 200 | 缺少SKU-ID / SKU 不存在 | 检查 sku_id,注意不是商品 ID |
| 200 | 订单号必须是历史24位或新版38位格式 | 按 下单 里的格式生成 trade_no |
| 200 | 订单号已存在 | 更换订单号,或用 查询订单 取结果 |
| 200 | 订单不存在 | 订单号有误,或不是当前账号的订单 |
旧版协议
已经对接旧版萌次元 V3/V4 协议的程序可以继续使用,填写站点根地址和同一组 API-ID、API 密钥即可。新项目请使用上面的接口。
鉴权方式不同:所有接口都在 POST 参数里传 app_id、app_key 和 sign,签名算法相同,app_id 和 app_key 也要参与签名。
| 接口 | 业务参数 | 返回 data |
|---|---|---|
/shared/commodity/connect | 无 | username、balance |
/shared/commodity/items | 无 | 按分类分组的商品,每个 SKU 一条 |
/shared/commodity/item | code 或 sharedCode(SKU ID) | 单个商品 |
/shared/commodity/stock | code | stock |
/shared/commodity/inventory | sharedCode | count |
/shared/commodity/inventoryState | shared_code、num | state |
/shared/commodity/trade | shared_code、num、request_no(你的订单号,64 位以内) | secret(发货内容) |
旧版下单和新接口有两点不同:除库存不足外,发货失败时也直接报错、不扣款;重复提交相同的 request_no 会返回原订单内容。