店铺开放平台DEVELOPER DOCUMENTATION
API 文档 v213 · v2 签名返回商店
OPEN API / 店铺共享协议

让你的平台,
连接本站商品。

从同步目录到完成交付,一份文档说明整个流程。支持 PHP、Python、Node.js,以及能发送 HTTP 请求的其他服务端。

站点根地址 / BASE URLhttps://your-site.example

推荐 v2 HMAC 签名表单 POST;兼容旧共享 MD5 协议。

01 / 认证商户 ID + 密钥会员中心获取对接凭据
02 / 同步目录 · 库存 · 价格以当前商户权限和价格为准
03 / 交付下单 → 查询 → 发货异步订单完成后再交付内容
AUTHENTICATION

认证与签名

登录会员中心的控制台,查看“商户 ID”和“商户密钥”。商户 ID 对应 app_id;密钥对应签名函数的 app_key。密钥只保存在你自己的服务器配置中,不放进网页、浏览器请求或公开日志。

公共参数类型说明
app_idstring商户 ID,所有请求必填
signstringv2 为 64 位 HMAC;v1 为 32 位 MD5,均为小写十六进制
app_key仅本地参与签名计算,不提交给接口

推荐:v2 HMAC-SHA256

新客户端默认使用 v2。除 app_id、sign 外,每次提交 signature_version=2、timestamp(Unix 秒)、nonce(16 字节随机数的小写十六进制,共 32 位)。时间偏差不超过 120 秒,同一商户的 nonce 不可重复。

  1. 全部表单字段转字符串,只移除 sign,保留空字符串和 0。
  2. 参数名按 ASCII 升序排序,键和值按 RFC3986 编码(空格编码为 %20),用 & 连接;不能再 urldecode。
  3. 拼接 POST、接口路径、timestamp、nonce、规范表单,使用换行分隔。
  4. 使用商户密钥计算 HMAC-SHA256 小写十六进制签名;通过表单提交,密钥不随请求发送。
$params['signature_version'] = '2';
$params['timestamp'] = (string)time();
$params['nonce'] = bin2hex(random_bytes(16));
unset($params['sign']);
ksort($params, SORT_STRING);
$canonical = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
$path = '/shared/authentication/connect';
$message = "POST\n" . $path . "\n" . $params['timestamp']
    . "\n" . $params['nonce'] . "\n" . $canonical;
$params['sign'] = hash_hmac('sha256', $message, $appKey);
服务端保存商户 nonce 并加锁防重放。已验签的请求即使后续业务失败,也不能复用 nonce。查询原订单时生成新 nonce;付款结果未知时仍不能重新采购。系统时钟需保持同步。v2 使用标准 /shared/… 路径,不使用 index.php?s= 路由别名。
旧客户端兼容:v1 MD5 签名
  1. 组装全部业务字段和 app_id,移除 sign。
  2. 按参数名升序排序;只移除值为空字符串的项,保留 0 和 "0"。
  3. 用 PHP http_build_query(RFC1738)拼接,再追加 &key=你的密钥。
  4. 对整个拼接结果进行一次 urldecode,计算小写 md5。中文统一 UTF-8。
  5. 把签名放入 sign,以 application/x-www-form-urlencoded 发送原始表单参数。
function sign(array $params, string $appKey): string {
    unset($params['sign']);
    ksort($params);
    foreach ($params as $name => $value) {
        if ($value === '') unset($params[$name]);
    }
    return md5(urldecode(http_build_query(
        $params, '', '&', PHP_QUERY_RFC1738
    ) . '&key=' . $appKey));
}
这是现有共享协议的兼容算法。请使用 HTTPS;旧 v1 没有时间戳或 nonce,也不提供严格防重放保证。不要自行改成 HMAC、二次编码或大写 MD5,否则现有接口无法验签。

