概览
开放接口数
5
支持方式
JSON POST
时效要求
5 分钟签名时窗
- 所有接口都走 POST,请求头使用 Content-Type: application/json。
- 开放接口推荐通过 https://openapi.cpaynow.com/v1/... 访问。
- 业务请求与成功响应字段名使用 snake_case;除特别说明外,请求字段均按字符串传递。
- 当前基础币种校验支持 CNY / VND / USD,具体币种还必须得到商户所绑定渠道的支持。
- 签名字段统一叫 sign,签名原文按字段名升序拼接后追加商户密钥。
- 时间戳支持秒或毫秒,但服务端仅接受与当前时间差不超过 5 分钟的请求。
- 文档中的时间戳和签名均为格式示例,联调时必须替换为当前时间并重新计算签名。
- 业务校验失败统一返回 HTTP 200(响应体中包含错误 code/message 信息);触发平台限流时可能返回 HTTP 429。
建议所有商户统一使用 openapi.cpaynow.com 和 JSON 请求体。notify_url 必须填写对接方真实、有效且可公网访问的 HTTP/HTTPS 地址,不得使用平台内部测试回调地址。
签名规则
签名逻辑与当前后端实现一致:
- 排除字段 sign。
- 字段值先按接口规则去掉首尾空白;过滤 null、undefined 和空字符串。
- 按字段名升序排序。
- 拼成 key=value&key=value。
- 最后在尾部追加 &merchantSecret。
- 对整个字符串做 MD5,输出小写 32 位字符串。
- 字段和值不做 URL Encode;签名时只能使用下方各接口列出的字段,不要加入自定义字段。
amount=100¤cy=VND&member_name=Nguyen Van A&merchant_no=M10001¬ify_url=https://merchant.example.com/notify&product_no=P10001×tamp=1774096500000&trade_no=T202603210001&version=v1&merchantSecret
推荐固定传入大写币种、account_type=BANK 和 version=v1,并用完全相同的字符串参与签名。
下单接口的 currency、account_type、version 按请求原始大小写验签;查询接口会先把币种转为大写再验签。即使请求省略 version,服务端仍按默认值 v1 参与签名。
代收下单
POST
/v1/trade/payin
创建一笔代收订单,成功后返回平台订单号、收银台地址和可用于自定义收银台的支付数据。
| 字段 | 必填 | 说明 |
|---|---|---|
| merchant_no | 是 | 商户编号。 |
| trade_no | 是 | 商户订单号;同一商户下必须唯一,代收和代付共用唯一性范围。 |
| amount | 是 | 支持 JSON 正整数或正整数字符串,例如 100;兼容 100.0 / 100.00 并归一化为 100,不接受非零小数。请求验签仍使用传入原值。 |
| currency | 是 | CNY / VND / USD,推荐大写;还需匹配绑定渠道能力。 |
| product_no | 是 | 平台分配的代收产品号,必须传入并参与签名。 |
| notify_url | 是 | 对接方真实、有效且可公网访问的异步回调地址,仅支持 HTTP/HTTPS;不得使用 localhost、私网地址或平台内部测试回调地址。 |
| timestamp | 是 | 秒或毫秒时间戳 |
| member_name | 是 | 会员姓名 |
| return_url | 否 | 同步跳转地址 |
| version | 否 | 默认且仅支持 v1;省略时仍按 version=v1 参与签名。 |
| sign | 是 | 签名值 |
{
"merchant_no": "M10001",
"trade_no": "COL202603210001",
"amount": "100",
"currency": "VND",
"product_no": "COLLECT_VND",
"notify_url": "https://merchant.example.com/notify",
"timestamp": "1774096500000",
"member_name": "Nguyen Van A",
"version": "v1",
"sign": "md5sign"
}{
"platform_trace_no": "PT17740965000000001",
"trade_no": "COL202603210001",
"merchant_no": "M10001",
"product_no": "COLLECT_VND",
"currency": "VND",
"amount": "100",
"order_time": "2026-03-21 18:05:40",
"url": "https://top1.cpaynow.com/pay?token=xxxx",
"status": "1",
"cashier_data": {
"bank_name": "ACB",
"account_name": "Convenient Pay",
"card_no": "0123456789",
"amount": "100",
"currency": "VND",
"remittance_detail": "PT17740965000000001",
"qrcode_data": "000201010212...",
"qrcode_data_url": "",
"checkout_url": "https://top1.cpaynow.com/pay?token=xxxx",
"payment_link_id": ""
}
}成功响应字段
| 字段 | 说明 |
|---|---|
| platform_trace_no | 平台订单号。 |
| trade_no | 商户订单号。 |
| merchant_no | 商户编号。 |
| product_no | 平台实际使用的代收产品号。 |
| currency | 规范化后的大写币种。 |
| amount | 归一化后的正整数金额字符串;下单、查询和回调格式一致。 |
| order_time | 订单创建时间文本,不包含时区标识;当前代收接口使用 Asia/Kolkata。该字段仅用于展示,不要用于订单判断或时间计算。 |
| url | 平台收银台或第三方支付页地址。 |
| status | 创建成功固定为 1。 |
| cashier_data | 自定义收银台数据对象;字段是否有值取决于实际渠道。 |
cashier_data 字段
| 字段 | 说明 |
|---|---|
| bank_name | 收款银行名称或渠道返回的银行标识。 |
| account_name | 收款账户名称。 |
| card_no | 收款账号。 |
| amount | 创建响应中的正整数金额字符串。 |
| currency | 大写币种。 |
| remittance_detail | 转账附言或识别信息,付款时应原样填写。 |
| qrcode_data | 二维码原始文本;非空时可由商户前端自行生成二维码图片。 |
| qrcode_data_url | 二维码图片 Data URL;部分渠道为空。 |
| checkout_url | 收银台或第三方支付页地址。 |
| payment_link_id | 第三方支付链接 ID;仅部分渠道返回。 |
url、二维码和账户字段可能因渠道而为空。接入方应按“可用收银台链接 → 二维码 → 账户信息”的顺序做兼容展示。
代付下单
POST
/v1/trade/payout
创建一笔代付订单。请求成功表示平台已受理,实际到账结果必须以后续查询或异步回调为准。
| 字段 | 必填 | 说明 |
|---|---|---|
| merchant_no | 是 | 商户编号。 |
| trade_no | 是 | 商户订单号;同一商户下必须唯一,代收和代付共用唯一性范围。 |
| amount | 是 | 支持 JSON 正整数或正整数字符串,例如 2000;兼容 2000.0 / 2000.00 并归一化为 2000,不接受非零小数。请求验签仍使用传入原值。 |
| currency | 是 | CNY / VND / USD,推荐大写;还需匹配绑定渠道能力。 |
| product_no | 是 | 平台分配的代付产品号,必须传入并参与签名。 |
| notify_url | 是 | 对接方真实、有效且可公网访问的异步回调地址,要求与代收一致。 |
| timestamp | 是 | 秒或毫秒时间戳 |
| account | 是 | 收款账号 |
| account_type | 是 | 忽略大小写校验,当前仅支持 BANK;签名仍使用请求原始大小写。 |
| payee | 是 | 收款人姓名 |
| bank | 是 | 银行名称 |
| bank_code | VND 必填 | 越南银行编码 |
| bank_branch | 否 | 支行名称 |
| remark | 否 | 备注 |
| version | 否 | 默认且仅支持 v1;省略时仍按 version=v1 参与签名。 |
| sign | 是 | 签名值 |
{
"merchant_no": "M10001",
"trade_no": "PO202603210001",
"amount": "2000",
"currency": "VND",
"product_no": "PAYOUT_VND",
"notify_url": "https://merchant.example.com/notify",
"timestamp": "1774096500000",
"account": "0123456789",
"account_type": "BANK",
"payee": "Tran Thi B",
"bank": "ACB",
"bank_code": "970416",
"bank_branch": "HCM Branch",
"version": "v1",
"sign": "md5sign"
}{
"platform_trace_no": "PT17740965000000002",
"trade_no": "PO202603210001",
"merchant_no": "M10001",
"product_no": "PAYOUT_VND",
"currency": "VND",
"amount": "2000",
"order_time": "2026-03-21 19:36:10",
"fee": "0.00",
"status": "1",
"provider_payout_id": "",
"provider_transaction_id": "",
"qrcode_data": "",
"qrcode_data_url": "",
"deeplink_url": "bank-app://transfer?..."
}成功响应字段
| 字段 | 说明 |
|---|---|
| platform_trace_no | 平台订单号。 |
| trade_no | 商户订单号。 |
| merchant_no | 商户编号。 |
| product_no | 平台实际使用的代付产品号。 |
| currency | 规范化后的大写币种。 |
| amount | 正整数金额字符串。 |
| order_time | 订单创建时间文本,不包含时区标识;当前按币种分别使用 CNY=Asia/Shanghai、VND=Asia/Ho_Chi_Minh、USD=America/New_York。该字段仅用于展示。 |
| fee | 预留的渠道预估手续费字段,当前返回 0.00,不代表商户最终费率。 |
| status | 受理成功固定为 1,不代表到账成功。 |
| provider_payout_id | 第三方代付 ID;异步渠道刚受理时可能为空。 |
| provider_transaction_id | 第三方交易 ID;异步渠道刚受理时可能为空。 |
| qrcode_data | 代付审核或转账使用的二维码原始文本,仅部分渠道返回。 |
| qrcode_data_url | 二维码图片 Data URL,仅部分渠道返回。 |
| deeplink_url | 银行 App 跳转地址,仅部分本地渠道返回。 |
后五个渠道字段允许为空,接入方不得以这些字段是否为空判断订单成功。请保存 platform_trace_no,并以订单查询或签名回调确认最终状态。
订单查询
代收查询
POST
/v1/payin/query
代付查询
POST
/v1/payout/query
两个查询接口的请求体和响应结构一致;接口会按商户号、商户订单号和订单类型查找订单。
| 字段 | 必填 | 说明 |
|---|---|---|
| merchant_no | 是 | 商户编号。 |
| trade_no | 是 | 商户订单号。 |
| currency | 是 | 必须填写订单实际币种,支持 CNY / VND / USD;服务端转为大写后参与签名,推荐请求和签名均使用大写。 |
| timestamp | 是 | 秒或毫秒时间戳,5 分钟有效。 |
| sign | 是 | 仅使用以上四个业务字段生成签名。 |
{
"merchant_no": "M10001",
"trade_no": "COL202603210001",
"currency": "VND",
"timestamp": "1774096500000",
"sign": "md5sign"
}成功响应
{
"platform_trace_no": "PT17740965000000001",
"merchant_no": "M10001",
"trade_no": "COL202603210001",
"amount": "100",
"currency": "VND",
"status": "2",
"success_time": "2026-03-21 18:10:12"
}| 字段 | 说明 |
|---|---|
| platform_trace_no | 平台订单号。 |
| merchant_no | 商户编号。 |
| trade_no | 商户订单号。 |
| amount | 订单实际金额,返回不带小数点的正整数字符串。 |
| currency | 订单实际币种。 |
| status | 1 处理中、2 成功、3 失败。 |
| success_time | 仅成功订单返回时间文本,其他状态返回空字符串;当前固定使用 Asia/Kolkata 且不包含时区标识。该字段仅用于展示。 |
查询待处理的 PayOS 代收订单,以及 PayOS / PayPay 代付订单时,平台会先向渠道同步一次状态,再返回最新结果。
余额查询
POST
/v1/balance/query
| 字段 | 必填 | 说明 |
|---|---|---|
| merchant_no | 是 | 商户编号。 |
| currency | 是 | CNY / VND / USD;服务端转为大写后参与签名。 |
| timestamp | 是 | 秒或毫秒时间戳,5 分钟有效。 |
| sign | 是 | 仅使用以上三个业务字段生成签名。 |
{
"merchant_no": "M10001",
"currency": "CNY",
"timestamp": "1774096500000",
"sign": "md5sign"
}{
"merchant_no": "M10001",
"mch_name": "Demo Merchant",
"currency": "CNY",
"balance": "0.00",
"freeze": "0.00"
}| 字段 | 说明 |
|---|---|
| merchant_no | 商户编号。 |
| mch_name | 商户显示名称;未配置名称时返回商户编号。 |
| currency | 查询币种。 |
| balance | 可用余额:成功代收净额,加已生效线下调账,减成功及待处理代付金额和对应商户手续费。 |
| freeze | 待处理代付金额与对应商户手续费合计。 |
回调说明
代收或代付进入成功、失败终态时,平台会向订单的 notify_url 发起 JSON POST 回调。对接方必须提供真实、有效且可公网访问的回调地址。
{
"merchant_no": "M10001",
"trade_no": "PO202603210001",
"platform_trace_no": "PT17740965000000002",
"amount": "2000",
"currency": "VND",
"status": "3",
"timestamp": "1774096812000",
"order_type": "PAYOUT",
"sign": "md5sign"
}| 字段 | 说明 |
|---|---|
| merchant_no | 商户编号。 |
| trade_no | 商户订单号。 |
| platform_trace_no | 平台订单号,建议作为回调幂等键。 |
| amount | 订单实际金额,返回不带小数点的正整数字符串,并以该值参与回调签名。 |
| currency | 订单币种。 |
| status | 终态:2 成功,3 失败。 |
| timestamp | 平台生成回调时的毫秒时间戳。 |
| order_type | COLLECTION 或 PAYOUT。 |
| sign | 对其余全部非空字段按本文签名规则生成的签名。 |
- 商户应先验签,再校验商户号、订单号、金额和币种,最后以幂等方式更新本地订单。
- 商户返回任意 HTTP 2xx 即视为本次投递成功,响应正文没有固定格式。
- 平台默认等待回调响应 5 秒,部署配置可能调整;请先快速返回 2xx,再异步处理耗时业务。
- 当前终态变更自动投递一次;失败后可由平台运营手工重试,因此商户必须支持重复回调。
notify_url 的协议、域名解析和公网 IP 校验发生在投递回调时,不发生在创建订单时。正式接入禁止使用 localhost、私网地址或任何平台内部测试回调地址;回调失败时还应主动调用订单查询接口确认状态。
状态与错误码
业务状态
| 值 | 含义 |
|---|---|
| 1 | 处理中 / PENDING |
| 2 | 成功 / SUCCESS |
| 3 | 失败 / FAILED |
HTTP 状态
| HTTP | 说明 |
|---|---|
| 200 | 接口成功;仍需检查响应中的业务状态。 |
| 400 | 请求字段、签名、商户、订单、余额或渠道校验失败。 |
| 429 | 请求过于频繁,请退避后重试并保持同一商户订单号。 |
| 500 | 平台内部错误;不要直接更换商户订单号重复下单,应先查询原订单。 |
HTTP 400 默认返回 NestJS 标准错误结构:
{
"message": "sign invalid",
"error": "Bad Request",
"statusCode": 400
}常见错误信息
| message | 处理建议 |
|---|---|
| missing required fields | 检查该接口全部必填字段。 |
| version must be v1 | 固定传入并签名 version=v1。 |
| currency must be CNY/VND/USD | 改用支持的币种并确认渠道能力。 |
| timestamp invalid / timestamp expired | 使用当前秒或毫秒时间戳,并确保服务器时钟同步。 |
| sign invalid | 按本文规则检查字段集合、排序、空值、大小写和商户密钥。 |
| merchant not found / merchant is disabled | 检查商户号和商户状态。 |
| merchant secret not configured / merchant secret invalid | 联系平台重新配置或确认商户密钥。 |
| trade_no already exists | 该商户订单号已被使用;先查询原订单,不要直接重复下单。 |
| order not found | 检查商户号、商户订单号及查询接口类型。 |
| amount format invalid / amount must be greater than 0 / amount must be a positive integer | 使用正整数;兼容仅包含零的小数部分,例如 100.00,但不接受 100.01。 |
| merchant collection channel is not configured / merchant payout channel is not configured | 联系平台为商户绑定对应产品。 |
| collection amount must be >= ... / amount exceeds collection daily limit | 检查代收渠道的最低金额和当日限额。 |
| amount below payout minimum limit / amount exceeds payout single limit / amount exceeds payout total limit | 调整金额或联系平台确认代付渠道限额。 |
| merchant balance insufficient | 检查可用余额;代付金额和商户手续费都会占用余额。 |
| account_type must be Bank | 使用 account_type=BANK。 |
| bank is required when account_type is Bank | 补充银行名称。 |
| bank_code is required when currency is VND | VND 代付必须传越南银行编码。 |
渠道或第三方服务还可能返回与配置、额度、银行信息有关的动态错误。任何超时或 5xx 场景都应先调用对应订单查询接口,确认订单不存在后才能使用新的 trade_no 重新发起。