CKP 收银台集成
商户把买家重定向到 Paydify 托管的收银台页面(CKP),由收银台引导买家选择钱包并完成支付。CKP 是 Payin 集成里集成工作量最低、覆盖终端最广的方式,推荐作为接入首选。
| 维度 | 说明 |
|---|---|
| 用户体验 | 佳 |
| 集成工作量 | 较低 |
| 支持的平台 | WAP(手机)/ App(手机),PC 自动降级为二维码展示 |
交互示意
商户将买家重定向到 Paydify 的中间收银台页面,买家在那里选择支付方式(钱包),然后拉起钱包完成支付。

集成准备
在开始集成前,请确认以下前置条件已满足:
- 已通过 KYC,并获取专属
PartnerID、x-api-key、x-api-secret(商户 Portal - 开发者中心获取); - 已了解 服务域名 与 请求 / 响应规范;
- 已下载并初始化服务端 SDK(推荐方式,封装了加签 / 验签逻辑)。详见 开发资源。
集成步骤
集成时序
步骤 1:加 / 验签
每次访问 Paydify 接口、以及您接收 Paydify 推送的回调时,请求都需要附带一份签名。签名的作用是双向证明"这次请求 / 回调真的来自我们彼此",避免被冒充或篡改。
推荐做法:直接接入 Paydify 提供的 服务端 SDK(Java / Node.js / Python / PHP 等),SDK 已封装整个签名计算过程,您只需把 x-api-key 和 x-api-secret 注入 SDK。
如需自行实现:参考 签名算法,关键约束:
- 签名要传 2 个 HTTP 头:
x-api-key/x-api-timestamp; - 您与 Paydify 之间的服务器时钟需要保持准确(建议同步 NTP),避免请求被认作"过期";
- 接收回调时您也需要验签,校验失败一律拒收,避免被伪造请求扰乱订单状态。
步骤 2:服务端创建一笔支付订单
服务端调用 POST /payin/v1/createPayment 创建支付会话,并传入订单信息以创建支付会话并跳转到 Paydify 收银台页面。同时,您需要重点关注如下字段:
| 字段名 | 类型 | 必传 | 描述 |
|---|---|---|---|
mchTxnId | string(60) | 是 | 商户侧订单 ID,最长 60 位,唯一幂等键 |
txnAmount | string(20) | 是 | 订单金额,如 100.23 |
currency | string(8) | 是 | 订单金额(txnAmount)的计价币种,可传范围由 app 产品类型决定(开通时二选一,传错会被拒单、不自动折算):稳定币收单 app 传 USDT / USDC(按精确金额付款);法币收单 app 传 USD / SGD 等(按实时汇率折算为稳定币)。参看 支持的链和币种 |
payMethod1 | string(20) | 否 | 支付使用的钱包,枚举值参看 支持的链和币种;使用 CKP 收银台支付模式,无需传此字段 |
payMethod2 | string(20) | 否 | 支付使用的链,枚举值参看 支持的链和币种 |
notificationUrl | string(300) | 是 | 支付结果回调商户的地址,仅支持 https |
successReturnUrl | string(300) | 否 | 支付成功后跳转的地址 |
failReturnUrl | string(300) | 否 | 支付失败后跳转的地址 |
pendingReturnUrl | string(300) | 否 | 支付中途返回时跳转的地址 |
accountInfo | object[] | 否 | 收款账号信息列表,如 [{"toAddress":"0xttttttt22222","network":"ETH"}]。元素字段:toAddress(收款地址,元素存在时必填)、network(目标链,如 ETH / BSC / SOL / TRX / BASE,可选;未传则回退到外层 payMethod2)。仅针对 DEX 交易有效,实现 DEX 交易资金直接结算至该地址;不传或传空数组时取商户 Portal-应用详情 所配置的 DEX 交易收款地址;兼容旧版单对象写法 |
lifetime | int | 否 | 订单超时周期,单位毫秒,默认 30 分钟 |
merchantId | string(60) | 否 | 订单归属商户 ID(子商户)。合作伙伴(Partner)凭据代发时必填;商户自有凭据可不传,默认归属凭据所属商户。最长 60 字符 |
merchantAppId | string(64) | 否 | 归属商户下的应用 ID,用于归属商户存在多个已授权应用时消歧。凭据覆盖该商户多个应用时必填;仅一个授权应用时可不传,系统自动匹配。最长 64 字符 |
更多字段(如
source/txnTitle/txnDesc/payerInfo/mchExtInfo)详见 接口定义 · 发起支付。
请求示例:
{ "mchTxnId": "MCH_TXN_20260610_002", "txnAmount": "0.01", "currency": "USDT", "checkoutMode": "MERCHANT", "payMethod1": "", "payMethod2": "", "notificationUrl": "https://your-domain.com/api/payment/notify", "successReturnUrl": "https://your-domain.com/pay/success", "failReturnUrl": "https://your-domain.com/pay/fail", "pendingReturnUrl": "https://your-domain.com/pay/pending", "txnTitle": "Test Payment Order", "source": "web", "txnDesc": "Payment for test product", "accountInfo": [ { "toAddress": "0x1111111111222222222233333333334444444444", "network": "ETH" } ], "payerInfo": { "uid": "USER_123456" }, "mchExtInfo": "{\"orderId\":\"ORD_2025081201\",\"productId\":\"PROD_001\"}" }
响应示例:
// 成功响应 { "code": "SYS_SUCCESS", "message": null, "messageDetail": null, "data": { "txnId": "P1167515578018041857", "mchTxnId": "MCH_TXN_20260610_002", "state": "INIT", "errorMsg": "", "qrCode": "data:image/png;base64,iVBORw0KGgoAAAANSU...", "deeplink": "bitkeep://pay?txnId=P20250827173005906", "httplink": "https://payrouter.paydify.com/en/pay/middle?txnId=P1167515578018041857&_needChain=base" }, "success": true } // 失败响应 { "code": "SYS_ERROR", "message": "System error", "messageDetail": "Error details", "data": null, "success": false }
CKP 模式下,您主要使用 data.httplink 字段。
步骤 3:客户端重定向至 Paydify 收银台
商户服务端拿到 createPayment 响应中的 data.httplink 后,传给前端,由前端引导用户跳转:
<a href="{{httplink}}" target="_self">前往支付</a>
Paydify 收银台会根据用户终端自动适配:
- 移动端:自动尝试唤起主流钱包 App;
- PC 浏览器:展示二维码,引导用户使用手机钱包扫码支付。
payrouter.paydify.com。
用户支付完跳回您的页面
收银台流程结束时,Paydify 会根据用户结果跳回您在步骤 2 中传入的对应 URL:
| 用户结果 | 跳回 URL |
|---|---|
| 支付成功 | successReturnUrl |
| 支付失败 | failReturnUrl |
| 用户在支付中主动返回 | pendingReturnUrl |
步骤 4:获取支付结果(双保险)
订单创建后,异步回调通知(Webhook)+ 主动查询接口两条路必须都接入,构成"双保险":
- Webhook 是主路径:Paydify 在订单状态变更时主动推送,延迟最低;
- 主动查询是兜底路径:用于网络抖动 / 商户回调端临时不可用时的状态补偿。
4.1 接收异步回调通知(Webhook)
Paydify 在订单状态变化时向您 createPayment 时填写的 notificationUrl 发起 POST 请求,请求体是 JSON,请求头带签名字段(与步骤 1 中的说明一致)。完整接收、验签、应答、重试规则参见 回调通知。
开发者最需要知道的 4 条事实:
- 必须验签:未通过验签的请求一律返回
HTTP 400+ 记录告警日志,不要进入业务处理; - 必须幂等:同一
txnId的通知可能被推送多次(网络抖动、Paydify 重推、用户多次链上事件),按txnId + state做去重; - 必须正确应答:处理成功返回
HTTP 200 + 响应体 "SUCCESS",Paydify 收到此应答才认为通知送达;其它任何响应(包括 HTTP 200 但 body 不是 SUCCESS)都会触发自动重推; - 自动重推策略:失败后 Paydify 按
1m / 5m / 30m / 2h / 6h / 12h / 24h七次间隔重试,超过仍未送达会进入告警。
回调载荷示例:
{ "txnId": "P5081643613805693697", "mchTxnId": "dcb97435-6713-4129-b428-2340c61c5605", "state": "PAID", "txnAmount": "0.01", "currency": "USDT", "paidAmount": "0.01", "paidCurrency": "USDT", "paidNetwork": "BNB", "paidTime": 1780971481993, "txnHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "fromAddress": "0x5555555555666666666677777777778888888888", "toAddress": "0x1111111111222222222233333333334444444444", "fee": "0", "errorMsg": "", "mchExtInfo": "{\"orderId\":\"ORD_2025081201\",\"productId\":\"PROD_001\"}" }
商户应答示例:
- HTTP 状态码:
200 Content-Type: text/plain- 响应体(裸字符串,不区分大小写):
success
以下写法均会被识别为成功,不再重试:
success/SUCCESS/Success- 首尾带空白或换行:
success、success\n
以下写法会被判定为失败并触发重试:
- JSON 对象:
{"status":"success"}/{"code":0}/{"result":"success"} - HTML 错误页或空响应体
- 除
success外的任何字面量(含fail)
4.2 主动调用订单查询接口
详见 查询支付状态。
接口:POST /payin/v1/getPaymentStatus
请求参数(txnId 与 mchTxnId 二选一):
| 字段名 | 必传 | 描述 |
|---|---|---|
txnId | 二选一 | Paydify 订单号,createPayment 响应中返回 |
mchTxnId | 二选一 | 商户订单号,与 createPayment 时传入的一致;同时提供两者时以 txnId 为准 |
merchantId | 否 | 订单归属商户 ID(子商户)。合作伙伴(Partner)凭据代发时必填;商户自有凭据可不传,默认归属凭据所属商户。最长 64 字符 |
merchantAppId | 否 | 归属商户下的应用 ID,用于归属商户存在多个已授权应用时消歧。凭据覆盖该商户多个应用时必填;仅一个授权应用时可不传,系统自动匹配。最长 64 字符 |
请求示例:
{ "txnId": "P5081643613805693697" }
响应示例:
{ "code": "SYS_SUCCESS", "message": null, "data": { "txnId": "P5081643613805693697", "mchTxnId": "dcb97435-6713-4129-b428-2340c61c5605", "state": "PAID", "txnAmount": "0.01", "currency": "USDT", "paidAmount": "0.01", "paidCurrency": "USDT", "paidNetwork": "BNB", "paidTime": 1780971481993, "txnHash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "fromAddress": "0x5555555555666666666677777777778888888888", "toAddress": "0x1111111111222222222233333333334444444444", "fee": "0", "errorMsg": "", "mchExtInfo": "{\"orderId\":\"ORD_2025081201\"}" }, "success": true }
state 取值:
| state | 含义 | 是否终态 |
|---|---|---|
INIT | 订单已创建,尚未感知到链上支付 | 否 |
PAYING | 已感知到链上发起,等待区块确认 | 否 |
PAID | 支付完成,资金已确认到账 | 是 |
FAILED | 支付失败(链上失败 / 金额不匹配 / 用户取消) | 是 |
TIMEOUT | 订单超时未支付(达到 lifetime) | 是 |
推荐使用方式:
- 收到 Webhook 后,先校验签名 + 幂等去重 → 再调一次
getPaymentStatus二次确认,避免直接信任回调载荷被伪造或错位; - 长时间未收到回调时,按业务超时配置(建议 ≥ 订单
lifetime)轮询getPaymentStatus做兜底。
步骤 5:发起退款(可选)
订单进入 PAID 状态后,商户可对原单发起全额或部分退款。退款是异步流程,Paydify 提交退款后会通过独立的 webhook 回写最终结果。
创建退款单
调用接口:POST /payin/v1/createRefund,详见 发起退款 与 查询退款状态。
请求参数:
| 字段名 | 类型 | 必传 | 描述 |
|---|---|---|---|
mchTxnId | string(60) | 是 | 商户侧退款单号,同 createPayment 一样具有幂等性(重复传相同值返回首次创建的退款单) |
paymentTxnId | string(32) | 是 | 原支付订单的 txnId |
refundAmount | string(20) | 是 | 退款金额,精度与原订单 currency 一致;支持部分退款 |
notificationUrl | string(300) | 否 | 退款结果回调地址,留空时复用原 createPayment 时的 notificationUrl |
mchExtInfo | string(512) | 否 | 商户透传字段,会在退款回调中带回 |
merchantId | string(64) | 否 | 退款归属商户 ID(子商户)。合作伙伴(Partner)凭据代发时必填;商户自有凭据可不传,默认归属凭据所属商户 |
merchantAppId | string(64) | 否 | 归属商户下的应用 ID,用于归属商户存在多个已授权应用时消歧。凭据覆盖该商户多个应用时必填;仅一个授权应用时可不传,系统自动匹配 |
请求示例:
{ "mchTxnId": "REFUND_2026061001", "paymentTxnId": "P5081643613805693697", "refundAmount": "0.01", "mchExtInfo": "{\"reason\":\"customer_cancel\"}" }
响应示例:
{ "code": "SYS_SUCCESS", "data": { "refundTxnId": "R5081643613805694001", "mchTxnId": "REFUND_2026061001", "paymentTxnId": "P5081643613805693697", "state": "PENDING", "refundAmount": "0.01", "currency": "USDT" }, "success": true }
退款场景(CEX / DEX 差异)与退费规则详见 常见问题 - 退款。
步骤 6:获取对账单文件(可选)
对账单用于商户做每日资金核对、财务入账、跨系统对账。接口调用(请求参数、响应字段、Summary / Detail 文件下载链接)详见 获取结算文件。
- 结算日期
settlementDate格式YYYY-MM-DD,使用 UTC 时区,只能查询today-1及之前的日期; summaryFileUrl/detailFileUrl为 S3 预签名链接,60 分钟有效,过期后请重新调用本接口获取新链接;- 推荐每日 UTC 01:00 之后拉取
T-1对账单,错峰避免与商户高峰冲突。
Summary 文件格式
Summary 按 settlementCurrency 分组输出汇总行(一种结算币种一行)。CSV、UTF-8、逗号分隔,首行为表头。
| 列名 | 示例 | 说明 |
|---|---|---|
clearingBatchId | 20260609001 | 结算批次 ID |
settleDate | 20260609 | 结算日,yyyyMMdd |
totalCount | 42 | 当前 currency 分组下的明细笔数 |
settlementCurrency | USDT | 结算币种 |
transactionCurrency | USDT | 交易币种 |
netTransactionAmount | 1234.5678 | 该 currency 下交易净额(扣除退款后) |
fees | 12.345 | 该 currency 下明细级 8 项费用合计(不含 settle fee) |
netSettlementAmount | 1222.2228 | = netTransactionAmount - fees |
settleFee | 1 | 批次级结算费(batch 维度) |
netReceivedAmount | 1221.2228 | = netSettlementAmount - settleFee,商户实收 |
Detail 文件格式
Detail 每行对应一笔 PAYMENT 或 REFUND。CSV、UTF-8、逗号分隔,首行为表头。
| # | 列名 | 示例 | 说明 |
|---|---|---|---|
| 1 | clearingBatchId | 20260609001 | 结算批次 ID |
| 2 | merchantId | MCH789012 | 商户 ID |
| 3 | x-api-key | APP123456 | 应用 ID |
| 4 | transactionRequestId | P5081643613805693697 | Paydify 交易号 |
| 5 | originalTransactionRequestId | P5081... 或空 | 原单交易号(仅 REFUND 行有值) |
| 6 | merchantReference | dcb97435-... | 商户订单号(mchTxnId) |
| 7 | transactionType | PAYMENT / REFUND | 交易类型 |
| 8 | transactionTime | 2026-06-09 14:32:00 | 交易时间,yyyy-MM-dd HH:mm:ss |
| 9 | transactionCurrency | USDT | 交易币种 |
| 10 | transactionAmount | 0.01 | 交易金额 |
| 11 | billingCurrency | USD | 计费币种 |
| 12 | billingAmount | 0.01 | 计费金额 |
| 13 | settlementCurrency | USDT | 结算币种 |
| 14 | settlementAmount | 0.01 | 结算金额(带符号,退款为负) |
| 15 | networkRate | 0 | 网络费率 |
| 16 | networkFeeAmount | 0 | 网络费金额 |
| 17 | acqRate | 0.005 | 收单费率 |
| 18 | acqFeeAmount | 0.00005 | 收单费金额(按比例) |
| 19 | acqPtFixAmount | 0 | 收单每笔固定费 |
| 20 | acqAddFixAmount | 0 | 收单附加固定费 |
| 21 | kytAmount | 0 | KYT 检查费 |
| 22 | kyaAmount | 0 | KYA 检查费 |
| 23 | serviceRate | 0 | 服务费率 |
| 24 | serviceRateAmount | 0 | 服务费金额(按比例) |
| 25 | servicePtFixAmount | 0 | 服务每笔固定费 |
| 26 | netSettlementAmount | 0.00995 | 该笔净结算 = settlementAmount -(第 15~25 行内 8 项费用合计) |
上线检查清单
[ ] 已使用沙箱凭据跑通 createPayment → 收银台支付 → Webhook → getPaymentStatus 全链路 [ ] 已验证回调验签失败时返回 HTTP 400 [ ] 已验证同一 txnId 多次回调的幂等去重 [ ] 已验证回调应答返回 200 + 裸字符串 success [ ] 已配置 successReturnUrl / failReturnUrl / pendingReturnUrl [ ] 已与商务确认生产域名、回调出口 IP 白名单、HTTPS 证书 [ ] 已切换至生产 x-api-key / x-api-secret,沙箱凭据已下线