旧 ACG 客户端可能仍提交 app_key,兼容入口允许其参与原签名;新 SDK 不提交它。旧签名不提供 v2 的防重放和无歧义编码。所有下游迁移后,可在 config/shared-api-v213.php 将 allow_legacy 改为 false;不可在旧客户端迁移前直接停用。

QUICK START

先连接,再读取商品

下载下方客户端,填写服务端环境变量 SHOP_BASE_URL、SHOP_APP_ID、SHOP_APP_KEY。以下示例只读取余额和目录,不创建订单。

客户端使用 30 秒总截止时间、8 MiB 响应上限(可配置);PHP/Python 的连接超时为 10 秒,不跟随重定向,不自动重试请求;订单号使用字符串,金额请使用十进制定点数。下载客户端的采购示例默认处于注释状态。

PRODUCT MODEL

商品、价格与规格

字段 / 概念正确处理
code本站对接商品 CODE;下单使用 shared_code,详情/库存使用 sharedCode。不要用数据库 ID 或上游 shared_code 替代。
factory_price当前商户、会员等级对应的拿货单价,使用最多 5 位小数字符串返回。price / user_price 是其他展示价格,不应直接用作你的采购成本。
configINI 格式文本,不是 JSON。出现 category 时,以种类键作为 race;category_factory 为对应种类拿货价。不要仅依赖普通 factory_price。
minimum / maximum数量下限 / 上限;实际以服务端购买规则为准。num 为份数,不要统一按“每千份”换算,供应商计价规则不等于本站对外商品计价。
widget商品动态表单定义,可能为 JSON 文本。按定义收集字段,再把字段名和值平铺提交到下单表单并参与签名;不要把整个 widget 当成一个 JSON 参数。
delivery_way0 为自动发货、1 为手动发货;自动商品也可能异步完成,不能据此假设下单立即返回卡密。
draft_status1 表示支持预选;先读 draftCard 选择 card_id。预选通常按单卡处理,勿用同一个 card_id 下多份。
商品单价可包含最多 5 位小数,例如 0.03500。不要先把单价保留 2 位再乘数量;指定数量请使用 quote 试算,账单金额以本站返回的 amount 为准,不能承诺 amount 也有 5 位小数。建议服务端用 Decimal / 定点计算,并把大订单号保留为字符串。

列表为空时,检查商品“上架”“开放 API”、所属分类是否启用、会员等级可见性及专属商品限制。部分网络、时长或动态表单商品还需要额外业务参数,不能只用通用三字段下单;以商品字段定义和本站配置为准。

ORDER LIFECYCLE

下单与异步交付

保存接入方业务单号→创建并支付→查询原订单→确认完成后交付
  1. 创建 1–64 位 ASCII 字母数字、下划线或连字符组成的 request_no(不能为 0),例如 商户ID-UUID,先写入你的订单数据库,并对同一业务单加锁。现有服务端单号重复检查是全局的,请加入商户前缀。
  2. 调用 trade 会使用余额付款。成功后保存 tradeNo、amount,不要再次创建付款单。
  3. 用 /shared/integration212/orderStatus 查询。同一商户一次只填 trade_no 或 request_no。
  4. state=pending 时按 next_poll_seconds(默认 5 秒)轮询;持续等待可退避至 10–30 秒。到达你的等待期限后转订单页继续查询,不自动退款或重下。
  5. 只有 state=delivered 且 result_available=true 才交付 secret;pending 的 secret 固定为 null。交付内容原样保存,保留换行,不把它当作 HTML 执行。
unpaid

未确认付款,不发货。

pending

已付款,发货尚未完成。

delivered

本站已保存交付结果,可交付。

付款请求超时、断网、返回 HTML 或“request ID already exists”,都不代表购买失败。请按原 request_no 查询,勿换新单号重发。现有 request_no 检查不构成严格并发幂等;短时间查无订单也不能证明扣款不会稍后完成。

