{
"code": 0,
"message": "success",
"data": { ... },
"timestamp": 1704355200
}
| 字段 | 类型 | 说明 |
|---|---|---|
| code | int | 状态码,0 表示成功,非 0 表示失败 |
| message | string | 状态描述 |
| data | object | 业务数据 |
| timestamp | int | 响应时间戳 |
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 0 | 成功 | — |
| 1001 | 参数错误 | 检查请求参数 |
| 1002 | 数据不存在 | 检查资源是否存在 |
| 1003 | 重复操作 | 幂等处理,可忽略 |
| 1006 | 未授权 | 检查 AppId 和签名 |
| 1007 | 禁止访问 | 账户可能被停用 |
| 2001 | 余额不足 | 提醒用户充值 |
| 2002 | 超过限量 | 次日重试或联系客服 |
| 3001 | 商品不存在 | 检查商品编码 |
| 3002 | 商品已下架 | 选择其他商品 |
| 3003 | 商品缺货 | 稍后重试 |
| 4001 | 订单不存在 | 检查订单号 |
| 4002 | 订单重复 | 幂等处理,返回原订单 |
| 5001 | 系统错误 | 联系技术支持 |
外部分销商接入开放 API 前,双方需交换以下信息,以便完成网关授权与联调。
| 项目 | 说明 |
|---|---|
| 公司/主体名称 | 用于开通分销商账号 |
| 技术联系人 | 姓名、邮箱、手机,用于接口联调与问题排查 |
| 回调通知地址(notify_url) | 订单状态变更时的 HTTP POST 接收地址,需可公网访问;若暂不确定,可先使用默认或后续在请求中按单传递 |
| IP 白名单地址 | 调用方的发起调用的服务器 IP,用于加入白名单,在 IP 白名单内,方可调用相关接口 |
| 业务说明(可选) | 接入场景、预估量级等,便于配置限流与支持 |
| 项目 | 说明 |
|---|---|
| API 网关地址 | 调用入口 Base URL,所有接口均通过该地址访问 |
| AppId(x-ca-key) | 网关 APP Key,作为请求头 x-ca-key 传递 |
| AppSecret | 网关 APP Secret,用于计算摘要签名,请妥善保管、勿泄露 |
| 商品编码表或商品列表接口说明 | 可供采购的商品及 product_code,用于创建订单时填写 |
完成上述信息对接并完成网关授权后,即可按本文档「鉴权说明」与「接口列表」进行开发与联调。
以上信息会发送至调用方对接人邮箱。
分销商仅通过阿里云 API 网关调用开放 API:请求先经网关(安全认证类型为「阿里云 APP」)校验签名,通过后再转发至业务后端。请勿直连业务后端。
| Header | 必填 | 说明 |
|---|---|---|
| x-ca-key | 是 | APP Key,即分销商 AppId |
| X-Ca-Signature | 是 | 对签名串做 HmacSHA256/HmacSHA1 后 Base64 |
| x-ca-signature-method | 否 | HmacSHA256 或 HmacSHA1,默认 HmacSHA256 |
| X-Ca-Signature-Headers | 否 | 参与签名的 Header 的 Key,英文逗号分隔 |
| Accept | 建议 | 建议显式设置,如 application/json;为空时部分客户端会填 */* 导致验签失败 |
| Content-Type | 按需 | 如 application/json |
| Content-MD5 | 按需 | 有 Body 且非 Form 时可传 Body 的 MD5 的 Base64 |
| Date | 按需 | HTTP 标准 Date 头 |
签名串由以下 7 个字段用换行符 \n拼接,字段为空也保留 \n,大小写敏感:
HTTPMethod
Accept
Content-MD5
Content-Type
Date
Headers
PathAndParameters
Key:Value\n 拼接;多个头末尾保留 \n。不参与签名的头:X-Ca-Signature、X-Ca-Signature-Headers、Accept、Content-MD5、Content-Type、Date。Path?key1=value1&key2=value2...,Query/Form 的 Key 按字典序排序;无参数则不带 ?。Value 为空时只保留 Key;数组参数取第一个 Value。X-Ca-Signature 的值。以下为 GET /api/open/v1/balance、无 Query、无参与签名的自定义头时的示例。
| 项目 | 取值 |
|---|---|
| HTTPMethod | GET |
| Accept | application/json |
| Content-MD5 | (空) |
| Content-Type | (空) |
| Date | (空) |
| Headers | (无自定义头,空) |
| PathAndParameters | /api/open/v1/balance |
| AppSecret(示例) | test_secret_123 |
StringToSign(共 7 行,第 3~6 行为空行):
GET
application/json
/api/open/v1/balance
计算步骤:使用 AppSecret test_secret_123 对上述 StringToSign(UTF-8 编码)做 HmacSHA256,再对二进制结果做 Base64 编码。
得到的 X-Ca-Signature 示例值:
+UA1tPK41ggA7Ufd6SEHW9rITTnahv50U5OggO7h+Fc=
说明:上述签名为基于示例 AppSecret 计算所得,仅供格式与算法对照;实际调用请使用 vipsys 分配的网关 AppId 与 AppSecret,并在网关控制台配置一致的安全认证方式。
以下为阿里云 API 网关摘要签名(HmacSHA256 + Base64)的 Java 实现示例,可直接用于生成请求头 X-Ca-Signature。
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
public class ApiGatewaySign {
/**
* 生成 X-Ca-Signature 头
*
* @param method HTTP 方法,如 GET、POST(大写)
* @param path 路径,如 /api/open/v1/balance
* @param queryParams Query 参数,Key 会按字典序参与 PathAndParameters;可为 null
* @param headersForSign 参与签名的自定义头,Key 会按字典序参与 Headers 段;可为 null
* @param accept Accept 头
* @param contentMd5B64 Content-MD5 的 Base64,无 Body 时传空字符串
* @param contentType Content-Type,无 Body 时传空字符串
* @param date Date 头,可不传时传空字符串
* @param appSecret 网关 AppSecret
* @return Base64 编码的签名,即 X-Ca-Signature 的值
*/
public static String sign(String method,
String path,
Map<String, String> queryParams,
Map<String, String> headersForSign,
String accept,
String contentMd5B64,
String contentType,
String date,
String appSecret) throws Exception {
// PathAndParameters
String pathAndParams = path;
if (queryParams != null && !queryParams.isEmpty()) {
String query = new TreeMap<>(queryParams).entrySet().stream()
.filter(e -> e.getValue() != null && !e.getValue().isEmpty())
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("&"));
if (!query.isEmpty()) {
pathAndParams = path + "?" + query;
}
}
// Headers 段:参与签名的头按 Key 字典序,格式 Key:Value\n
StringBuilder headersSb = new StringBuilder();
if (headersForSign != null && !headersForSign.isEmpty()) {
for (Map.Entry<String, String> e : new TreeMap<>(headersForSign).entrySet()) {
headersSb.append(e.getKey()).append(":").append(e.getValue() != null ? e.getValue() : "").append("\n");
}
}
String stringToSign =
(method != null ? method.toUpperCase() : "") + "\n"
+ (accept != null ? accept : "") + "\n"
+ (contentMd5B64 != null ? contentMd5B64 : "") + "\n"
+ (contentType != null ? contentType : "") + "\n"
+ (date != null ? date : "") + "\n"
+ headersSb
+ pathAndParams;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] signBytes = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(signBytes);
}
// 示例:GET /api/open/v1/balance,无 Query、无自定义头
public static void main(String[] args) throws Exception {
String signature = sign(
"GET",
"/api/open/v1/balance",
null,
null,
"application/json",
"",
"",
"",
"test_secret_123"
);
System.out.println("X-Ca-Signature: " + signature);
// 输出应与文档示例一致: +UA1tPK41ggA7Ufd6SEHW9rITTnahv50U5OggO7h+Fc=
}
}
调用示例(GET 余额):
String xCaSignature = ApiGatewaySign.sign(
"GET",
"/api/open/v1/balance",
null, // 无 Query
null, // 无参与签名的自定义头
"application/json",
"",
"",
"",
"your_app_secret"
);
// 请求头: x-ca-key: your_app_id, X-Ca-Signature: xCaSignature, Accept: application/json
POST 带 Body 时,若网关要求对 Body 做 Content-MD5,可先对 Body 的 UTF-8 字节做 MD5 再 Base64,再传入 contentMd5B64;path 仍为路径不含 Query,如 /api/open/v1/orders。
网关侧可配置时间戳、Nonce 等防重放策略,具体以阿里云控制台为准。
创建充值订单,系统自动发起发货。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| merchant_order_no | string | 是 | 分销商订单号,需保证唯一,最长 64 字符 |
| product_code | string | 是 | 平台商品编码 |
| recharge_account | string | 是 | 充值账号(手机号/QQ号等) |
| notify_url | string | 否 | 回调通知地址,不传则使用默认配置 |
curl -X POST "https://your-gateway.aliyuncs.com/api/open/v1/orders" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "x-ca-key: your_app_id" \
-H "X-Ca-Signature: your_computed_signature" \
-d '{
"merchant_order_no": "M20260104001",
"product_code": "HF-100-0001",
"recharge_account": "13800138000"
}'
请求头中的X-Ca-Signature需按「鉴权说明」中的阿里云摘要签名规则计算;x-ca-key为 vipsys 分配的 AppId。网关地址以 vipsys 提供的为准。
| 参数 | 类型 | 说明 |
|---|---|---|
| order_no | string | 平台订单号 |
| merchant_order_no | string | 分销商订单号 |
| product_code | string | 商品编码 |
| product_name | string | 商品名称 |
| face_value | string | 面值 |
| amount | string | 订单金额(扣款金额) |
| recharge_account | string | 充值账号 |
| order_status | string | 订单状态文本 |
| order_status_code | int | 订单状态码 |
| delivery_status | string | 发货状态文本 |
| delivery_status_code | int | 发货状态码 |
| create_time | string | 创建时间 |
{
"code": 0,
"message": "订单创建成功",
"data": {
"order_no": "ORDER-20260104-A1B2C3D4",
"merchant_order_no": "M20260104001",
"product_code": "HF-100-0001",
"product_name": "话费充值100元",
"face_value": "100.00",
"amount": "95.00",
"recharge_account": "13800138000",
"order_status": "PAID",
"order_status_code": 2,
"delivery_status": "WAITING",
"delivery_status_code": 0,
"create_time": "2026-01-04 10:00:00",
"complete_time": null,
"refund_reason": null
},
"timestamp": 1704355200
}
幂等性:相同 merchant_order_no 重复提交,返回原订单信息;不会重复扣款。
通过平台订单号查询订单详情。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| order_no | string | 是 | 平台订单号 |
curl -X GET "https://your-gateway.aliyuncs.com/api/open/v1/orders/ORDER-20260104-A1B2C3D4" \
-H "Accept: application/json" \
-H "x-ca-key: your_app_id" \
-H "X-Ca-Signature: your_computed_signature"
响应参数:同「创建订单」响应参数。
通过分销商订单号查询订单详情。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| merchant_order_no | string | 是 | 分销商订单号 |
curl -X GET "https://your-gateway.aliyuncs.com/api/open/v1/orders?merchant_order_no=M20260104001" \
-H "Accept: application/json" \
-H "x-ca-key: your_app_id" \
-H "X-Ca-Signature: your_computed_signature"
响应参数:同「创建订单」响应参数。
查询当前账户余额信息。
curl -X GET "https://your-gateway.aliyuncs.com/api/open/v1/balance" \
-H "Accept: application/json" \
-H "x-ca-key: your_app_id" \
-H "X-Ca-Signature: your_computed_signature"
| 参数 | 类型 | 说明 |
|---|---|---|
| cash_balance | string | 现金余额 |
| credit_limit | string | 授信额度 |
| used_credit | string | 已用授信 |
| available_credit | string | 可用授信 |
| available_balance | string | 可用余额(现金+可用授信) |
| frozen_amount | string | 冻结金额 |
{
"code": 0,
"message": "success",
"data": {
"cash_balance": "10000.00",
"credit_limit": "5000.00",
"used_credit": "1000.00",
"available_credit": "4000.00",
"available_balance": "14000.00",
"frozen_amount": "0.00"
},
"timestamp": 1704355200
}
查询当前可用的商品列表。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | int | 否 | 页码,默认 1 |
| page_size | int | 否 | 每页数量,默认 20,最大 100 |
curl -X GET "https://your-gateway.aliyuncs.com/api/open/v1/products?page=1&page_size=20" \
-H "Accept: application/json" \
-H "x-ca-key: your_app_id" \
-H "X-Ca-Signature: your_computed_signature"
| 参数 | 类型 | 说明 |
|---|---|---|
| list | array | 商品列表 |
| list[].product_code | string | 商品编码 |
| list[].product_name | string | 商品名称 |
| list[].category | string | 商品分类(部分商品可能为 null) |
| list[].face_value | string | 面值 |
| list[].supply_price | string | 供货价(您的采购价) |
| list[].delivery_type | int | 发货类型:1=直充,2=券码 |
| list[].recharge_account_type | int | 充值账号类型 |
| list[].stock_status | int | 库存状态:1=有货,2=缺货 |
| list[].daily_limit | int | 日限量(null=不限) |
| list[].daily_remaining | int | 今日剩余(null=不限) |
| pagination | object | 分页信息 |
说明:仅返回「分销商已启用」且「平台商品已上架」的商品。
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"product_code": "HF-100-0001",
"product_name": "话费充值100元",
"category": "话费充值",
"face_value": "100.00",
"supply_price": "95.00",
"delivery_type": 1,
"recharge_account_type": 2,
"stock_status": 1,
"daily_limit": 1000,
"daily_remaining": 800
}
],
"pagination": {
"total": 50,
"page": 1,
"page_size": 20,
"total_pages": 3
}
},
"timestamp": 1704355200
}
订单状态变更时,系统会向 notify_url 发送 HTTP POST 请求。
请求方式:POST · Content-Type:application/json
| 参数 | 类型 | 说明 |
|---|---|---|
| order_no | string | 平台订单号 |
| merchant_order_no | string | 分销商订单号 |
| order_status | string | 订单状态 |
| order_status_code | int | 订单状态码 |
| delivery_status | string | 发货状态 |
| delivery_status_code | int | 发货状态码 |
| complete_time | string | 完成时间(成功时返回) |
| refund_reason | string | 退款原因(退款时返回) |
| timestamp | int | 回调时间戳 |
| sign | string | 回调签名 |
{
"order_no": "ORDER-20260104-A1B2C3D4",
"merchant_order_no": "M20260104001",
"order_status": "COMPLETED",
"order_status_code": 5,
"delivery_status": "SUCCESS",
"delivery_status_code": 2,
"complete_time": "2026-01-04 10:05:00",
"refund_reason": null,
"timestamp": 1704355500,
"sign": "a1b2c3d4e5f6..."
}
使用与请求签名相同的算法验证回调签名:
# 去掉 sign 参数后验证
params = {k: v for k, v in callback_data.items() if k != 'sign'}
expected_sign = generate_sign(params, app_secret)
is_valid = callback_data['sign'].lower() == expected_sign.lower()
返回 JSON 格式:
{
"code": 0,
"message": "success"
}
code=0 表示接收成功| 次数 | 间隔 |
|---|---|
| 第1次 | 1秒 |
| 第2次 | 5秒 |
| 第3次 | 30秒 |
| 第4次 | 5分钟 |
| 第5次 | 30分钟 |
最多重试 10 次,建议实现幂等处理。
| 状态码 | 状态值 | 说明 |
|---|---|---|
| 0 | PENDING | 待支付 |
| 1 | PAYING | 支付中 |
| 2 | PAID | 已支付 |
| 3 | PROCESSING | 处理中 |
| 4 | DELIVERED | 已发货 |
| 5 | COMPLETED | 已完成 |
| 6 | CANCELLED | 已取消 |
| 7 | REFUNDED | 已退款 |
| 状态码 | 状态值 | 说明 |
|---|---|---|
| 0 | WAITING | 待发货 |
| 1 | DELIVERING | 发货中 |
| 2 | SUCCESS | 已成功 |
| 3 | FAILED | 已失败 |
| 类型值 | 说明 |
|---|---|
| 1 | 直充 |
| 2 | 券码 |
| 类型值 | 说明 |
|---|---|
| 1 | 平台账号 |
| 2 | 手机号 |
| 3 | QQ号 |
| 4 | 手机+QQ |
| 5 | QQ+微信 |
merchant_order_no,建议格式:{日期}{序号}