开放平台文档
该部分内容供有云平台研发能力的公司做接口接入,平台开放基础服务能力包括但不限于:
- 聚合支付
- 电子发票
- 广告联盟
- 停车业务
- 充电业务
- 车联网业务
- 营销业务
等功能。
您可联系平台商务获得技术以及商务政策信息,平台将安排专人协助完成功能接入。
1 网关与环境
平台提供两个接入网关,请选择与接口路径对应的域名发起请求:
| 网关 | 接口路径前缀 | 生产环境 | 测试环境 |
|---|---|---|---|
| 支付接入网关 | /gate/1.0/payment/* |
https://papi.4pyun.com |
https://dev-api.4pyun.com |
| 开放平台网关 | /gate/1.0/parking/*/gate/1.0/invoice/*/gate/1.0/energy/*/gate/1.0/adverting/*/gate/1.0/bonus/*/gate/1.0/dataware/* |
https://api.4pyun.com |
https://dev-api.4pyun.com |
[!WARNING|label:如何判断用哪个网关] 只看接口路径:以
payment/开头的一律走支付网关(papi),其余全部走开放网关(api)。例:
POST /gate/1.0/payment/trade/create应请求https://papi.4pyun.com/gate/1.0/payment/trade/create;GET /gate/1.0/parking/realtime/space应请求https://api.4pyun.com/gate/1.0/parking/realtime/space。
1.1 接入凭证
app_id / app_secret 由平台分配(对接方需提供公司全称,由商务提交研发申请)。
两个网关共用同一套凭证、同一套签名算法,同一 app_id 可同时调用支付网关与开放网关接口。
1.2 其它域名
以下域名不属于接口网关,按场景使用:
| 域名 | 用途 |
|---|---|
https://auth.4pyun.com |
用户授权(详见用户授权) |
https://app.4pyun.com |
支付中转页,即交易接口返回的 pay_url |
https://qr.4pyun.com |
停车优惠二维码 |
https://ad-api.4pyun.com |
广告服务(小程序需配置该域名) |
https://assets.4pyun.com |
广告 JS SDK 静态资源 |
2 公共请求参数
所有接口(含平台主动发起的回调通知)均携带以下公共参数:
| 字段 | 说明 | 示例 |
|---|---|---|
| app_id | 应用ID, 由P云平台分配 | op12defadfad |
| timestamp | 当前请求时间戳, 单位毫秒 | 1570318158852 |
| sign | 签名数据,具体规则见签名算法 | 1A6FE20BDD05B654F8FD33A299D75DF3 |
| sign_type | 签名算法 | MD5 |
其中 app_id 必须参与签名;timestamp、sign_type 若实际传入则一并参与排序;sign 本身不参与签名。
3 签名算法
两个网关使用完全相同的签名算法,差异仅在于请求载体(URL 参数 / 表单 / JSON)不同时,待签字符串的拼装方式与签名值的传递位置不同。
3.1 算法执行步骤
- 设所有发送或接收到的数据为集合M,将集合M内非空参数值的参数按照参数名
ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2...)拼接成字符串stringA。 sign = stringA + "&app_secret=" + appSecret,取MD5(32位不区分大小写)。
注意事项
- 参数名 ASCII码 从小到大排序(字典序);
- 如果参数值为空(即null)不参与签名;
- 参数名区分大小写;
- 验证签名时,sign 参数不参与签名,将生成的签名与该 sign 值作校验;
- 接口可能增加字段,验证签名时必须支持增加的扩展字段;
3.2 计算示例
密钥:
| 字段 | 示例值 |
|---|---|
| app_id | opXxxx |
| app_secret | XXXX |
输入参数:
| 字段 | 示例值 |
|---|---|
| park_uuid | xxxxxx |
| plate | 粤B660PP |
| car_type | 1 |
| enter_time | 1563242533431 |
计算 sign 的过程如下:
- 参数排序后字符串拼接:
app_id=op1235677abcefd&car_type=1&enter_time=1563242533431&park_uuid=40e06b24-7320-4a61-8d97-7ebccb364a87&plate=粤B660PP&sign_type=MD5×tamp=1563242932357&app_secret=XXX - 使用 MD5 (32位不区分大小写)加密:
0efc810fc198b148d9ab857744d72f2a
3.3 按请求载体的签名规则
| 请求载体 | 待签字符串拼装方式 | 签名值传递位置 |
|---|---|---|
URL 传参(?a=1&b=2) |
除 sign 外所有参数按参数名升序拼接为 a=1&b=2,末尾追加 &app_secret=XXX |
URL 参数 sign |
表单(application/x-www-form-urlencoded) |
与 URL 传参完全相同,参数放在请求体而非 URL | 表单字段 sign |
JSON(application/json) |
请求体原始 JSON 字符串 + &app_secret=XXX |
请求头 Authorization |
[!TIP|label:注意] 同一接口的请求方式可能与查询方式使用不同载体。例如退款:
- 发起退款
POST /gate/1.0/payment/trade/refund使用application/json+Authorization头;- 退款查询
GET /gate/1.0/payment/trade/refund使用 URL 传参 +sign参数。
URL 传参 / 表单请求示例(开放平台网关):
// 支付接口请将 gateway 替换为 https://papi.4pyun.com
String gateway = "https://api.4pyun.com";
String appId = "opxxxxx";
String appSecret = "XXXXX";
Map<String, String> params = new TreeMap<>();
params.put("app_id", appId);
params.put("timestamp", String.valueOf(System.currentTimeMillis()));
params.put("sign_type", "MD5");
params.put("park_uuid", "e24deadf-1aa0-4981-bde5-f9c474c4f5f5");
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
String encryptStr = builder.toString() + "app_secret=" + appSecret;
String sign = MD5.encryptHEX(encryptStr);
String url = gateway + "/gate/1.0/parking/realtime/space?" + builder.toString() + "sign=" + sign;
Response response = Request.Get(url).execute();
JSON 请求示例(支付接入网关):
// 支付接口统一使用支付接入网关
String gateway = "https://papi.4pyun.com";
String appId = "opXXXX";
String appSecret = "XXXXX";
Map<String, Object> params = new HashMap<>();
params.put("app_id", appId);
params.put("pay_serial", "20220721102644066066610031");
params.put("value", "1");
params.put("reason", "接口测试退款");
String jsonStr = JSON.toJSONString(params);
String encryptStr = jsonStr + "&app_secret=" + appSecret;
String sign = MD5.encryptHEX(encryptStr);
Response response = Request.Post(gateway + "/gate/1.0/payment/trade/refund")
.setHeader("Authorization", sign)
.bodyString(jsonStr, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8))
.execute();
3.4 回调通知验签
平台主动调用对接方接口(支付结果通知、开票结果通知、营销回调等)时,同样会携带 sign 参数,对接方必须使用相同的规则验签后再处理业务,避免伪造请求。
处理规则:
- 按 3.3 的规则计算签名,与请求中的
sign比对,不一致直接拒绝; - 验签通过并处理成功后,按各接口约定返回成功状态码(多数为
code = 1001); - 未返回成功状态码时平台会重复通知,对接方必须按业务单号做幂等处理,重复通知直接返回成功即可;
- 接口可能增加字段,验签时必须支持增加的扩展字段。
4 公共响应参数
所有接口的响应均包含以下公共字段:
| 字段名称 | 字段说明 | 类型 | 必填 | 备注 |
|---|---|---|---|---|
| code | 请求状态码 | string | Y | 见附录 - 错误码 |
| message | 返回描述 | string | Y | 返回描述 |
| hint | 返回错误说明 | string | N | 返回具体错误描述,用于指导排查 |
| seqno | 服务器日志标示 | string | Y | 排查问题时请提供该值 |
| data_node | 处理请求的节点 | string | N | CN-South/HS3-2 |
| path | 请求的接口路径 | string | N | 异常响应中返回 |
各业务的成功/失败状态码见具体接口说明,通用错误码见附录 - 错误码。