旧 query / query2 的 status=1 仅表示已付款,secret 可能是处理中提示。新接口不触发上游查询和采购,只读取本站订单。服务类商品完成时可能返回服务说明。标记已发货却没有交付内容时返回 attention,停止自动交付并联系本站。退款和部分完成没有单独映射,请联系本站处理,勿根据等待时间自行推断。

API REFERENCE

接口参考

全部使用 POST;成功判断同时检查 HTTP 状态和 JSON code=200。cURL 中的 SIGN、TIMESTAMP、NONCE 需要在服务端按 v2 算法生成。

11 个接口

POST

连接与余额

/shared/authentication/connect

验证商户 ID、签名及当前余额。只读,不扣款。

参数类型要求说明
仅需公共参数 app_id、sign。
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/authentication/connect' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN"
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": {
    "shopName": "示例商店",
    "balance": "100.00"
  }
}
POST

分类与商品列表

/shared/commodity/items

返回分类数组,每个分类的 children 是商品。无分页参数;数组可能为空。仅包含分类启用、商品上架且开放 API,并通过会员可见性检查的商品。

参数类型要求说明
仅需公共参数 app_id、sign。
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/commodity/items' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN"
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": [
    {
      "id": 1,
      "name": "邮箱账号",
      "children": [
        {
          "id": 101,
          "code": "MAIL-DEMO",
          "name": "示例邮箱",
          "factory_price": 0.035,
          "api_status": 1,
          "status": 1,
          "minimum": 1,
          "maximum": 100,
          "delivery_way": 0,
          "draft_status": 0,
          "config": "",
          "widget": null
        }
      ]
    }
  ]
}
POST

单个商品详情

/shared/commodity/item

仍返回“分类 → children”结构,不是单个平铺对象。使用商品 code,不使用本地商品 ID 或上游 shared_code。

参数类型要求说明
sharedCodestring必填商品 code;注意是驼峰名称
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/commodity/item' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN" \
  --data-urlencode 'sharedCode=MAIL-DEMO'
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": [
    {
      "id": 1,
      "name": "邮箱账号",
      "children": [
        {
          "code": "MAIL-DEMO",
          "name": "示例邮箱",
          "factory_price": 0.035,
          "config": "",
          "widget": null
        }
      ]
    }
  ]
}
POST

库存与价格

/shared/commodity/inventory

下单前刷新库存。count 为库存提示,不是锁库承诺;手动发货商品可能返回 99999,不代表真实卡密数。多种类价格见 config.category_factory,勿将 factory_price=0 误作免费。

参数类型要求说明
sharedCodestring必填商品 code
racestring可选种类键,无种类传空字符串
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/commodity/inventory' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN" \
  --data-urlencode 'sharedCode=MAIL-DEMO' \
  --data-urlencode 'race='
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": {
    "count": 100,
    "delivery_way": 0,
    "draft_status": 0,
    "price": 0.3,
    "user_price": 0.25,
    "factory_price": 0.035,
    "is_category": false,
    "config": ""
  }
}
POST

购买数量预检

/shared/commodity/inventoryState

校验当前库存及可选卡密。成功仅代表本次预检通过,实际下单仍可能因库存变化失败。

参数类型要求说明
shared_codestring必填商品 code;此接口使用下划线
numinteger必填购买数量,正整数
card_idinteger可选无预选传 0
racestring可选无种类传空字符串
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/commodity/inventoryState' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN" \
  --data-urlencode 'shared_code=MAIL-DEMO' \
  --data-urlencode 'num=1' \
  --data-urlencode 'card_id=0' \
  --data-urlencode 'race='
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": []
}
POST

预选卡密列表

/shared/commodity/draftCard

仅用于 draft_status=1 的商品。返回预选说明和卡 ID,不返回未购买的卡密。返回分页字段以服务端为准。

参数类型要求说明
sharedCodestring必填商品 code
pageinteger必填页码,建议从 1 开始
limitinteger必填每页数量,建议 20
racestring可选无种类传空字符串
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/commodity/draftCard' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN" \
  --data-urlencode 'sharedCode=MAIL-DEMO' \
  --data-urlencode 'page=1' \
  --data-urlencode 'limit=20' \
  --data-urlencode 'race='
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": {
    "current_page": 1,
    "data": [
      {
        "id": 42,
        "draft": "示例预选说明"
      }
    ],
    "total": 1
  }
}
POST

创建并付款

/shared/commodity/trade

使用商户余额支付,成功即可能扣款。商品 widget 额外字段按名称平铺提交并一起签名。request_no 是接入建议的必填项;旧服务端并未实现严格的并发幂等承诺。超时必须先查原单,不能自动重下。

参数类型要求说明
shared_codestring必填商品 code
numinteger必填购买数量,正整数
request_nostring必填业务单号:1–64 位字母数字、下划线或连字符,不能为 0;建议 商户ID-UUID
contactstring必填联系方式;根据商品要求填写
card_idinteger可选无预选传 0
deviceinteger可选设备标识,默认 0
passwordstring可选查单密码,默认空
racestring可选商品种类键,默认空
frominteger可选默认 0
couponstring可选必须为空,优惠券已停用
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/commodity/trade' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN" \
  --data-urlencode 'shared_code=MAIL-DEMO' \
  --data-urlencode 'num=1' \
  --data-urlencode 'request_no=YOUR_APP_ID-UUID' \
  --data-urlencode '[email protected]' \
  --data-urlencode 'card_id=0' \
  --data-urlencode 'device=0' \
  --data-urlencode 'password=' \
  --data-urlencode 'race=' \
  --data-urlencode 'from=0' \
  --data-urlencode 'coupon='
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": {
    "url": null,
    "amount": 0.04,
    "tradeNo": "905488631289636187",
    "secret": "示例交付内容"
  }
}
POST

指定数量试算

v213 新增
/shared/integration212/quote

只计算本站当前价格,不扣款、不锁库存、不请求供应商。普通商品和静态价格可试算;需要专用参数的 IP 网络及 t57h 服务商品明确拒绝通用试算,避免返回错误金额。最终付款仍以实际订单 amount 为准。

参数类型要求说明
shared_codestring必填本站商品 CODE
numinteger必填1–999999;同时检查商品最少/最多购买限制
racestring可选多种类商品应明确传入种类键
{"code":200,"msg":"success","data":{"code":"MAIL-DEMO","quantity":100,"race":"","unit_price":"0.03500","amount":"3.50","currency":"CNY","binding":false}}
POST

准确查询发货状态

v213 新增
/shared/integration212/orderStatus

v213 新增只读接口,只返回当前商户自己的订单;不触发采购、补单、退款或同步。state=delivered 才交付 secret。pending 时 secret=null;服务类商品的 secret 可能是完成说明,不一定为账号密码。

参数类型要求说明
trade_nostring可选本站订单号;与 request_no 二选一
request_nostring可选接入方业务单号;与 trade_no 二选一
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/integration212/orderStatus' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN" \
  --data-urlencode 'trade_no=905488631289636187'
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": {
    "trade_no": "905488631289636187",
    "request_no": "1001-demo-001",
    "payment_status": 1,
    "delivery_status": 1,
    "state": "delivered",
    "result_available": true,
    "amount": "0.04",
    "currency": "CNY",
    "quantity": 1,
    "secret": "[email protected]_ONLY",
    "next_poll_seconds": null
  }
}
POST

旧版按本站单号查询

/shared/commodity/query

status 是付款状态,不能当作发货完成。旧接口可能返回处理中提示;新接入使用 orderStatus;空交付异常返回 attention。widget 结构与商品有关,不应对外直接展示内部字段。

参数类型要求说明
tradeNostring必填本站订单号,驼峰
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/commodity/query' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN" \
  --data-urlencode 'tradeNo=905488631289636187'
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": {
    "secret": "示例内容或处理中提示",
    "widget": null,
    "status": 1
  }
}
POST

旧版按接入方单号查询

/shared/commodity/query2

查询范围限定当前商户。请求名称是 requestNo,而创建订单时是 request_no;新接入推荐 orderStatus。

参数类型要求说明
requestNostring必填接入方单号,驼峰
cURL 请求示意 先在服务端生成 TIMESTAMP、NONCE 和 SIGN;同一次请求须一致
curl --request POST '{{BASE}}/shared/commodity/query2' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "app_id=$SHOP_APP_ID" \
  --data-urlencode "signature_version=2" \
  --data-urlencode "timestamp=$TIMESTAMP" \
  --data-urlencode "nonce=$NONCE" \
  --data-urlencode "sign=$SIGN" \
  --data-urlencode 'requestNo=YOUR_APP_ID-UUID'
成功响应示例 示意数据,非真实商品或卡密
{
  "code": 200,
  "msg": "success",
  "data": {
    "secret": "示例内容或处理中提示",
    "widget": null,
    "status": 1
  }
}
DEVELOPER RESOURCES

直接带走接入资源

示例客户端使用标准 HTTP 库;PHP 需要 cURL 扩展。为了防止服务器把示例当作程序执行,源文件以 .txt 提供,下载后按说明改名。

OpenAPI 中的站点地址为 /,导入外部工具后替换为本站 HTTPS 根地址。签名需由服务端或工具的请求前置脚本计算;导入文件不会自动完成签名。

TROUBLESHOOTING

错误与排障

接口默认每商户 240 次/分钟、每来源 IP 300 次/分钟,超限返回频率错误并附 Retry-After。服务器仅信任 REMOTE_ADDR;经共享代理接入时应按实际部署评估限额。所有表单字段名使用 ASCII 字母开头的字母、数字或下划线。

现象处理方式
HTTP 200,但 code 不为 200业务失败,读取 msg;不要仅依赖 HTTP 码,也不要硬编码未经承诺的错误编号。
密钥错误 / 签名不能为空检查是否签了所有字段,空字符串被移除而 0 保留;UTF-8、参数排序、签名版本与编码是否一致、时钟偏差、nonce 是否复用、密钥是否已经重置。
商品列表为空检查上架、开放 API、分类启用和会员可见性;确认请求的是 shared/commodity/items。
库存不足 / 最少购买 / 最多购买刷新商品库存和规格;修改数量前先确认前一笔付款单没有成立。
订单不存在检查商户是否一致、单号是否字符串,以及 trade_no / request_no 是否用错;接口只允许查当前商户订单。
返回 404、登录页面或 HTML检查站点根地址、URL 重写、WAF 与 PHP 日志。不要把 HTML 当作 JSON,不要附加后台 /mzt 前缀。
超时 / 5xx / 网络中断付款结果可能未知,先查询原单;只读查询可以退避重试,付款请求禁止盲目重试。
COMPATIBILITY

不同平台如何接入

能编写 HTTP 接口适配器的平台,可按本文的共享协议接入:验证余额 → 展开分类 children → 保存 code → 同步库存与拿货价 → 余额下单 → 查询交付结果。只支持固定供应商协议的平台,需要编写对应适配器。

已有“ACG 店铺共享”驱动的平台,可先用商户 ID / 密钥配置本站根地址,检查该驱动是否正确处理异步发货。新适配器建议使用本页的 orderStatus,而非把旧 status=1 直接判成已发货。

本站原有独角 Next 上游协议使用独立的 /api/v1/upstream/… 路径及 HMAC 请求头,属于另一套协议,部署时还依赖对应的 URL 重写。本页共享协议的签名和参数不能与其混用。

API 面向服务端,不依赖网页登录 Cookie。本页不提供会扣款的在线调试按钮,也不收集或保存真实密钥。目录缓存可按业务需求设置,付款前重新读取库存与价格。