首页 / 开发者
商户对接文档

HissPay 商户开发文档

完整、最新的对接文档以 https://mch.hisspay.com/docs/ 为准(当前 v1.13.0 · 2026-10-27,持续更新)。沙箱联调请看沙箱测试指南。

版本:v1.13.0 · 更新:2026-10-27。本文面向接入 HissPay 的下游商户,依据当前生产接口源码和产品配置编写;各版本改动见第 17 节「变更记录」。示例中的应用、订单和账户均为占位值。产品配置可能变化;下单前以商户实际签约及平台通知为准。

1. 开始接入

生产网关:https://transaction.hisspay.com;沙箱网关:https://sandbox-api.hisspay.com。使用前请登录商户后台(mch.hisspay.com)→「应用密钥」核对环境和应用ID(appId),生产与沙箱凭据不得混用。下文通用示例以 {GATEWAY} 代替。

所有接口为 HTTPS POST,使用 Content-Type: application/json。交易请求由商户服务端发起,不要把密钥放在网页、App 安装包或公开仓库中。

接入前向平台确认:

  1. 商户已审核并启用;取得商户号。
  2. 创建并启用 API 应用,取得该应用的 appId 和 appSecret。商户号不能替代 appId。
  3. 开通交易币种和账户,分别签约代收、代付产品,取得对应产品编码。
  4. 平台已配置可用交易路由、金额范围、费率和结算周期。应用可用不代表所有产品可交易。
  5. 代付申请需配置商户服务器的公网出口 IP 白名单;多出口机器应提供完整清单。回调来源 IP 另向平台确认,不能用上游服务商 IP 替代平台通知来源。
  6. 提供公网 HTTPS 回调地址;准备正确验签、事务幂等和订单核对逻辑。

示例使用 INR。其他币种和支付方式以商户实际开通结果为准,不能仅改变 currency 就跨币种交易。名称包含 test 的商户或应用不等于沙箱;生产请求涉及真实业务。

当前币种及产品目录(2026-10-27 生产快照)

产品在目录中出现,不等于该商户可交易。服务端还会检查应用、商户币种、有效协议、金额及可用路由/渠道。下表由产品清单自动生成,状态含义如下:

  • LIVE:可用。仍须商户签约、开通币种并有可用路由才能交易;不保证任一商户都已开通,也不保证实际交易成功。
  • PLANNED:即将开放,不可下单。
  • BLOCKED:暂不可用,不可下单。

「说明」列出该产品在通用字段之外对下单请求的要求,具体字段见第 6 节「按支付方式的下单要求」。标为 PLANNED 或 BLOCKED 的产品,开放时间以平台通知为准。

共 30 个目录产品:LIVE 7 个,PLANNED 13 个,BLOCKED 10 个。

状态币种方向产品编码名称支付方式说明
LIVE(可用)AUD代收AUD-PAYPLUS-APPLE-M85澳元 Apple Pay(AUD Apple Pay)钱包已向部分商户开放;此编码仅适用于实际签约该产品的应用。请以后台签约产品为准,其他商户不要直接复用。
LIVE(可用)AUD代收AUD-PAYPLUS-GOOGLE-M85澳元 Google Pay(AUD Google Pay)钱包已向部分商户开放;此编码仅适用于实际签约该产品的应用。请以后台签约产品为准,其他商户不要直接复用。
LIVE(可用)AUD代收AUD-VKDPWMRTAU-PAYIN(Australia AUD pay-in)银行卡澳洲银行卡托管支付:须传 payType=CARD、clientIp(真实付款人 IP,键名区分大小写)、cardExtra(JSON 字符串,格式见第 6 节「澳洲银行卡(AUD-VKDPWMRT)」)和 https 的 returnUrl;金额 1–500 AUD,整数或 .99(如 20、20.00、19.99);仅支持澳洲手机号与澳洲账单信息;返回支付链接 payUrl,结果以回调或查单为准。
LIVE(可用)INR代收INR-HBGMMNKI印度卢比-收款T0(India INR pay-in (T+0))未细分—
LIVE(可用)INR代付INR-NPLMSUEX印度卢比-默认代付(India INR default payout)未细分—
LIVE(可用)THB代收THB-PROMPTPAY-PAYIN泰铢-PromptPay 扫码代收(Thailand THB PromptPay QR pay-in)未细分按商户逐个开通,以开通通知为准。不传 payType;cardExtra 须为含 payerAccountNo、payerBankCode 的 JSON 字符串;默认单笔 500.00–49999.00 THB;返回收银台 payUrl,结果以回调或查单为准(见第 16 节)。
LIVE(可用)USD代收USD-EKCBBONA美元-国际卡收款(USD international card pay-in)银行卡银行卡托管收银台:下单返回支付链接 payUrl,引导付款人跳转付款;结果以回调或查单为准。
PLANNED(即将开放,不可下单)EUR代收EUR-CARD-PAYIN欧元-银行卡代收(托管收银台,需购物车/购物者信息)(EUR card pay-in (hosted checkout, cart & shopper required))银行卡银行卡代收须在下单请求中提供 cardExtra(购物车和购物者信息,见第 6 节「按支付方式的下单要求」);金额两位小数;返回支付链接 payUrl,结果以回调或查单为准。
PLANNED(即将开放,不可下单)GBP代收GBP-CARD-PAYIN英镑-银行卡代收(托管收银台,需购物车/购物者信息)(GBP card pay-in (hosted checkout, cart & shopper required))银行卡银行卡代收须在下单请求中提供 cardExtra(购物车和购物者信息,见第 6 节「按支付方式的下单要求」);金额两位小数;返回支付链接 payUrl,结果以回调或查单为准。
PLANNED(即将开放,不可下单)JPY代收JPY-CARD-PAYIN日元-银行卡代收(托管收银台,需购物车/购物者信息)(JPY card pay-in (hosted checkout, cart & shopper required))银行卡银行卡代收须在下单请求中提供 cardExtra(购物车和购物者信息,见第 6 节「按支付方式的下单要求」);JPY 金额须为整数(否则 10006);返回支付链接 payUrl,结果以回调或查单为准。
PLANNED(即将开放,不可下单)THB代付THB-BANK-PAYOUT泰铢-银行转账代付(Thailand THB bank transfer payout)银行转账需单独开通,收到开通通知(含可用银行、户名长度上限、单笔范围与费率)前不可下单;bizCode 固定 BANK(见第 16 节)。
PLANNED(即将开放,不可下单)USD代收USD-APPLEPAY-PAYIN美元-Apple Pay 托管代收(USD Apple Pay hosted pay-in)钱包Apple Pay 托管页,仅 USD:须提供付款人公网 IPv4(clientIp);单笔限额待确认;返回支付链接 payUrl,结果以回调或查单为准。
PLANNED(即将开放,不可下单)USD代收USD-CARD-PAYIN美元-银行卡代收(托管收银台,需购物车/购物者信息)(USD card pay-in (hosted checkout, cart & shopper required))银行卡银行卡代收须在下单请求中提供 cardExtra(购物车和购物者信息,见第 6 节「按支付方式的下单要求」);金额两位小数;返回支付链接 payUrl,结果以回调或查单为准。
PLANNED(即将开放,不可下单)USD代收USD-CASHAPP-PAYIN美元-Cash App 代收(USD Cash App pay-in)钱包Cash App 代收,仅 USD,单笔 1–99:须提供付款人公网 IPv4(clientIp);返回支付链接 payUrl;实付可能比订单金额少 0.01–0.20,按通知中的 realAmount 入账。
PLANNED(即将开放,不可下单)USD代收USD-HOSTED-PAYIN美元-托管收银台代收(USD hosted checkout pay-in)托管收银台托管收银台:须提供格式有效的付款人 email;返回支付链接 payUrl(有有效期),结果以回调或查单为准;不能指定只收银行卡。
PLANNED(即将开放,不可下单)USD代付USD-LOCAL-PAYOUT美国-代付(待配置)(USD payout (draft))钱包Cash App 代付,仅 USD:收款人 Cash App 账户名填入 account(字段映射待确认;格式规则待确认:1–64 位字母或数字,不能是纯数字,不含 $ 或 @),accountName 必填;处理可能长达约 1 小时,期间为处理中,不是失败。
PLANNED(即将开放,不可下单)USDT代收USDT-BSCUSDT-BSC 网络代收(USDT pay-in on BSC)加密资产USDT 代收,金额最多 4 位小数;下单返回 payUrl 与收款信息 paymentInfo;结果以回调或查单为准,链上确认后查单返回 txHash。
PLANNED(即将开放,不可下单)USDT代收USDT-ETHEREUMUSDT-Ethereum 网络代收(USDT pay-in on Ethereum)加密资产USDT 代收,金额最多 4 位小数;下单返回 payUrl 与收款信息 paymentInfo;结果以回调或查单为准,链上确认后查单返回 txHash。
PLANNED(即将开放,不可下单)USDT代收USDT-SOLANAUSDT-Solana 网络代收(USDT pay-in on Solana)加密资产USDT 代收,金额最多 4 位小数;下单返回 payUrl 与收款信息 paymentInfo;结果以回调或查单为准,链上确认后查单返回 txHash。
PLANNED(即将开放,不可下单)USDT代收USDT-TRONUSDT-Tron 网络代收(USDT pay-in on Tron)加密资产USDT 代收,金额最多 4 位小数;下单返回 payUrl 与收款信息 paymentInfo;结果以回调或查单为准,链上确认后查单返回 txHash。
BLOCKED(暂不可用,不可下单)AUD代收AUD-CARD澳洲-银行卡代收(待开通)(Australia card pay-in (pending))银行卡—
BLOCKED(暂不可用,不可下单)AUD代付AUD-LOCAL-PAYOUT澳大利亚-代付(待配置)(Australia payout (draft))未细分—
BLOCKED(暂不可用,不可下单)BDT代收BDT-LOCAL-PAYIN孟加拉-代收(待配置)(Bangladesh pay-in (draft))未细分—
BLOCKED(暂不可用,不可下单)BDT代付BDT-LOCAL-PAYOUT孟加拉-代付(待配置)(Bangladesh payout (draft))未细分—
BLOCKED(暂不可用,不可下单)IDR代收IDR-LOCAL-PAYIN印度尼西亚-代收(待配置)(Indonesia pay-in (draft))未细分—
BLOCKED(暂不可用,不可下单)IDR代付IDR-LOCAL-PAYOUT印度尼西亚-代付(待配置)(Indonesia payout (draft))未细分—
BLOCKED(暂不可用,不可下单)PHP代收PHP-LOCAL-PAYIN菲律宾-代收(待配置)(Philippines pay-in (draft))未细分—
BLOCKED(暂不可用,不可下单)PHP代付PHP-LOCAL-PAYOUT菲律宾-代付(待配置)(Philippines payout (draft))未细分—
BLOCKED(暂不可用,不可下单)PKR代收PKR-LOCAL-PAYIN巴基斯坦-代收(待配置)(Pakistan pay-in (draft))未细分—
BLOCKED(暂不可用,不可下单)PKR代付PKR-LOCAL-PAYOUT巴基斯坦-代付(待配置)(Pakistan payout (draft))未细分—

生产产品状态 0 为正常(对应 LIVE)、1 为锁定(本表记为 PLANNED 或 BLOCKED);以上仅供识别目录,不构成交易授权。平台还有更广的支付方式编码(CARD、PAYPAL、CASHAPP、GOOGLE_PAY 等,见第 6 节「支付方式编码」),但编码并不代表已经签约或有可用通道。没有明确开通的组合不能交易。现金类产品编码以平台分配为准,目录中暂无现金类产品行。币种余额查询还要求商户有相应账户。

2. 接口清单

操作路径说明
创建代收订单/transaction/payin/v1/apply返回支付页面及平台订单号
查询代收订单/transaction/payin/v1/query查询本应用的订单
创建代付订单/transaction/payout/v1/apply受理成功后异步处理,不代表已到账
查询代付订单/transaction/payout/v1/query查询最终付款状态
查询账户余额/transaction/payout/v1/balance返回账面、可用和冻结余额
创建收款人/transaction/payout/v1/beneficiaries/create仅已开通 USD 银行卡代付的应用,见第 7 节「收款人管理」
查询收款人/transaction/payout/v1/beneficiaries/query同上
更新收款人/transaction/payout/v1/beneficiaries/update同上
沙箱:查看来源 IP/transaction/sandbox/v1/network仅沙箱。返回 environment 与平台看到的来源 IP sourceIp,用于配置代付白名单(沙箱默认不校验白名单,开启「模拟生产白名单」后才需要)
沙箱:查询 / 修改沙箱设置/transaction/sandbox/v1/settings/query、/transaction/sandbox/v1/settings/update仅沙箱。payoutIpWhitelistMode:SANDBOX_OPEN(默认,不校验代付来源 IP)或 PRODUCTION(模拟生产白名单,名单外返回 10010)
沙箱:通知投递记录/transaction/sandbox/v1/notify-log/query仅沙箱。本商户最近的通知投递结果(限速顺延、熔断、拒绝非公网目标等),见沙箱测试指南「回调规则」
沙箱:查询模拟单/transaction/sandbox/v1/query仅沙箱。查看模拟渠道状态与投递记录,见沙箱测试指南
沙箱:手动终态/transaction/sandbox/v1/trigger仅沙箱。对可手动场景的模拟单触发 PAID / FAILED
沙箱:重发通知/transaction/sandbox/v1/resend仅沙箱。请平台重发最近终态通知

所有接口都使用第 3 节的请求签名。上述沙箱接口只在沙箱网关存在,生产网关返回 404。生产代付始终校验来源 IP 白名单。

代收查单、代付查单、余额查询当前分别按 appId 限制 每秒 5 次。建议订单轮询间隔至少 3–5 秒,并在失败时退避。下单 TPS、日额度和路由限额需单独确认;不要把查询限频当作下单容量承诺。

3. 请求签名

必填请求头

请求头类型说明
appIdstring应用标识
timestampstringUnix 时间戳,毫秒,与平台时间差不得超过 30 秒
noncestring至少 10 个字符;推荐随机 UUID,每次请求重新生成
signstringSHA-256 小写十六进制,64 位

服务器应同步时间。相同 appId 下的 nonce 在防重放窗口(当前 60 秒,即时间戳允许误差的两倍)内不能重复:重复使用已成功验签的 nonce 返回业务码 400(msg 形如 nonce has been used);两个并发请求同时使用同一 nonce 时,后到者返回 900(Request repeated)。重试查询时更换 nonce、timestamp、sign,但保留原订单标识。

签名相关的常见拒绝(均为业务码 400,msg 仅供诊断):缺少请求头(如 AppId cannot be null)、nonce 少于 10 个字符(nonce cannot be null)、时间戳不是整数或超出 30 秒(timestamp invalid / timestamp has expired)、请求体不是 JSON 对象或含 null 值(Signed JSON body invalid)、签名不一致(Sign invalid)。签名校验服务暂时不可用时返回 500(Signature verification temporarily unavailable),换新 nonce 稍后重试。代付类接口(第 7 节)把这些 msg 统一改写为 Payout request rejected,业务码不变;但代付下单缺少签名请求头或 Content-Type 不是 application/json 时返回业务码 500(Payout request not confirmed; query original order),请先确认请求头齐全再按第 11 节处理。

计算规则

  1. 合并请求体字段与请求头 appId、timestamp、nonce;不要加入 sign。
  2. 字段名按字典序升序排序,拼成 key=value,各项以 & 连接。
  3. 在拼接结果末尾直接追加 appSecret,不加分隔符。
  4. 对完整字符串按 UTF-8 编码计算 SHA-256,输出小写十六进制。
sign = lowercase_hex(SHA256(UTF8(sorted_key_value_pairs + appSecret)))

下游签名不是 HMAC,也不需要 RSA;不要套用上游通道文档的签名算法。无需对待签名值做 URL 编码,不把整个 JSON 原文当成待签名串。HTTP 请求中无需传 appSecret。

请求体使用扁平 JSON 对象。推荐字段值使用字符串,金额统一写为 "100.00";省略无值的可选字段:不能发送 null(任何字段为 null 都会被拒绝,业务码 400),也不要发送数组或嵌套对象。若发送空字符串,应将该字段的 key= 纳入签名。不要签名后再更改金额格式或字段值。

例如,以下为余额查询的固定签名演示,密钥完全虚构:

body: {"currency":"INR"}
appId: demo-app
timestamp: 1700000000000
nonce: demo-nonce-0001
appSecret: demo-secret

待签名串:
appId=demo-app&currency=INR&nonce=demo-nonce-0001&timestamp=1700000000000demo-secret

此时间戳只用于核对算法,不能直接请求生产接口。可下载固定测试向量、Python 示例和 Node.js 示例。两个示例默认只做只读余额查询,从服务器环境变量读取网关 HISSPAY_GATEWAY 与凭据 HISSPAY_APP_ID、HISSPAY_APP_SECRET;旧变量名 PAYPLAT_APP_ID、PAYPLAT_APP_SECRET 暂时仍可使用,但会提示已弃用,请改名。

4. 金额与订单号

  • 下游接口金额单位是币种主单位。100 INR 传 "100.00",不要传上游 paise 值 10000。
  • 使用十进制定点计算,避免二进制浮点金额误差。精度按币种:
  • 一般法币(INR、USD、AUD、THB 等)最多两位小数;
  • 零小数位币种(JPY、KRW、VND、CLP、UGX 等)必须为整数,否则返回 10006;
  • 三位小数币种(BHD、JOD、KWD、OMR、TND)当前不支持,下单返回 10006;
  • USDT 最多 4 位小数(四个网络一致,见第 6 节「USDT 代收」)。
  • 超出精度的金额会被拒绝(10006);实际通道可要求整数金额或更严格的范围。
  • 代收金额必须大于 0。
  • 代付金额必须大于 0,且不低于代付最低金额。通道下限由平台为代付通道配置;未配置时为该币种默认值:AUD、USD 为 1.00;INR、PKR、BDT 为 100.00;其他币种为 100.00(平台可为通道设置其他值,可高于或低于默认值)。签约下限为商户签约中配置的最低金额,未配置时不额外限制。实际下限取通道下限与签约下限中的较高者(签约下限低于通道下限时按通道下限),并仍需满足签约路由的上下限。低于下限返回 10006;代付接口当前把 msg 统一改写为 Payout request rejected(见第 11 节),不会显示具体下限,请以签约与开通通知中的金额范围自查。
  • 银行账户、商户号、appId、平台订单号均作为字符串处理,保留前导零。
  • merchantOrderNo 由商户生成;建议使用商户前缀+时间+随机串,控制在 64 个 ASCII 字符以内,使用字母、数字、_、-。接口上限为 255 个字符,超过会被拒绝(业务码 400;代收 msg 形如「请求参数不正确:merchantOrderNo too long」,代付 msg 统一为 Invalid payout request,见第 11 节)。代收、代付上限相同。
  • product 为平台分配的产品编码,不要自行拼接或改写。代收下单最长 64 个字符,代付下单最长 20 个字符;超长返回业务码 400(product too long)。
  • 每笔业务使用唯一订单号。同一应用下,用已存在的 merchantOrderNo 再次下单,无论参数是否相同,通常返回 10020(商户订单号重复),不会返回原受理结果。平台可为个别产品单独启用业务幂等(目前仅可能用于 USD 银行卡代付):启用后同一单号、同一参数返回原受理结果,参数改变返回 409。是否启用以开通通知为准;未说明时按 10020 处理。
  • 无论是否启用幂等,下单超时或结果不确定时都先用原单号查单,不要换单号重试未知付款,也不要把 10020 当作下单失败。

实际到账金额规则

  • amount 始终为创建订单时的原订单金额,用于核对订单,不能被回调改写。
  • realAmount 为平台核验后的实际收款总额(主币种单位、扣手续费前),是代收成功后下游入账的金额依据。它可能小于或大于 amount,尤其是孟加拉实际付款金额通道。商户账户结算净额另按签约费率及固定费用计算,不能把 realAmount 当作扣费后的可用余额。
  • 不要要求 realAmount == amount 才接受成功通知,也不要收到成功就按 amount 入账。 例如 BDT 原订单 100.00、实际收到 95.00,则按 95.00 记实际收款;实际收到 105.00,则按 105.00 记实际收款。商品交付、少付补款或多付处理由商户业务规则决定,不能伪造平台收款金额。
  • 仅在成功状态、验签及订单归属核验通过、realAmount 为有效正数时执行幂等入账。未成功、金额缺失/非法、同一订单重复通知却金额不同、查询与通知矛盾时,保留待核对状态;不能回退使用原订单金额补记账。
  • 平台仅对已完成实际金额验证的渠道自动处理差额;其他金额异常进入待核对。本文不表示尚未开通的国家或渠道已经可交易。

5. 通用响应

{"code":0,"msg":"Success","data":{}}

同时检查 HTTP 状态和 JSON code。HTTP 200 也可能包含业务错误。code=0 表示接口操作成功;是否支付成功要看订单状态。msg 供诊断展示,不作为稳定的程序判断条件。金额在响应中是 JSON 数字,小数位数不固定(可能是 100、100.0 或 100.0000,平台账务按 4 位小数存储),商户应使用支持 Decimal 的解析方式并按数值比较,不要按字符串比较。尚未成功的代收订单查单时 realAmount 可能为 0 或 0.0,不是实际收款。

接口响应通过 HTTPS 返回;当前交易接口没有统一的响应签名字段。异步回调另有签名,必须验签。

6. 代收下单

POST /transaction/payin/v1/apply

字段必填说明
merchantOrderNo是商户唯一订单号,最长 255 个字符
amount是主币种金额,如 "100.00";法币最多两位小数,零小数位币种(如 JPY)须为整数,USDT 最多 4 位小数(如 "12.3456");不符合返回 10006
currency是如 INR,须已开通;USDT 代收固定为 USDT。四字母代码只支持 USDT,其他返回 10006
product是平台分配、该商户已签约的代收产品编码,最长 64 个字符
name是付款人姓名;具体格式受支付通道要求约束。AUD-VKDPWMRT 仍须填写但不使用,名/姓以 cardExtra 为准(见下文「澳洲银行卡(AUD-VKDPWMRT)」)
phone是付款人手机号;按通道要求填写,不能留空。AUD-VKDPWMRT 只能是 5–15 位数字,不带 +、空格、横线和国家码(见下文「澳洲银行卡(AUD-VKDPWMRT)」)
email是付款人邮箱,不能留空
userId是商户侧付款用户的唯一标识,字符串,最长 32 个字符;同一付款人保持不变,参与签名。超过 32 个字符返回业务码 400
clientIp按渠道要求真实付款人的公网 IPv4/IPv6 地址;部分渠道(包括印度原生 UPI)必填,按签约产品要求传入。值非空白(不是空串或全空白)时必须是合法的 IPv4 或 IPv6 文本,否则返回 10021(超过 45 个字符也返回 10021);空串或全空白在这一步按未传处理。此字段必须参与签名,不要使用商户服务器 IP 代替。键名区分大小写,必须写作 clientIp。AUD-VKDPWMRT 必填,见下文「澳洲银行卡(AUD-VKDPWMRT)」
notifyUrl否本单公网 HTTPS 通知地址;未填时使用商户默认通知地址。非空时(空字符串视为未填)必须是合法的 http(s) URL,否则返回业务码 400
returnUrl否支付后浏览器跳转地址;非空时(空字符串视为未填)必须是合法的 http(s) URL,否则返回业务码 400;部分通道要求必填的 HTTPS 地址。AUD-VKDPWMRT 必填 HTTPS,见下文「澳洲银行卡(AUD-VKDPWMRT)」
addr否付款人地址,视通道要求。AUD-VKDPWMRT 不使用
payType否支付方式编码,见下文「支付方式编码」表;显式传入时须与币种匹配,否则返回 10012;不传时按产品路由。不使用时请省略字段:传空字符串也返回 10012。编码不代表已开放。AUD-VKDPWMRT 必须显式传 CARD,见下文「澳洲银行卡(AUD-VKDPWMRT)」
otherExtend否扩展字符串;当前下单响应可返回,不保证查单/回调携带
cardExtra按产品要求通道扩展信息,字符串。AUD-VKDPWMRT 必填,格式见下文「澳洲银行卡(AUD-VKDPWMRT)」。部分即将开放的银行卡代收产品也须提交购物车和购物者信息,见下文「银行卡代收(需提交购物车和购物者信息)」;这些产品使用前向平台确认格式
{
  "merchantOrderNo":"DEMO_IN_20260912_001",
  "amount":"100.00",
  "currency":"INR",
  "product":"INR-HBGMMNKI",
  "name":"Test User",
  "phone":"YOUR_TEST_PHONE",
  "email":"payer@example.com",
  "notifyUrl":"https://merchant.example.com/payments/notify",
  "returnUrl":"https://merchant.example.com/payments/result"
}

示例响应:

{"code":0,"msg":"Success","data":{"appId":"YOUR_APP_ID","merchantOrderNo":"DEMO_IN_20260912_001","orderNo":"PLATFORM_ORDER_NO","currency":"INR","product":"INR-HBGMMNKI","amount":100.00,"payUrl":"https://cashier.example.com/example","payStatus":0,"otherExtend":null}}

响应中的 amount 为 JSON 数字,请用 Decimal 解析;所有代收下单响应都返回 product。法币订单不返回 paymentInfo 键(仅 USDT 产品返回)。

记录平台 orderNo,再让付款人访问 payUrl。浏览器跳转到 returnUrl 不能作为到账凭证;以验签通过的回调或查单结果确认付款。

支付方式与实际开通

payType 是可选字段;不传时由已签约产品及路由决定。显式传入时平台只校验编码与币种的组合(不匹配返回 10012),不按 payType 选择通道,也不证明相应通道已在生产开通。当前已配置产品见上表;任何支付方式均须向平台确认适用产品、商户协议和通道要求。returnUrl 推荐公网 HTTPS,非空时须为合法 http(s) URL,不强制 HTTPS;部分上游可要求其必填。不要向本接口提交卡号或 CVV。例外:AUD-VKDPWMRT 必须显式传 payType=CARD,且 returnUrl 必填并必须为 HTTPS(见下文「澳洲银行卡(AUD-VKDPWMRT)」)。

支付方式编码

payType支付方式可用币种说明
CARD银行卡24 个币种(含 USD、EUR、GBP、JPY、AUD、INR 等)卡支付/托管收银台
PAYPALPayPal20 个币种PayPal 钱包
CASHAPPCash App PayUSDCash App 钱包支付;不是现金交付
GOOGLE_PAYGoogle Pay(GPay)USD、EUR、GBP、JPY、AUDGoogle Pay 钱包支付;不设独立产品编码,配合银行卡、托管收银台或钱包类产品使用
APPLE_PAYApple PayUSD、AUDApple Pay 托管页;AUD 见第 15 节(沙箱暂未同步 AUD + APPLE_PAY,当前返回 10012)
CASH现金USD、AUD、EUR、GBP、INR、BDT、PKR、PHP、IDR现金类代收;现金类产品编码以平台分配为准
HOSTED托管收银台USD、AUD、EUR、GBP托管支付页,由付款人在页面选择方式
CRYPTO加密资产USDTUSDT 代收,见下文「USDT 代收」
WALLET钱包INR印度钱包/UPI
JAZZCASH、EASYPAISA钱包PKR巴基斯坦钱包
BKASH、NAGAD钱包BDT孟加拉钱包

币种列是编码级校验范围,不是商户开通范围;不在范围内的组合返回 10012。具体某个产品能否使用某编码,以平台开通结果为准。商户只传标准 payType;上游通道字段由平台映射。

按支付方式的下单要求

平台将陆续开放银行卡、钱包和托管收银台等支付方式。本节说明这些支付方式对本接口下单请求的额外要求。对应产品在上方目录中标为 LIVE 之前不可下单。

  • 商户只对接 HissPay 接口,只传本文列出的字段。上游所需的参数由平台配置,商户无需也不能传入。
  • 标为「待确认」的内容尚未定稿。请勿自行猜测格式,接入前向平台索取该产品的字段说明。
  • 请求签名、nonce 和通用字段规则不变(第 3、4 节)。新增要求只通过已有字段表达,不需要新的请求头。

通用要求

  • 币种与金额:订单币种必须是该产品的币种。金额为主币种单位,最多两位小数;平台按支付方式换算金额时不做舍入,超出精度的金额会被拒绝(10006)。JPY 等零小数位币种的请求金额必须为整数,否则返回 10006。
  • 付款人信息:name、email、phone 请填写付款人真实信息,不要使用占位值。部分支付方式会在平台侧校验邮箱格式、付款人 IP 等;不合格的请求会被拒绝,具体响应形式待确认。AUD-VKDPWMRT 的情况已经确定:请求先过通用校验,不合规时返回各自原有的业务码(400、10006、10012、10021 等);通过通用校验后,在本产品校验中不合规的,当前返回 9999(见下文「澳洲银行卡(AUD-VKDPWMRT)」与第 11 节「9999 自查清单」)。无法判断结果时,按下文「下单结果不确定时」处理。
  • returnUrl:使用公网 HTTPS。部分托管收银台产品付款后不会跳回 returnUrl。无论是否跳回,都不能据此判断付款结果。
  • 不要向本接口提交卡号、CVV 或钱包凭据。这些支付方式都由托管支付页收集支付信息。
  • 付款结果只以验签通过的平台回调或查单为准(第 8、10 节)。部分通道会在付款明确失败时发送失败通知(status="2",见第 10 节「代收失败通知」);其他通道的失败、放弃或过期订单不发送通知,可能长期保持 payStatus=0,需要联系平台核对。

银行卡代收(需提交购物车和购物者信息)

AUD-VKDPWMRT 不适用本小节,见下文「澳洲银行卡(AUD-VKDPWMRT)」。

部分银行卡代收产品要求商户在 cardExtra 中提交购物车和购物者信息,产品目录的「说明」列会注明;目录中暂无需要 cardExtra 的钱包产品。cardExtra 缺失或信息不全时,下单会被拒绝。

cardExtra 是字符串字段,与其他字段一样原样参与签名;请求体仍须是扁平 JSON,不要把 cardExtra 写成 JSON 对象或数组。cardExtra 内部的键名和编码格式待平台确认,下表只列需要提供的信息项和示例值:

信息项是否必填示例值说明
购物车商品列表是编号 SKU-1,名称 Demo item,单价 25.00,数量 1至少一项;每项包含商品编号、名称、单价、数量,单价按主币种两位小数。各项合计是否必须等于 amount,待平台确认
购物者名(first name)是Test与姓分开提供
购物者姓(last name)是User与名分开提供
付款人公网 IP是203.0.113.10真实付款人 IP。由顶层 clientIp 提供还是须写入 cardExtra,待平台确认
邮箱是payer@example.com是否须在 cardExtra 中重复顶层 email,待平台确认
电话按产品要求YOUR_TEST_PHONE产品要求账单信息时必填(见产品目录「说明」)
账单地址、城市、邮编按产品要求Example Street 1,Example City,00000同上
国家按产品要求US同上;取值格式(是否为两位国家代码)待确认
州或省按产品要求Example State同上
收货地址否—可选
付款人浏览器 User-Agent、语言否Mozilla/5.0 …,en-US可选
商户侧客户编号否CUST0001可选

下单请求示例(cardExtra 的值是占位符,实际内容按平台提供的格式填写):

{
  "merchantOrderNo":"DEMO_CARD_20260930_001",
  "amount":"25.00",
  "currency":"USD",
  "product":"YOUR_CARD_PAYIN_PRODUCT",
  "name":"Test User",
  "phone":"YOUR_TEST_PHONE",
  "email":"payer@example.com",
  "clientIp":"203.0.113.10",
  "notifyUrl":"https://merchant.example.com/payments/notify",
  "returnUrl":"https://merchant.example.com/payments/result",
  "cardExtra":"CART_AND_SHOPPER_INFO_IN_PLATFORM_FORMAT"
}
  • 成功时响应与普通代收相同。payUrl 是托管支付页的 HTTPS 地址,可能不在 HissPay 域名下;请直接引导付款人打开,不要按域名白名单拦截或改写链接。之后按下文「托管收银台」的方式等待结果。
  • 支付方式由所签约的产品决定,商户无需传入其他参数;可用币种以商户实际开通为准。

澳洲银行卡(AUD-VKDPWMRT)

AUD-VKDPWMRT 是澳元银行卡托管支付:下单成功返回托管支付页 payUrl,付款人在支付页填写卡信息,商户不接触、也不得提交卡号或 CVV。除通用字段规则(第 3、4 节及上方字段表)外,下列要求须全部满足。错误码按校验顺序返回:请求先经过通用校验,不合规时返回原有业务码,例如必填字段为空、URL 非法返回 400,金额 ≤0 或精度超限返回 10006,payType 与币种不匹配或为空字符串返回 10012,clientIp 非空白但格式非法返回 10021,产品、协议、路由问题返回 10004、10005 等;只有通过这些通用校验之后,在本产品自身的校验中不满足下列要求时,当前才返回业务码 9999,平台正在改为具体业务码。收到 9999 时按第 11 节「9999 自查清单」处理。

当前仅支持澳洲手机号(area_code 固定 61)与澳洲账单信息(country=AU、state 取下表所列、4 位邮编);海外手机号/海外账单地址暂不支持(平台正在向通道确认)。

顶层字段
字段本产品要求
payType必填,必须显式传 CARD。传空字符串或与 AUD 不匹配的编码返回 10012;不传时平台按 WALLET 记录订单,或传了其他与 AUD 匹配的编码(如 PAYPAL),都会被本产品拒绝(当前 9999)
amountAUD 1–500(含两端),只能是整数或 .99 结尾,最多两位小数表示:"20"、"20.00"、"19.99"、"500" 合规;"20.50"、"0.99"、"500.99" 不合规。金额 ≤0 或超过两位小数(如 "19.999")返回 10006;超出签约路由金额范围按路由规则返回(如 10005);其余不合规当前返回 9999
clientIp必填。键名必须精确为 clientIp(区分大小写);写成 client_ip、clientIP、ip 等能通过验签,但平台不读取该键(未知字段被忽略),等同未传,下单被拒。值为真实付款人 IP 的字面量:IPv4 点分形式(如 203.0.113.10)或 IPv6;不能是域名,不能带端口或方括号,IPv4 不要写成 ::ffff:203.0.113.10 这类映射形式。不要传商户服务器 IP;不要放在请求头或 URL 查询参数里(同样不会被读取)。值非空白但不是合法 IPv4/IPv6(含超过 45 个字符)返回 10021;不传、null、空字符串、全空白或键名错误都视为缺失,本产品当前返回 9999;能通过通用格式检查、但不是本产品接受的字面量(如 ::ffff: 映射形式)当前也返回 9999
returnUrl必填。必须以 https:// 开头;主机名须含点(如 merchant.example.com),不能是 localhost;不含用户信息(如 user@);端口省略或为 443;总长不超过 512 个字符。非空且不是合法 http(s) URL 返回 400;不传、空字符串,或是合法 URL 但不满足上述要求(如 http://、localhost、端口 8443)当前返回 9999
phone必填,只能是 5–15 位数字:不带 +、空格、横线或括号,也不要加国家码 61(国家码由 cardExtra 中 account_info.area_code 提供)。为空返回 400;非空但不符合上述格式当前返回 9999
email必填,形如 payer@example.com:不含空白,只有一个 @,@ 之后含点;不超过 254 个字符。为空返回 400;非空但不符合上述格式当前返回 9999
name仍必填(不能为空),但本产品不使用;付款人名、姓以 cardExtra 中的 first_name、last_name 为准
addr本产品不使用,可省略
cardExtra必填,JSON 字符串,格式见下
cardExtra 格式

cardExtra 的值是一段字符串:先把下面描述的 JSON 对象序列化成文本,再把这段文本作为 cardExtra 的字符串值放进请求体。顶层请求体仍是扁平 JSON,不要把 cardExtra 作为嵌套对象或数组发送。平台把该字符串解析为 JSON 后按以下规则校验:

  • 顶层必须恰好是 connection_info、account_info 两个对象,不允许任何其他键。
  • 两个对象中只能出现下表列出的键;出现未列出的键(包括拼写或大小写错误)即被拒。必填键缺失也被拒。
  • 除 create_time 外,所有值都必须是 JSON 字符串:不能为空或全空白,不能含控制字符(换行、制表符等),长度和格式须完全符合下表。
  • 任何文本值都不得含 cvv、cvc、card number、card no、security code 字样(不区分大小写,cardnumber、card_no、security-code 等写法同样禁止),不得含疑似卡号(13–19 位数字串,含以空格或 - 分隔的写法,且通过 Luhn 校验)。
  • 整个 cardExtra 字符串按 UTF-8 编码不超过 8192 字节。
  • 禁止放入卡号、CVV 等任何卡信息;卡信息只在托管支付页填写。

connection_info:

键必填类型规则
country是字符串固定为 "AU"
state是字符串NSW、VIC、QLD、ACT、NT、SA、TAS、WA 之一(大写)
zip_code是字符串4 位数字,如 "2000"
media_source是字符串来源标识,由商户自定:1–64 个字符,只能是字母、数字、_、-([A-Za-z0-9_-]{1,64})
user_agent否字符串付款人浏览器 User-Agent,不超过 1024 个字符,不含控制字符
uuid否字符串不超过 64 个字符,只能是字母、数字、.、_、:、-([A-Za-z0-9._:-]+)
language否字符串不超过 16 个字符,形如 en、en-AU([A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})?)

account_info:

键必填类型规则
merchant_user_id是字符串付款人在商户侧的稳定用户 ID;不超过 64 个字符,只能是字母、数字、.、_、:、@、-([A-Za-z0-9._:@-]+);与 email、phone 一一绑定,见下
create_time是整数该用户在商户侧的注册时间,Unix 毫秒时间戳,必须是 JSON 整数(不能加引号写成字符串,不能带小数);不小于 1000000000000,且不晚于当前时间
role是字符串GUEST 或 PRIVATE(大写)
area_code是字符串固定为 "61"(字符串,不是数字)
first_name是字符串付款人名:不超过 64 个字符,只能是英文字母、空格、'、-
last_name是字符串付款人姓:规则同 first_name

用户身份绑定:merchant_user_id 与 email、phone 一一绑定。同一 merchant_user_id 必须始终使用同一 email 和同一 phone;同一 email 或同一 phone 也不能出现在另一个 merchant_user_id 下(email 比较不区分大小写)。任一组合与之前的订单冲突时下单被拒。请使用商户侧稳定的用户 ID,不要每单随机生成,也不要多个用户共用一个 ID;用户更换邮箱或手机号前请联系平台。

cardExtra 示例(为便于阅读而换行;实际发送时用下方请求示例中的单行文本):

{
  "connection_info":{
    "country":"AU",
    "state":"NSW",
    "zip_code":"2000",
    "media_source":"demo_site",
    "user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
    "language":"en-AU"
  },
  "account_info":{
    "merchant_user_id":"demo-user-0001",
    "create_time":1767225600000,
    "role":"PRIVATE",
    "area_code":"61",
    "first_name":"Test",
    "last_name":"User"
  }
}
完整请求示例

以下全部为合成数据(IP 为文档保留地址段,邮箱与域名为 example.com,手机号为虚构值):

{
  "merchantOrderNo":"DEMO_AUD_20261003_001",
  "amount":"20.00",
  "currency":"AUD",
  "product":"AUD-VKDPWMRT",
  "payType":"CARD",
  "name":"Test User",
  "phone":"0491570156",
  "email":"payer@example.com",
  "clientIp":"203.0.113.10",
  "notifyUrl":"https://merchant.example.com/payments/notify",
  "returnUrl":"https://merchant.example.com/payments/result",
  "cardExtra":"{\"connection_info\":{\"country\":\"AU\",\"state\":\"NSW\",\"zip_code\":\"2000\",\"media_source\":\"demo_site\",\"user_agent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\",\"language\":\"en-AU\"},\"account_info\":{\"merchant_user_id\":\"demo-user-0001\",\"create_time\":1767225600000,\"role\":\"PRIVATE\",\"area_code\":\"61\",\"first_name\":\"Test\",\"last_name\":\"User\"}}"
}
该示例的待签名串

签名规则与第 3 节相同。以虚构的 appId=demo-app、timestamp=1700000000000、nonce=demo-nonce-0001、appSecret=demo-secret 为例,待签名串为(实际是一整行,此处未换行):

amount=20.00&appId=demo-app&cardExtra={"connection_info":{"country":"AU","state":"NSW","zip_code":"2000","media_source":"demo_site","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)","language":"en-AU"},"account_info":{"merchant_user_id":"demo-user-0001","create_time":1767225600000,"role":"PRIVATE","area_code":"61","first_name":"Test","last_name":"User"}}&clientIp=203.0.113.10&currency=AUD&email=payer@example.com&merchantOrderNo=DEMO_AUD_20261003_001&name=Test User&nonce=demo-nonce-0001&notifyUrl=https://merchant.example.com/payments/notify&payType=CARD&phone=0491570156&product=AUD-VKDPWMRT&returnUrl=https://merchant.example.com/payments/result&timestamp=1700000000000demo-secret
  • cardExtra 作为字符串原样参与签名:取的是请求体 JSON 解码后的字符串值本身。请求体里的 \" 在待签名串中就是 ";JSON 转义只是传输写法,不改变待签名值。
  • 先生成一次 cardExtra 文本,并用同一段文本既放进请求体、又参与签名。签名后不要再重新序列化或格式化 cardExtra:键顺序或空格的任何变化都会改变字符串内容,导致验签失败。
  • 值中的空格(如 Test User、User-Agent)原样保留,不做 URL 编码。
  • 本例时间戳已过期、密钥虚构,不能请求生产接口,因此不给出 sign 值;请用Python 示例或 Node.js 示例按第 3 节算法自行计算并核对。
结果

成功时响应与普通代收相同:返回平台 orderNo 和 payUrl(托管支付页 HTTPS 地址,可能不在 HissPay 域名下),payStatus=0 只表示已创建。之后按下文「托管收银台」的方式引导付款人打开 payUrl,以验签通过的回调或查单结果为准,按 realAmount 入账;跳回 returnUrl 不代表已付款。

托管收银台(hosted checkout)

托管收银台产品下单后返回托管支付页链接,付款人在该页面选择方式并付款,商户不接触支付信息。

  1. 调用代收下单,保存平台 orderNo,把 payUrl 交给付款人:网页端整页跳转或在新窗口打开。能否嵌入 iframe,待确认。
  2. 支付页有有效期,因支付方式而异(例如 15 分钟或 1 小时)。不要缓存或重复发放旧链接。
  3. 付款后付款人可能跳回 returnUrl,也可能停留在支付页。跳回不代表已付款,未跳回也不代表未付款。
  4. 等待平台代收成功通知(status="1"),或低频查单直到 payStatus=1;按 realAmount 入账(第 4 节)。
  5. 付款人放弃或链接过期时,平台通常不发送失败通知,查单可能一直是 payStatus=0;只有通道明确确认付款失败时才可能收到失败通知或查到 payStatus=2(第 8、10 节)。如需让付款人重新付款,先联系平台确认原单已关闭,再用新的 merchantOrderNo 创建订单;不要用原订单号重新下单。
  6. 收银台页面展示哪些支付方式由产品配置决定;商户不能通过本接口要求只收银行卡。

USDT 代收(加密资产)

USDT 代收使用与法币相同的下单、查单和异步通知接口,currency 固定为 USDT,通过 product 选择网络;商户不传链编号或网络字段。对应产品在上方目录中标为 LIVE 之前不可下单(当前为 PLANNED,即将开放,不可下单)。

产品编码资产网络金额精度
USDT-TRONUSDTTron最多 4 位小数
USDT-ETHEREUMUSDTEthereum最多 4 位小数
USDT-BSCUSDTBSC最多 4 位小数
USDT-SOLANAUSDTSolana最多 4 位小数
  • 金额使用十进制字符串,四个网络统一最多 4 位小数(最小单位 0.0001 USDT),且须满足签约路由的金额下限;超出精度返回 10006。后续如放宽精度会另行通知。
  • payType 可省略;显式传入时为 CRYPTO。clientIp、cardExtra 沿用通用规则。

下单请求示例:

{
  "merchantOrderNo":"DEMO_USDT_20261001_001",
  "amount":"12.3456",
  "currency":"USDT",
  "product":"USDT-TRON",
  "name":"Test User",
  "phone":"YOUR_TEST_PHONE",
  "email":"payer@example.com",
  "notifyUrl":"https://merchant.example.com/payments/notify",
  "returnUrl":"https://merchant.example.com/payments/result"
}

下单成功时响应比法币多返回收款信息 paymentInfo(product 所有代收均返回);商户可跳转 payUrl,也可按自身页面规范展示地址和二维码:

{"code":0,"msg":"Success","data":{"appId":"YOUR_APP_ID","merchantOrderNo":"DEMO_USDT_20261001_001","orderNo":"PLATFORM_ORDER_NO","currency":"USDT","product":"USDT-TRON","amount":12.3456,"payUrl":"https://cashier.example.com/example","payStatus":0,"paymentInfo":{"asset":"USDT","network":"TRON","address":"NETWORK_RECEIVING_ADDRESS","amount":"12.3456","qrCodeImage":null,"expiresAt":"2026-10-01T12:00:00Z"},"otherExtend":null}}
  • paymentInfo 仅 USDT 产品且平台已分配收款地址时返回,否则不返回该键;返回时 6 个字段全部输出;network 为 TRON、ETHEREUM、BSC 或 SOLANA;qrCodeImage 为预留字段,当前版本恒为 null,请按 address 与 amount 自行生成二维码;expiresAt 为 UTC ISO 8601 时间,由平台给出,可能为 null;有值时过期后不要继续引导付款。响应中的 amount 为 JSON 数字,paymentInfo.amount 为字符串,均最多 4 位小数,请用 Decimal 解析。
  • 付款人须按 paymentInfo.amount 足额转账;payStatus=0 只表示待付款,不代表链上到账。
  • 查单(第 8 节)额外返回 product 和 txHash;txHash 仅在链上确认后返回,确认前不返回该键。建议轮询间隔 10–15 秒并退避。
  • 成功通知(第 10 节)在有 txHash 时追加该字段,参与签名;USDT 通知金额保留 4 位小数。
  • 按通知或查单中的 realAmount 幂等入账;不要用订单 amount 替代缺失的 realAmount。

订阅与定期扣款

平台目前没有订阅或定期扣款接口。不要用代收下单模拟订阅或周期扣款;有需求请联系平台。

下单结果不确定时

下单请求超时、断线、HTTP 5xx、返回非 JSON 或无法判断的结果时,订单可能已经创建。平台遇到不确定结果时不会自动重新提交,商户也不要重新提交。

  1. 保留原 merchantOrderNo,不要再次调用代收下单:既不要换新订单号重下,也不要用同一订单号重下。
  2. 用原 merchantOrderNo 低频查单,并等待验签通过的成功通知;以回调或查单的 payStatus=1 为准。
  3. 不要用同一订单号修改金额或其他参数后重下:同一订单号再次下单返回 10020(启用业务幂等的产品参数不同返回 409,第 4 节)。
  4. 长时间保持 payStatus=0 时联系平台核对,不要自行判定失败,也不要让付款人再次付款。

16.3 THB 代收(PromptPay 扫码)

POST /transaction/payin/v1/apply,字段在第 6 节字段表基础上按下表填写。下表是统一契约:同时满足所有付款通道的要求。不同付款通道实际做的校验不完全相同,部分不合规的值可能被某些通道接受、或被替换为默认值(如不合规的 returnUrl 可能被替换为平台默认结果页),因此平台不保证对不符合下表的请求一律拒绝;请按下表在提交前自行校验,不要以平台是否拒绝作为判断依据。

字段必填THB 代收要求
currency是固定 THB
product是平台分配的 THB 代收产品编码
amount是见 16.2,默认 500.00–49999.00
name是付款银行账户的户名,须与付款账户户名一致。去掉首尾空格后 1–50 个字符;只能使用泰文或英文字母(含泰文元音及声调符号)、空格、.、'、-,首字符须为字母;不能含数字或其他符号
phone是付款人手机号:6–15 位数字,可带一个前导 +(如 0812345678、+66812345678),不含空格或 -
email是必填。付款人邮箱,形如 payer@example.com,不含空格,不超过 64 个字符。不传或传空字符串时返回 400(msg 形如「请求参数不正确:email invalid」);格式不符或超长返回 9999(见下方自查清单)
cardExtra是JSON 字符串,格式见下
payType否请勿传。付款方式由 THB 代收产品决定(PromptPay 扫码),目前没有对应的 payType 编码。平台编码表中的 THB CARD、PAYPAL 组合能通过编码校验,但与本产品无关,传入也不会改变付款方式
returnUrl否付款后浏览器跳转地址。填写时必须是 https:// 绝对地址,不能包含 ? 查询参数或 # 片段,不含空白字符,不超过 128 个字符;开通通知给出更短的上限时以通知为准。不填时付款后显示平台的默认结果页。开通通知未确认长度上限前,建议不传
notifyUrl否与第 6 节相同;平台通知只发往这里或商户默认通知地址
clientIp、addr否本产品不使用,可省略

cardExtra 的值是一段字符串:把下面的 JSON 对象序列化成文本,再作为 cardExtra 的字符串值放进请求体(与第 6 节其他产品相同,不要作为嵌套对象发送)。对象必须恰好包含以下两个键,不允许其他键,值都必须是 JSON 字符串,序列化后的文本不超过 512 个字符:

键必填规则
payerAccountNo是付款人的泰国银行账号(不是银行卡号,也不是手机号或 PromptPay ID),6–20 位纯数字,保留前导零,不含空格或 -
payerBankCode是付款银行,取 16.1 表中「代收」为「支持」的编码

说明:本产品要求提交付款人的银行账号与户名,用于让付款人使用该账户完成扫码付款;这是第 6 节「不要提交卡号」规则的唯一例外,仍然不得提交银行卡号、CVV、密码或任何验证码。付款人使用其他账户或其他户名付款时,可能无法自动确认到账,订单会进入人工核对。

完整请求示例:

{
  "merchantOrderNo":"DEMO_THB_20261026_001",
  "amount":"1500.50",
  "currency":"THB",
  "product":"YOUR_THB_PAYIN_PRODUCT",
  "name":"Somchai Jaidee",
  "phone":"0812345678",
  "email":"payer@example.com",
  "notifyUrl":"https://merchant.example.com/payments/notify",
  "cardExtra":"{\"payerAccountNo\":\"1234567890\",\"payerBankCode\":\"SCB\"}"
}

该示例的待签名串(虚构 appId=demo-app、timestamp=1700000000000、nonce=demo-nonce-0001、appSecret=demo-secret;实际是一整行):

amount=1500.50&appId=demo-app&cardExtra={"payerAccountNo":"1234567890","payerBankCode":"SCB"}&currency=THB&email=payer@example.com&merchantOrderNo=DEMO_THB_20261026_001&name=Somchai Jaidee&nonce=demo-nonce-0001&notifyUrl=https://merchant.example.com/payments/notify&phone=0812345678&product=YOUR_THB_PAYIN_PRODUCT&timestamp=1700000000000demo-secret

对应 sign(SHA-256 小写十六进制):2857fc38acbfdcbaec806757360be995c4fa32349ffb5b6a273e14f6c3304bd4

cardExtra 按解码后的字符串原样参与签名,规则同第 6 节「澳洲银行卡(AUD-VKDPWMRT)」中的说明:先生成一次文本,同一段文本既放进请求体又参与签名。

成功响应与普通代收相同(第 6 节),例如:

{"code":0,"msg":"Success","data":{"appId":"YOUR_APP_ID","merchantOrderNo":"DEMO_THB_20261026_001","orderNo":"PLATFORM_ORDER_NO","currency":"THB","product":"YOUR_THB_PAYIN_PRODUCT","amount":1500.50,"payUrl":"https://cashier.example.com/example","payStatus":0,"otherExtend":null}}
  • payUrl 是收银台页面(含 PromptPay 二维码)的地址,域名可能是第三方收银台,不在 HissPay 域名下,协议可能是 https 或 http。请把付款人直接跳转到 payUrl:不要校验或白名单限制其域名,不要改写、截断或追加参数,也不要自行重新生成二维码。payStatus=0 只表示已创建。
  • 引导付款人用 cardExtra 中声明的银行账户扫码付款。付款页的有效期由付款页面显示;过期后不要让付款人重复付款,按下文处理。

下单结果与处理:

下单结果订单状态处理
code=0 且有 payUrl处理中引导付款,等待成功通知或查单
400、10006、10012 等通用校验错误未创建或未提交按第 11 节修正后用新单号下单
9999,且原单查单 paymentStatus=CANCELLED 或查无此单本节要求不满足,订单未提交付款通道,没有 payUrl按下方自查清单修正后用新的 merchantOrderNo 下单
9999,且原单查单 paymentStatus=PROCESSING结果未知:请求可能已到达付款通道按第 6 节「下单结果不确定时」处理,不要换单号重下
10009付款通道明确未受理,没有 payUrl;当前订单仍显示 PROCESSING不要用原单号重试,不要引导付款;联系平台核对后再决定是否用新单号下单
HTTP 5xx、超时、非 JSON结果未知同第 6 节「下单结果不确定时」

9999 自查清单(THB 代收):cardExtra 是字符串且恰好含两个键;payerAccountNo 为 6–20 位数字;payerBankCode 是 16.1 的 6 个代收编码之一;name 符合户名规则且不超过 50 个字符;phone、email 都已填写且符合上表格式(不传会先返回 400);returnUrl 不传,或为不含 ?/#、不超过上限的 https:// 地址;金额在单笔范围内;没有传 payType。

结果确认:

  • 平台核实付款状态与金额后才把订单置为成功,并发送成功通知(第 10 节,status="1",realAmount 等于订单金额)。THB 代收只发送成功通知。
  • 付款失败、放弃或过期的订单不发送通知。生产环境中这类订单一般长期保持 PROCESSING(旧字段 payStatus=0),平台目前不会把 THB 代收自动置为 FAILED;沙箱失败场景(尾数 .01、.07)会显示 paymentStatus=FAILED、isFinal=true,仅用于演练。不要把长期处理中当作失败,也不要换单号让付款人再付一次。
  • 创建超过 3 天仍未确认成功的订单,平台可能无法再自动核实,请联系平台人工核对;不要换单号重复收款。

7. 代付下单

POST /transaction/payout/v1/apply

字段必填说明
merchantOrderNo是商户唯一代付订单号,最长 255 个字符
amount是主币种金额,须大于 0 且不低于代付最低金额(通道下限与签约下限中的较高者,见第 4 节);低于最低金额返回 10006
currency是已开通币种
product是已签约的代付产品编码,与代收产品分开,最长 20 个字符
accountName是收款账户姓名
account是收款银行账号或适用支付账户,字符串
phone是收款人手机号
email是收款人邮箱
bizCode条件必填业务类型编码,按平台提供的编码填写。仅下文「免填 bizCode / branchCode 的条件」三项同时满足时可不传;否则缺失或为空返回业务码 400
payCode是支付方式编码;由平台按产品提供
branchCode条件必填分行或银行标识;印度银行代付通常填写收款账户 IFSC,THB 填银行编码(第 16 节)。免填条件同 bizCode
bankName否银行名称,视通道要求;最长 255 个字符,超长返回业务码 400
notifyUrl否本单 HTTPS 回调地址;可回退到商户默认通知地址
address否收款人地址
accountId是收款人在商户系统中的唯一标识,同一收款人保持不变;平台按通道要求作为收款用户标识上送
swiftCode否SWIFT 标识,视通道要求
extra否扩展信息,使用前确认格式

免填 bizCode / branchCode 的条件(三项同时满足才可省略,否则两者都必填):

  1. payCode 为 CARD;
  2. product 为 USD-PAYPLUS-PAYOUT、USD-LOCAL-PAYOUT 或 AUD-LOCAL-PAYOUT 之一;
  3. currency 与产品匹配:前两个产品为 USD,AUD-LOCAL-PAYOUT 为 AUD。

例如上述产品传 payCode=BANK,或币种不匹配时,缺少 bizCode / branchCode 会返回业务码 400。

{
  "merchantOrderNo":"DEMO_OUT_20260912_001",
  "amount":"100.00",
  "currency":"INR",
  "product":"INR-NPLMSUEX",
  "accountName":"RECIPIENT_NAME",
  "account":"RECIPIENT_ACCOUNT",
  "phone":"RECIPIENT_PHONE",
  "email":"recipient@example.com",
  "bizCode":"ASSIGNED_BIZ_CODE",
  "payCode":"ASSIGNED_PAY_CODE",
  "branchCode":"RECIPIENT_IFSC",
  "notifyUrl":"https://merchant.example.com/payments/notify"
}

成功受理返回 appId、merchantOrderNo、orderNo、currency、amount、payStatus:0。平台会校验可用余额,并按签约费用及账务规则占用资金,异步完成付款。不要收到 code=0 就向用户宣称“已到账”,也不要因为尚未回调再次提交新代付。

代付下单返回非 0 业务码时,订单通常未创建、未占用资金;返回 500、超时或非 JSON 时结果未确认,须先查原单。代付接口的 msg 当前统一改写、不指出具体字段,各类拒绝的返回形式与处置见第 11 节「代付下单的拒绝与 msg」。

USD 银行卡代付接入(按商户开通)

本节描述 USD 银行卡代付的接口格式,不代表该产品已向您的应用开放。先由平台确认产品编码、USD 账户、额度、费用、来源 IP 白名单及收款人确认,再使用生产应用。当前只支持单笔 CARD,不支持该产品批量代付或自动重付;收款人通过下方独立接口创建、查询和更新。请勿复用 USD 钱包代付产品编码。

字段USD 银行卡要求
currency / payCodeUSD / CARD
product平台为该应用开通的银行卡代付产品编码;不是渠道名称或代收产品
account收款卡号,13–19 位数字,通过卡号校验;不要提交 CVV
extraJSON 字符串,仅含 beneficiary_id(正整数)和 card_valid(MM/YYYY);有效期不能已过期
extra.beneficiary_id收款人接口查询 READY 后返回的 beneficiaryId;不可猜测,不可跨应用、产品或环境使用
accountName / phone / email必填,填写该收款人的合法信息
bizCode / branchCode此美国卡代付产品不需要,新订单省略这两个字段;不填写 IMPS、IFSC 或占位值。历史订单重试保留首次请求原值,避免幂等冲突
notifyUrl您自己的 HTTPS 接收地址。接收的是本平台商户通知,不是资金服务商的通知格式

以下为结构示例。替换所有占位值后使用,金额须符合实际签约范围;编号 12345 仅用于展示类型。

{
  "merchantOrderNo":"MERCHANT_OUT_UNIQUE_001",
  "amount":"100.00",
  "currency":"USD",
  "product":"USD-PAYPLUS-PAYOUT",
  "accountName":"RECIPIENT_NAME",
  "account":"RECIPIENT_CARD_NUMBER",
  "phone":"RECIPIENT_PHONE",
  "email":"recipient@example.com",
  "payCode":"CARD",
  "extra":"{\"beneficiary_id\":12345,\"card_valid\":\"12/2030\"}",
  "notifyUrl":"https://merchant.example.com/payout/notify"
}

签名沿用第 3 节:请求体平面字段与 appId、timestamp、nonce 合并,按键排序,拼接 key=value(& 分隔),末尾直接追加 appSecret,再计算 UTF-8 SHA-256 小写十六进制。extra 是字符串,以传输时相同的字符串内容参与签名;不要把 JSON 内部字段单独展开或改空格。timestamp 为毫秒,时间误差不超过 30 秒,每次 HTTP 请求使用新 nonce。商户只使用本平台 appId/appSecret。

可下载 Python 请求示例、Java 请求示例 和 JSON 配置模板、Java 配置模板。Python 默认只预检,Java 默认只预检;均需显式 --send 才请求。先用 query 或 balance 验证鉴权,单笔提交时保存原单号。两种示例都不会自动重试或跟随重定向;通信中断后用原单号查单,不换号重付。示例配置可能含卡资料,仅保存在受限服务器,不提交 Git。

python3 payout_request.py balance payout-request.json
python3 payout_request.py query payout-request.json --send
javac PayoutRequest.java
java PayoutRequest balance payout-request.properties
java PayoutRequest query payout-request.properties --send

生产请求地址由 HISSPAY_GATEWAY 指定(https://transaction.hisspay.com);商户模拟测试使用 https://sandbox-api.hisspay.com 和独立沙箱凭据。HISSPAY_APP_ID、HISSPAY_APP_SECRET 只在服务器环境变量配置。

结果判定与幂等:下单 code=0 / payStatus=0 只是受理。同一应用与 merchantOrderNo 唯一绑定原请求:相同单号再次提交返回 10020;若开通通知说明本产品已启用业务幂等,则相同参数返回原受理结果、改变金额或收款资料返回 409(第 4 节)。出现超时、5xx、无回调、查单暂未找到时均不能推断付款失败。先查原单;paymentStatus=SUCCEEDED / isFinal=true 表示成功,FAILED / true 表示失败,其他状态继续核对。退款或异常资金调整由平台核对,不能据此自动重付。

异步通知:JSON 字段为 merchantOrderNo、orderNo、currency、product、amount、status、statusDes,utr 可能为空。status="1" 成功、status="2" 失败;这与查询的 paymentStatus 不同。HTTP 头 appId/timestamp/nonce/sign 按第 10 节验签(空值不参与签名)。核对订单归属、币种、产品和原金额,在数据库事务中按应用和订单去重并保存结果后,返回 HTTP 200、纯文本 SUCCESS 或 OK。同一状态重复通知应正常 ACK,冲突终态进入人工核对,不能再次付款。成功响应正文不要包 JSON 或 HTML。失败说明仅用于诊断,不据 statusDes 文本判断资金终态。

常见错误:400 参数或签名错误;10006 金额限制;10008 可用余额不足;10010 代付来源 IP 未加白;10011 产品无效;10005 无可用路由;10020 商户订单号重复;409 同单号参数冲突(仅启用业务幂等的产品);429 限流。代付接口的 msg 统一改写(见第 11 节「代付下单的拒绝与 msg」)。500、超时及非 JSON 错误均视为结果尚未确认,查原单。完整错误码见第 11 节,HTTP 200 本身不能代表业务成功。

商户可先完成 沙箱代付完整自测,包括成功、失败、未知结果查询、手动终态、真实沙箱通知与本地重复通知去重。该测试使用模拟资金,不证明生产银行卡到账或服务商沙箱验收通过。

美国与澳洲:按支付方式阅读

按“适用范围 → 收款人 → 请求路径与方法 → Header → Body → 返回结果 → 查询与回调 → 测试”顺序接入。下表区分服务商规范与本平台接口,不能混用域名、签名或状态码。

项目美国 USD 卡代付澳洲 AUD
正式支持已签约并开通 USD-PAYPLUS-PAYOUT 的应用;美国收款人,借记卡出款尚未开放;已核实的正式卡代付规范未列出 AUD,不提供推测的正式请求
平台沙箱USD-LOCAL-PAYOUT;模拟收款账户,不发生真实银行卡出款AUD-LOCAL-PAYOUT;模拟收款账户,不证明真实 AUD 出款已支持
收款人创建 → 查询 READY → 使用返回编号付款;可复用同一已确认收款人平台模拟使用 SANDBOX-SUCCESS 等场景账户;正式受益人规则待官方规范确认
bizCode / branchCode新订单省略;不需要平台另发出款或分行编码AUD-LOCAL-PAYOUT + AUD + CARD 的模拟订单省略;不可据此构造正式请求
金额以本应用签约限额为准,不从沙箱最低额推断正式限额模拟最低 100 AUD;正式范围不作承诺

美国字段对应关系:平台 extra.beneficiary_id 对应服务商 beneficiary_id;account 对应 card_number;extra.card_valid 对应 card_valid(MM/YYYY);currency、amount 含义一致。平台生成服务商 reference_id,商户使用自己的 merchantOrderNo 查单和对账。收款人 firstName/lastName/payeeId 是平台字段,平台负责转换和隔离,商户不能直接提交其他账户的服务商编号。extra 保持 JSON 字符串格式参与签名。

平台差异:商户请求本平台 /transaction/payout/v1/...,使用本平台 appId/timestamp/nonce/sign;不要使用服务商的 AppId/Authorization 或服务商密钥。product/payCode/notifyUrl 是本平台路由和商户通知字段。平台下单受理 code=0 不等于到账;查询终态和验签回调按本节说明处理,不直接套用服务商返回码。已有订单重试时保持首次完整请求,包括原 bizCode/branchCode;不要因新版将字段改为空、删掉或换商户单号再次付款。

收款人管理:创建 → 查询确认 → 代付

本节为新增接口接入说明,须在平台通知接口及您签约产品已开放后使用;文档中的格式示例不代表正式代付已开通。当前实际银行卡流程仅支持美国收款人(country=US)及 USD。AUD 沙箱模拟仍可测试,但不表示真实 AUD 银行卡代付已获支持。

商户可为不同收款人创建记录,无需平台提前绑定一个固定收款人。为每位收款人在自己的系统中生成稳定的 payeeId,相同应用内不可换绑其他人;不要使用邮箱或卡号作为该标识。不同应用、产品及环境的记录不可混用。资料和卡号仅在商户服务端安全保存,不出现在前端、日志或代码仓库。

操作HTTPS POST 路径operation
创建收款人/transaction/payout/v1/beneficiaries/createCREATE
查询收款人/transaction/payout/v1/beneficiaries/queryQUERY
更新资料/transaction/payout/v1/beneficiaries/updateUPDATE

三种操作均用本平台 appId / timestamp / nonce / sign 签名,规则与代付一致;operation 是请求体必填字段,也参与签名,必须匹配路径。资料为平面字符串,不嵌套 JSON;更新时 version 必须是 JSON 整数,不能加引号。

字段创建查询更新填写方法
operation必填必填必填分别为 CREATE、QUERY、UPDATE
product必填必填必填您已签约的 USD 银行卡代付产品编码
payeeId必填必填必填商户不可变收款人标识,3–60 位字母、数字、下划线或连字符
language / country必填不传必填语言与国家,例如 en / US
phone / email必填不传必填收款人真实联系电话与邮箱
birthdate必填不传必填真实出生日期,YYYY-MM-DD
firstName / lastName必填不传必填收款人真实名与姓
zip / city / state / address必填不传必填收款人真实邮编、城市、州及地址
version不传不传必填最近查询返回的版本,JSON 非负整数;不要猜测或固定为 0
requestId不传不传必填本次修改的唯一标识,3–60 位字母、数字、下划线或连字符

产品编码最多 20 字符,所有资料不能含控制字符。语言为两个英文字母;电话为 4–12 位数字,或 +国家码-号码(国家码 1–3 位,例如 +1-2025550123)。名、姓各 3–50 字符,支持拉丁字母、撇号、连字符及内部空格。城市和州为 2–50 字符,支持拉丁字母及撇号、&、括号、连字符、内部空格;美国邮编为 5 位、5+4 位或 5–10 位数字。地址 5–100 字符,支持字母、数字、空格及 # ' ( ) , - . / : ; °;邮箱最多 120 字符。出生日期须在 1900-01-01 至当前 UTC 日期之间。更新版本须为 JSON 整数,范围 0–9223372036854775806。

查询仅传 operation / product / payeeId,不传个人资料,也不传第三方受益人编号。更新须提交完整资料,不是局部补丁;payeeId 不可改名或转给另一人。

响应沿用 { "code": 0, "msg": "", "data": ... }。data 包含 payeeId、可为空的 beneficiaryId、status 和 version。必须同时检查业务 code 和状态;HTTP 200 本身不表示收款人可用于付款。

status商户处理
READY资料已确认;有有效 beneficiaryId 时才可申请代付
UNKNOWN创建或更新结果未确认;查询同一 payeeId,不要换号重建
NOT_FOUND查询暂未确认记录;不能据此自动重复创建,先核对原请求或联系平台
REVIEW资料或结果需要核对;暂停对此记录出款

推荐流程:

  1. 新收款人调用 create,并保存原 payeeId 和响应。连接中断或结果未知时改查同一 payeeId,不换号重复创建。
  2. 调用 query,确认 READY,保存返回的 beneficiaryId 和 version。相同资料的已确认收款人可复用。
  3. 以该 beneficiaryId 填写原代付请求 extra 的 beneficiary_id,同时填写真实卡号和 card_valid;然后用唯一 merchantOrderNo 申请一次代付。收款人创建成功不表示付款已完成。
  4. 需要修改尚未用于出款的记录时,使用最近 version、新的 requestId 和完整资料调用 update,再查询确认。版本冲突返回 409 时先查最新记录,不盲目递增或重放更新。
  5. 已被任意出款冻结上下文使用的收款人不能再更新;合法资料变化需要新的 payeeId,重新创建并确认。新记录不能替代对旧代付订单的查询,也不能作为重复付款理由。

格式错误通常为 400,未开放或无权限为 403,身份、版本或已使用冲突为 409;500、超时及非 JSON 响应按结果未知处理。所有请求使用新的时间戳和 nonce,但不能把新的签名当成可重复创建、更新或付款的许可。

Python / Java 收款人请求示例

下载 Python 示例、公共签名客户端、Java 示例,以及创建、查询、更新模板:创建 JSON / Properties、查询 JSON / Properties、更新 JSON / Properties。示例资料全部为虚构,发送前替换产品及真实收款人资料。配置文件执行 chmod 600。

# 默认只预检字段名称,不打印收款人资料,也不请求网络。
python3 beneficiary_request.py create beneficiary-create.json
python3 beneficiary_request.py query beneficiary-query.json
python3 beneficiary_request.py update beneficiary-update.json
javac BeneficiaryRequest.java
java BeneficiaryRequest create beneficiary-create.properties
java BeneficiaryRequest query beneficiary-query.properties
java BeneficiaryRequest update beneficiary-update.properties

环境变量沿用 HISSPAY_GATEWAY、HISSPAY_APP_ID、HISSPAY_APP_SECRET,须选对应环境的凭据。正式环境会创建或修改真实收款人;确认服务开放和资料准确后,才为所需命令加 --send。不要一次批量执行创建、更新和付款。示例不自动重试,不跟随重定向;query 确认 READY 后,将返回编号放入 代付 Python 示例 或 Java 示例 的配置,再单独提交付款。

平台 USD/AUD 沙箱代付合成标记无需真实收款人资料,仍使用原有沙箱完整自测工具。本节新增收款人接口的沙箱可用性须以平台开放通知为准,不能将合成银行卡标记用到正式网关。

USD / AUD 代付沙箱示例

美国USD与澳洲AUD均可按沙箱测试指南使用平台模拟资金完成下单、查单、成功/失败通知和重复通知验收。使用对应币种的独立沙箱应用、已开通代付产品与路由,默认金额100。模拟结果不证明真实银行卡到账或正式产品开通。

下载完整自测工具,其中包含Python与Java,以及USD JSON、USD Properties、AUD JSON、AUD Properties。合成收款标记仅限沙箱,未知结果查询原单,不重复提交。

16.4 THB 代付(银行转账)

THB 代付需单独开通,以开通通知为准。 未收到开通通知(含代付产品编码、可用银行、户名长度上限、单笔范围与费率)前请勿调用;下文是开通后的接口格式。

POST /transaction/payout/v1/apply,字段在第 7 节字段表基础上按下表填写:

字段必填THB 代付要求
currency是固定 THB
product是平台分配的 THB 代付产品编码(第 1 节目录,以开通通知为准)
payCode是不能为空;填 BANK。平台不按 payCode 选择 THB 付款通道,开通通知另有说明时以通知为准
amount是收款人应收金额,见 16.2,默认 500.00–49999.00
bizCode是固定为 BANK
branchCode是收款银行编码,取 16.1 表中的值,且须在开通通知列出的可用银行内(可用银行按付款通道配置)
account是收款人泰国银行账号,6–20 位纯数字,保留前导零,不含空格或 -;必须真实有效
accountName是收款账户户名,须与收款账户一致:泰文或英文字母(含泰文元音及声调符号)、空格、.、'、-,首字符须为字母,去掉首尾空格后按字符计算长度。长度上限按付款通道不同,以开通通知为准:部分通道默认最多 10 个字符(付款通道自身限制,平台可在通道确认后放宽,最多 50),部分通道最多 64 个字符。开通通知未写明时按 10 个字符准备;户名超长时不要自行截断,联系平台确认
phone是收款人手机号:6–15 位数字,可带一个前导 +(如 0812345678 或 +66812345678),不含空格或 -
email是必填。收款人邮箱,形如 recipient@example.com,不含空格,不超过 64 个字符。不传或传空字符串时返回业务码 400(代付 msg 见第 11 节)
notifyUrl否与第 7 节相同
bankName、swiftCode、address、accountId、extra否本产品不使用,可省略

完整请求示例:

{
  "merchantOrderNo":"DEMO_THB_OUT_20261026_001",
  "amount":"2000.00",
  "currency":"THB",
  "product":"YOUR_THB_PAYOUT_PRODUCT",
  "payCode":"BANK",
  "bizCode":"BANK",
  "branchCode":"KBANK",
  "account":"1234567890",
  "accountName":"Somchai J",
  "phone":"0812345678",
  "email":"recipient@example.com",
  "notifyUrl":"https://merchant.example.com/payments/notify"
}

该示例的待签名串(虚构值同上;实际是一整行):

account=1234567890&accountName=Somchai J&amount=2000.00&appId=demo-app&bizCode=BANK&branchCode=KBANK&currency=THB&email=recipient@example.com&merchantOrderNo=DEMO_THB_OUT_20261026_001&nonce=demo-nonce-0001&notifyUrl=https://merchant.example.com/payments/notify&payCode=BANK&phone=0812345678&product=YOUR_THB_PAYOUT_PRODUCT&timestamp=1700000000000demo-secret

对应 sign:d5e969c9734479c732d7f3a8e74b9e273e9334ccc7f805eb3d067ab663236f4b

结果与状态:

  • 下单 code=0 只表示平台已受理并占用资金(16.2),付款异步完成;不要据此宣称已到账。
  • 本节字段不合规时同步返回参数校验错误、本次请求未建单、不占用资金:msg 形如 Invalid payout request: <field> <rule>,指出字段与规则(不回显字段值),具体返回码与各字段的 msg 见第 11 节「代付下单的拒绝与 msg」。按 msg 修正后重新提交(可沿用原 merchantOrderNo)。
  • 平台可能按权重把 THB 代付分配到多个付款通道;校验按本次可能分配到的所有通道规则的交集执行(户名取最严上限、可用银行取交集等),与实际分配到哪个通道无关。
  • 下单返回 500(Payout request not confirmed; query original order)表示平台或上游出现未知异常、结果未确认:保留原单号查单,不要换单号重付(第 11 节)。
  • 自查清单:bizCode=BANK;branchCode 在 16.1 表且在开通通知的可用银行内;account 6–20 位数字;accountName 只含允许的字符且不超过开通通知的长度上限;phone 6–15 位数字可带前导 +;email 格式正确且不超过 64 个字符;金额在单笔范围内。
  • 平台核实付款通道的处理结果和金额后才给出终态:成功通知 status="1"(utr 为银行流水号,可能为 null),失败通知 status="2"。statusDes 只用于展示和排查,不要用它做程序判断。
  • 超时不等于失败。 结果无法确认(如付款通道超时、处理中、返回不一致或无法验证)时,订单保持处理中(查单 payStatus=0),资金继续占用,由平台核对后再给出终态。不要因为尚未收到通知或查单仍为 0 就判定失败、退款给用户,或用新的商户订单号重复代付;超过您内部跟踪时限时联系平台人工核对(第 12 节)。
场景查单 payStatus通知 status含义
已受理/处理中/结果待核实0不发送继续等待,不要重复提交
付款成功1"1"已核实成功,utr 可能为 null
付款失败或被拒(含部分通道的提交前校验未通过)2"2"未出款,按账务规则释放占用资金

8. 查单与状态

代收:POST /transaction/payin/v1/query

代付:POST /transaction/payout/v1/query

{"merchantOrderNo":"YOUR_ORIGINAL_MERCHANT_ORDER_NO"}

或使用平台订单号:

{"orderNo":"PLATFORM_ORDER_NO"}

两者至少提供一个,建议只传一个。两者同时提供时必须指向同一笔订单,否则返回 30001。使用创建订单的同一个 appId;不存在或不属于当前应用的订单也可能返回 30001。

返回字段:appId、merchantOrderNo、orderNo、currency、amount、payStatus,以及第 14 节的 paymentStatus、isFinal、可选 failureReason。代收额外返回 realAmount、product(当前订单均返回,历史归档订单可能为 null)、txHash(仅 USDT 产品在链上确认后返回,法币或确认前不返回该键)和可选 failureCode(通道明确确认付款失败时给出,取值如 PAYMENT_DECLINED、PAYMENT_RISK_REJECTED、PAYMENT_FAILED);金额字段为 JSON 数字;代付额外返回 payStatusDes。未知的新字段请忽略。

场景状态字段值含义
代收下单payStatus0创建/待支付
代收查单payStatus1已收款
代收查单payStatus0未报告成功:创建、处理中、待核对、已取消或结果未知,用 paymentStatus 细分
代收查单payStatus2通道明确确认付款失败(目前仅部分通道),paymentStatus=FAILED、isFinal=true
代付下单payStatus0已受理、异步处理中
代付查单payStatus0处理中或尚未得出终态
代付查单payStatus1付款成功
代付查单payStatus2付款失败

不能把代收查单的 0 当作“确定失败”;代收失败只在 payStatus=2 或 paymentStatus=FAILED(isFinal=true)时确认。成功代收的原金额与实际金额可以不同,按上述实际到账规则处理。金额缺失/非法、长时间未决、查询与回调矛盾时保留订单并联系平台核对。

9. 余额查询

POST /transaction/payout/v1/balance

{"currency":"INR"}
{"code":0,"msg":"Success","data":{"appId":"YOUR_APP_ID","accountNo":"ACCOUNT_NUMBER","currency":"INR","balance":1000.00,"balanceActive":800.00,"balanceFreeze":200.00}}
  • balance:账面余额。
  • balanceActive:可用余额,是否可代付还要考虑手续费及其他校验。
  • balanceFreeze:冻结/占用金额,不能再次使用。

页面旧余额不能替代实时查询。扣款、代付或审核中的申请可能已占用资金;应处理原申请,不要重复提交来尝试“清零”。

10. 异步通知与验签

平台以 POST JSON 请求商户 notifyUrl,头部携带 appId、timestamp、nonce、sign。

通知体

代收成功示例(字段值当前以字符串发送):

{"currency":"INR","merchantOrderNo":"DEMO_IN_20260912_001","orderNo":"PLATFORM_ORDER_NO","product":"YOUR_PAYIN_PRODUCT","amount":"100.00","realAmount":"100.00","status":"1"}

代付成功示例:

{"currency":"INR","merchantOrderNo":"DEMO_OUT_20260912_001","orderNo":"PLATFORM_ORDER_NO","product":"YOUR_PAYOUT_PRODUCT","amount":"100.00","utr":"BANK_REFERENCE_IF_AVAILABLE","status":"1","statusDes":"Success"}

代付失败:status="2",statusDes 提供原因(仅供展示)。utr 可能为 null;不能假设每次都有。法币通知金额字符串固定两位小数,JPY 等零小数币种的通知也如此;USDT 通知金额固定 4 位小数。不要混淆通知体的 status 与查单的 payStatus。

代收失败通知

代收成功一定发送通知;失败通知只在部分通道、且通道明确确认付款失败时发送,其余失败、放弃、过期或取消的订单不发送通知,须查单或联系平台核对。失败通知 status="2"、realAmount="0.00",有两种形态,验签规则相同(所有非 null 字段参与签名):

  • 基本形态:字段与成功通知相同,仅 status="2"、realAmount="0.00"。
  • 扩展形态:另含 eventId(事件唯一标识,可用于去重)、eventType="PAYIN_FAILED"、paymentStatus="FAILED"、isFinal="true"、failureCode(PAYMENT_DECLINED、PAYMENT_RISK_REJECTED 或 PAYMENT_FAILED)与 failureReason(英文说明,仅供展示)。
{"amount":"100.00","currency":"USD","eventId":"EVENT_ID","eventType":"PAYIN_FAILED","failureCode":"PAYMENT_DECLINED","failureReason":"Payment declined","isFinal":"true","merchantOrderNo":"DEMO_IN_20260912_001","orderNo":"PLATFORM_ORDER_NO","paymentStatus":"FAILED","product":"YOUR_PAYIN_PRODUCT","realAmount":"0.00","status":"2"}

收到失败通知时:验签并核对订单归属后,把订单置为失败、不入账,返回 SUCCESS;不要按 failureReason 文本做程序判断。已确认成功的订单若再收到矛盾的失败通知,进入人工核对,不要冲正。

USDT 代收成功示例(有链上交易哈希时追加 txHash,并参与签名;未知的新字段同样参与验签):

{"currency":"USDT","merchantOrderNo":"DEMO_USDT_20261001_001","orderNo":"PLATFORM_ORDER_NO","product":"USDT-TRON","amount":"12.3456","realAmount":"12.3456","status":"1","txHash":"CHAIN_TRANSACTION_HASH"}

验签与入账顺序

  1. 按不区分大小写的 HTTP 头名读取四个签名头,核对 appId 属于接收方应用。
  2. 取通知体所有非 null字段,加上头部 appId、timestamp、nonce,按请求签名同一排序方式计算 SHA-256。不要把 sign 本身加入;未知的新字段也应参与计算。
  3. 用恒定时间比较校验签名。核对时间戳;建议允许不超过 5 分钟的时钟偏差并同步服务器时间。重试通知会重新生成签名头。
  4. 核对商户订单号、平台订单号、币种、产品,确认 amount 等于本地原订单金额。代收成功以 realAmount 作为实际收款依据,允许其与 amount 不同;验签、归属、金额合法性或已入账金额存在矛盾时进入人工核对,不自动重复记账。
  5. 在商户数据库事务中持久化通知和状态,以“应用+业务类型+商户订单号”的唯一约束/行锁保证同一笔只入账一次。
  6. 数据提交成功后,返回 HTTP 2xx,响应体为纯文本 SUCCESS。重复通知验签并确认已处理后,也返回 SUCCESS。

响应不能包在 JSON 或 HTML 中,不附加换行或空格。当前兼容纯文本 OK 或 SUCCESS,大小写不敏感;统一使用 SUCCESS 最稳妥。失败或未能持久化时不要提前确认成功。

实际金额不同的成功通知

以下 BDT 仅用于说明金额语义;该币种目前没有完整生产交易配置,不能据此下单。

以下业务体仍使用上文签名头和验签规则,不能仅凭 JSON 内容入账:

{"currency":"BDT","merchantOrderNo":"DEMO_BD_001","orderNo":"PLATFORM_ORDER_NO","product":"YOUR_BDT_PAYIN_PRODUCT","amount":"100.00","realAmount":"95.00","status":"1"}

查单成功时对应 payStatus=1,amount=100.00、realAmount=95.00,语义与通知一致。通知使用 status,查单使用 payStatus,不要混淆字段。同一订单的查询与通知应共用一个事务幂等入账记录,不分别入账。

重试

常规通知任务每笔最多投递 5 次(含首次),未收到有效 ACK 时按分钟级递增间隔重试(间隔约 5、10、30、60 分钟),实际执行时间受队列及网络影响,不应依赖固定送达时刻。超过次数后不再自动重试,可联系平台人工重发;人工重发、沙箱 resend 都可能带来额外通知。每次投递都会重新生成 timestamp、nonce 和 sign,不能仅用 nonce 去重,应按订单(或扩展失败通知的 eventId)幂等处理。

单次投递的规则:

  • 目标:可公开访问的 http:// 或 https:// 地址,推荐 HTTPS;不得含用户名/密码或 # 片段。平台代码不限制端口,但出口网络可能只放行常用端口,建议使用 443。内网、回环、链路本地、保留地址会被拦截,不能将 localhost 作为通知地址。沙箱更严格:只允许 80 / 443 端口,解析到非公网地址的通知直接判失败、不再重试,并有每商户 / 每目标主机每分钟上限与连续失败熔断,规则与投递记录查询见沙箱测试指南「回调规则」。
  • 来源 IP:回调来源 IP 按环境不同:沙箱 3.109.43.0(固定);生产 IP 在开通通知中提供。接收端如有入站白名单,请按环境加入对应地址。
  • 不跟随重定向:返回 3xx 视为投递失败,请直接配置最终地址。
  • 超时:连接约 5 秒,整个请求约 10 秒;请先持久化再快速返回,耗时处理放到异步任务。
  • ACK:HTTP 2xx 且响应体恰好为 SUCCESS 或 OK(大小写不敏感,不 trim:前后不能有空格或换行);响应体超过 64 KB 也视为失败。

若未配置本单或默认通知地址,平台不会发送通知,应先补齐配置。

11. 错误码与处理

code / 情况含义建议
0接口操作成功继续按支付状态判断
400签名、时间戳、nonce或输入不合法等(HTTP 200、JSON code=400;代收接口字段超长或 URL 非法时 msg 形如「请求参数不正确:merchantOrderNo too long」;签名类 msg 见第 3 节;代付类接口 msg 统一改写,见下文「代付下单的拒绝与 msg」)看 msg,校时并检查必填字段;不要盲重试下单
404 / 405请求路径不存在 / 请求方法不正确(五个接口都只接受 POST)核对 {GATEWAY} 与第 2 节路径、使用 POST
409启用业务幂等的产品:同业务单号的请求参数与原单不一致;收款人接口:身份、版本冲突或已被出款使用(Beneficiary request conflicts with existing state),或创建/更新结果未确认(Beneficiary not confirmed; query the original payeeId. Do not recreate.)查原单或原 payeeId,不改参数重复提交,不换号重建
500系统异常(HTTP 200、JSON code=500,msg 多为「系统异常」):例如请求体无法按字段类型解析(如把 cardExtra 写成 JSON 对象或数组)、签名校验服务暂时不可用(Signature verification temporarily unavailable)。代付接口的 500 msg 为 Payout request not confirmed; query original order,含义见下文「代付下单的拒绝与 msg」按结果不确定处理:保留原单号查单,不要换单号重付;修正请求格式后再处理。代付请先查询余额与原单
900并发重复请求:两个请求同时使用同一 nonce(Request repeated)。已验签过的 nonce 在 60 秒内再次使用返回 400 nonce has been used(第 3 节)每次请求使用新的 nonce、timestamp、sign
999功能未实现:本单路由到的支付通道不支持该操作(平台配置问题,仅代收下单可能返回);订单可能已创建,但未提交支付通道用原 merchantOrderNo 查单并联系平台;不要换单号重付
9999系统异常(An error has occurred. Please try again later.)。当前部分下单参数不合规也可能返回 9999:请求已通过通用校验(400、10006、10012、10021 等不会以 9999 返回),但在产品自身的校验中不合规。例如 AUD-VKDPWMRT 的 cardExtra 缺失或格式不对;clientIp 缺失(不传、空串、全空白、键名错误);payType 未传或不是 CARD;phone/email 非空但格式不符;returnUrl 缺失或不是符合要求的 HTTPS;金额不在 1–500 或不是整数/.99。平台正在改为具体业务码不要按 msg 字面「稍后再试」直接重发,也不要换单号重付;按下文「9999 自查清单」处理
10000应用不存在核对 appId,勿填商户号
10001应用不可用联系平台核对应用状态
10002币种不可用确认币种开通
10003商户不可用核对商户状态
10004产品未开通或协议过期同码可能有不同原因,结合 msg 核对签约
10005无匹配渠道核对产品路由、通道状态、金额范围
10006金额不允许(Amount not allowed:超出路由金额范围或币种精度;代收低于路由最低金额时 msg 形如 The minimum payable amount is 500.00.;含代付金额低于最低金额(通道下限与签约下限中的较高者),代付接口 msg 为 Payout request rejected)以实际产品/路由范围、代付最低金额(第 4 节)和币种精度为准(第 4 节),不能只依赖英文提示
10007账户不可用核对币种账户
10008可用余额不足查询可用与冻结余额,预留手续费
10009通道暂不可用原单查单;不要自动换单重付
10010来源 IP 不在白名单提供真实服务器公网出口 IP(沙箱默认不校验,仅开启「模拟生产白名单」后出现)
10011产品无效核对代收/代付产品编码
10012支付方式无效(payType 与币种不匹配,或传了空字符串)对照第 6 节「支付方式编码」表,或省略 payType
10013通道尚未接入:产品已配置但通道尚未接入,订单未创建视为该产品暂不可用,不要重试;联系平台确认开放时间
10020商户订单号重复:同一应用下该 merchantOrderNo 已存在(无论参数是否相同,第 4 节)查询原单,不生成新号重付
10021付款人 IP 不合规:clientIp 非空白但不是合法的 IPv4/IPv6 文本(含超过 45 个字符);或部分要求必填的产品(如印度原生 UPI)缺少可用的付款人 IP。注意:AUD-VKDPWMRT 缺失 clientIp(不传、null、空字符串、全空白、键名写错)当前返回 9999,不是 10021填真实付款人公网 IPv4/IPv6 字面量,键名写作 clientIp
10022代收准入未通过联系平台确认当前准入规则
10023 / 10024代收 / 代付费率配置不完整联系平台确认签约费用
30001订单未找到或不可访问核对 appId 及订单号。代付下单返回 500 后原单号持续查单 30001,表示该笔未建单(见下文「代付下单的拒绝与 msg」);其他未知代付结果须人工核对
30002币种参数无效或账户未开通同码多义,结合 msg 核对
48001仅沙箱:模拟订单当前状态不允许手动终态或重发(Sandbox order state does not allow this operation)先查询模拟单状态,只对可手动场景操作
47001 / 47014 / 47015交易条款未配置 / 条款冲突 / 条款不支持(平台侧签约条款配置问题,仅在平台为商户启用新结算条款后可能由代收下单返回);订单未创建不要重试;联系平台核对签约条款
429 / 限流请求过快:查询接口按 appId 每秒超过 5 次(当前为 HTTP 200、JSON code=429,msg 形如 Query limit 5 times in 1s)降低频率,使用退避
HTTP 5xx、超时、非 JSON结果不确定保存原单号并查单,禁止盲目重复付款

错误表为常见交易错误,不包含平台内部管理接口。不要依赖返回的英文文本完全一致。

代付下单的拒绝与 msg

代付类接口(代付下单、代付查单、余额查询、收款人接口)为避免回显收款人资料,会改写错误 msg。下单被拒时按下表判断订单是否已创建:

自 平台代付参数校验新版本上线(上线时间以平台通知为准) 起,代付请求参数校验失败同步返回、不建单:HTTP 状态 仍为 200(与所有商户接口一致,结果看响应体),JSON code=400,msg 格式 Invalid payout request: <field> <rule>[; <field> <rule>...]——<field> 为本接口字段名,<rule> 为违反的规则(规则中的数字是平台或通道配置的上下限),不回显字段值。适用范围:所有币种的代付下单 POST /transaction/payout/v1/apply(商户后台代付相同);THB 代付另加 16.4 的付款通道字段规则。多个字段同时出错时全部列出,用 ; 分隔,通用字段按字段名字母序,THB 字段按 bizCode、branchCode、account、accountName、phone、email、amount 顺序;同一字段只报一条。

校验项msg(<field> <rule> 部分)
必填字段缺失或为空(merchantOrderNo、amount、currency、product、accountName、account、phone、email、payCode)<field> required(如 email required、payCode required);amount 不大于 0 时为 amount must be greater than 0
字段超长(merchantOrderNo > 255、product > 20、bankName > 255)merchantOrderNo too long (max 255)、product too long (max 20)、bankName too long (max 255)
bizCode / branchCode 不满足免填条件(第 7 节)bizCode required、branchCode required
THB:bizCode 不是 BANKbizCode must be BANK
THB:branchCode 不在 16.1 表branchCode not supported (allowed: BAY, BBL, ...),allowed 按字母序列出当前可用银行
THB:branchCode 不在开通通知列出的可用银行内同上:branchCode not supported (allowed: ...),allowed 只含开通通知列出的可用银行(多个付款通道时取交集)
THB:account 不是 6–20 位数字account must be 6-20 digits
THB:accountName 含不允许的字符或超过开通通知的长度上限accountName required、accountName too long (max 10)(上限为通道配置,默认 10)、accountName invalid characters (letters, spaces and . ' - only, starting with a letter)
THB:phone 格式不符phone required、phone must be 6-15 digits with an optional leading +
THB:email 格式不符或超长email required、email too long (max 64)、email invalid format(部分付款通道要求,按交集执行,请始终按 16.4 填写)
THB:amount 超出付款通道单笔范围amount out of range (500.00-49999.00)(范围为通道配置)
情况返回订单处理
上表参数校验失败code=400,msg Invalid payout request: <field> <rule>确定未创建,未冻结资金,merchantOrderNo 未被占用按 msg 指出的字段修正后重新提交(可沿用原 merchantOrderNo,也可用新单号)
请求体不是 JSON 对象或字段类型错误(如 amount 不是数字)code=400,msg Invalid payout request: body must be a JSON object with correctly typed fields未创建修正请求格式后重提
THB:本次可能路由到的付款通道未开通或配置不完整10005,msg Payout request rejected未创建联系平台
业务规则拒绝:10004、10005、10006、10008、10010、10011、10013、10020 等对应业务码,msg 仍为 Payout request rejected未创建按第 11 节错误表处理
平台内部异常(数据库、提交阶段异常、超时等),以及缺少签名请求头或 Content-Type 不是 application/json业务码 500,msg Payout request not confirmed; query original order可能已建单先补齐请求头;保留原单号查单,查到订单按查单结果处理,持续 30001 时联系平台确认后再处理,不要直接换单号重提
超时、断线、HTTP 5xx、非 JSON—不确定同第 12 节,只查原单

说明:code=400 表示本次请求未建单;同号旧单可能已存在(重复单号仍按 10020),返回 500 时须先用原单号查单。THB 代付的金额精度与最低金额仍按原规则返回 10006(在 THB 字段规则之后检查)。已启用业务幂等的产品,同单号同参数重放直接返回原订单、不再校验;其他重复单号仍返回 10020。批量代付和平台人工改派不经过同步校验,仍可能以失败终态结束。以前参数错误的 msg 固定为 Invalid payout request,现在其后追加 : <详情>:按 code 或该前缀判断的客户端不受影响,按整串相等判断的请改为前缀匹配。上游付款通道的处理结果仍为异步,超时等未知结果按 16.4 「超时不等于失败」处理,不会变成 400。

9999 自查清单

收到 9999 时:

  1. 先用原 merchantOrderNo 查单(第 8 节),不要换单号重付。查单返回 30001(持续查无)说明本次未建单;返回 payStatus=0 说明订单已创建。对下面清单中的参数问题,平台在提交支付通道之前就会取消该订单,不会生成支付链接(9999 响应中也没有 payUrl),付款人无法对该单付款;查单接口目前不区分“已取消”与“待支付”,两者都显示 payStatus=0。
  2. 按下表逐项核对请求。下表只列通过通用校验后才会检查的项目;不满足通用校验的请求返回 400、10006、10012、10021 等原有业务码,不会是 9999(以 AUD-VKDPWMRT 为例,格式详见第 6 节「澳洲银行卡(AUD-VKDPWMRT)」)。
  3. 确认属于清单中的参数问题并修正后,如需重新下单,使用新的 merchantOrderNo:原单号已被占用,用同一单号、同样参数再次提交可能返回 code=0 但不含可用 payUrl 的原单受理结果,参数改动后再提交返回 409(第 4 节)。
  4. 清单全部核对无误仍收到 9999,或无法确定原因时,按第 6 节「下单结果不确定时」处理:保留原单号、联系平台核对原单,不要自行换单号重付。
自查项合规要求
cardExtra 是否存在且为字符串必填;值是序列化后的 JSON 文本,不是嵌套对象或数组(写成对象或数组可能返回 500)
cardExtra 顶层键恰好 connection_info、account_info 两个对象,无其他键
cardExtra 内部键与值只用第 6 节表中的键,必填键齐全;country="AU"、state 为 8 个州/领地缩写之一、zip_code 4 位数字、area_code="61"、role 为 GUEST 或 PRIVATE;create_time 为 JSON 整数毫秒时间戳且不晚于当前时间;名/姓只含英文字母、空格、'、-
cardExtra 内容限制无空值、无控制字符、无卡号/CVV 字样或疑似卡号;总长不超过 8192 字节
clientIp键名精确为 clientIp;值不是空串或全空白,是真实付款人 IP 字面量(IPv4 直接写点分形式);放在请求体中
payType显式传 CARD
phone5–15 位纯数字,不带 +、空格、横线、国家码
email形如 payer@example.com,不超过 254 个字符
returnUrl必填,https://,主机名含点且非 localhost,端口省略或 443,不超过 512 个字符
金额1–500 AUD,整数或 .99 结尾(如 "20"、"20.00"、"19.99")
用户身份绑定同一 merchant_user_id 始终对应同一 email 和 phone,email、phone 也未被其他 merchant_user_id 使用

16.5 THB 错误码速查

情况返回处理
缺少 name、phone、email 等必填字段,或传空字符串400:代收 msg 形如「请求参数不正确:email invalid」;代付 msg 见第 11 节「代付下单的拒绝与 msg」补齐字段后用新单号下单
金额超出单笔范围或签约路由范围、超过两位小数10006按 16.2 修正金额;不要只依赖 msg
THB 未开通、产品未签约10002 / 10004 / 10011核对开通通知与签约产品
没有可用的 THB 路由10005联系平台
代收传了 payType 空字符串或与币种不匹配的编码10012省略 payType
代收本节字段不合规(cardExtra、户名、手机号、邮箱、returnUrl、单笔范围)9999(订单未提交)按 16.3 自查清单修正,用新单号下单
代收结果未知9999(订单处理中)或 HTTP 5xx/超时原单查单,不要重下
代收付款通道明确未受理10009不要重试原单,联系平台
代付可用余额不足(含手续费)10008查询 THB 余额后再处理
代付来源 IP 不在白名单10010提供真实服务器公网出口 IP
代付本节字段不合规参数校验错误(见第 11 节「代付下单的拒绝与 msg」),本次请求未建单按 msg 修正后重提(可沿用原单号)
THB 付款通道未开通或配置不完整10005联系平台
代付 500结果未知,可能已建单原单查单,不要换单号重付
代付结果未知payStatus=0 持续等待平台核对,不要重复代付

其他错误码含义见第 11 节。

12. 重复请求、超时和对账

代付超时是结果未知,不是付款失败。 商户请求超时、HTTP 5xx、断线、非 JSON,或上游超时后平台仍返回处理中时,下游应保留待查状态。已受理订单在未确认终态前保留相应资金占用,不应因等待时间长就退款、解冻、重发或改走其他渠道。

  1. 保存原 merchantOrderNo、已取得的 orderNo、请求金额和时间,使用原订单标识查单。每次查询生成新的签名头。
  2. payStatus=0 表示仍待查;按退避间隔查询,等待验签通过的终态通知,超过内部跟踪时限转人工核对。
  3. 一次“查无此单”(例如 30001)不能证明上游没有受理;先确认 appId 和订单号,持续核查或联系平台,禁止立即换号重发。
  4. payStatus=1 确认成功,停止重发;仅在原单明确终态失败并完成资金核对后,才可按新的业务审批另建新单。不能对失败单或未知单使用原商户订单号重新提交。
  5. 重复通知和查询结果共用同一幂等处理流程;后到的处理中或超时结果不能覆盖已经确认的成功状态。
创建本地业务订单 → 持久化商户单号 → 提交平台
    ├─ 受理成功 → 保存平台单号 → 等回调 / 低频查单
    ├─ 超时或未知 → 保留同一商户单号 → 查单 / 人工核对
    └─ 明确参数拒绝 → 修正配置;确认原单未执行后再处理

回调验签 → 校验归属/金额 → 数据库事务幂等更新 → 返回 SUCCESS

商户至少保存:appId、业务类型、商户单号、平台单号、币种、订单金额、实际金额、状态、请求/回调时间及验签结果。日志不要记录 appSecret、完整银行账户或包含密钥的待签名串。

每日核对本地订单与平台订单,分别核对代收实际到账、代付金额及签约费用。差异单、未决单、冻结金额单独跟踪。历史记录不能因停用或删除商户而丢失;资金未处理完成时不应直接清账删除。

13. 联调与上线清单

  1. 使用平台分配的应用和产品,先运行示例默认的余额查询,验证网络、时间戳及签名。
  2. 校验必填手机号、邮箱等信息。使用受控的小额业务,金额仍需符合产品/接口最低要求。
  3. 验证代收创建、付款、查单、成功回调、重复回调幂等,以及不正确签名被拒绝。
  4. 单独验证代付来源 IP、余额及费用、受理/成功/失败/未知状态;生产代付测试须明确收款账户和资金用途。
  5. 验证通知失败后的重试、服务重启后的订单恢复,以及对账差异处理。
  6. 对需要 cardExtra 等扩展信息的产品,逐项核对产品目录「说明」和第 6 节;托管收银台还要验证付款后未跳回、链接过期和下单结果不确定时的处理。
  7. USDT 代收开放后,验证 paymentInfo 展示、地址过期、4 位小数金额、含 txHash 的通知验签,以及按 realAmount 入账。
  8. THB 代收或代付开通后,按第 16.6 节补充检查。
  9. 只有完成以上验收,才能把“接口可以访问”提升为“业务链路已验证”。

下载 OpenAPI 描述 · Python 签名与验签示例 · Node.js 签名与验签示例

14. 查询状态扩展与沙箱自测

查询返回 paymentStatus、isFinal 和可选 failureReason(代收另有可选 failureCode,见第 8 节);原 payStatus 的值和含义不变。failureReason 仅供展示和排查,可能是大写代码(如 PAYOUT_FAILED)也可能是英文短句,不要据此做程序判断。客户端应忽略未知响应字段,金额用Decimal解析;这次不改变请求或回调签名规则。下单返回code=0只表示受理。

paymentStatusisFinal含义
CREATEDfalse已创建,未确认支付结果
PROCESSINGfalse处理中
PENDING_CONFIRMATIONfalse代收金额等信息待核对,不自动入账
SUCCEEDEDtrue已确认成功,仍需核对订单、币种和realAmount
CANCELLEDfalse平台侧已取消。一般情况下本地取消不能证明上游未扣款,failureReason=CANCELLATION_NOT_PAYMENT_PROOF,保留待核对;例外:下单时返回 9999、且订单在提交付款通道前就因参数不合规被取消(如 THB 代收,见 16.3),此时付款人无法付款,可修正后用新单号下单
FAILEDtrue明确失败:代付 failureReason=PAYOUT_FAILED;代收在通道明确确认失败时给出(沙箱为 SANDBOX_SIMULATED_FAILURE)
UNKNOWNfalse未知状态,保留待核对,不自动重付

代收旧payStatus成功为1,部分通道明确失败为2,其余为0(包括部分 FAILED 订单,请以 paymentStatus/isFinal 为准);代付成功1、失败2、其他0。不要把所有payStatus=0判为失败,也不要将所有取消判为支付最终失败。代收失败通知只在部分通道发送(第 10 节「代收失败通知」)。沙箱100.01失败场景可通过FAILED/isFinal=true与100.02持续处理区分;正式渠道未确认失败仍保留待核对状态。

生产与沙箱共用本开发文档和签名示例。沙箱测试指南、商户后台沙箱说明从同一份版本化契约生成。沙箱产品和余额独立,不代表正式产品开通;代付金额范围以指南的环境差异说明为准。

下载可运行沙箱工具:余额、服务器出口IP、下单、查单、回调验签、SQLite幂等入账演示、本地重复通知测试和结果报告。按指南配置独立沙箱凭据与自己的公网HTTPS通知地址;不使用生产密钥、不连接真实钱包。

15. AUD Google Pay 与 Apple Pay 完整请求示例

本节用于已签约这两种 AUD 钱包产品的商户。沿用当前应用的 appId/appSecret;应用必须已绑定对应产品。产品编码中的字符属于完整编码,请原样传递。本文示例不会替商户开通产品,也不代表所有商户都已开通。

支付方式productpayType
Google PayAUD-PAYPLUS-GOOGLE-M85GOOGLE_PAY
Apple PayAUD-PAYPLUS-APPLE-M85APPLE_PAY

正式接口:POST https://transaction.hisspay.com/transaction/payin/v1/apply,Content-Type 为 application/json。请求头需 appId、timestamp、nonce、sign。timestamp 为当前13位毫秒时间戳,允许时间差30秒;nonce 每次重新生成且至少10字符。

金额为1–500 AUD,目前仅整数或 .99,例如1.00、1.99、19.99。示例金额使用字符串,避免签名时浮点格式变化。具体商户费率与结算周期以签约协议为准。

必须替换示例中的姓名、邮箱、电话、真实付款人公网IP、客户ID、注册时间、州、邮编、订单号及回调/跳转URL。clientIp不是商户服务器IP。澳大利亚资料country=AU、area_code=61,州为NSW/VIC/QLD/ACT/NT/SA/TAS/WA,邮编四位;电话仅数字。create_time为客户真实注册时间的13位毫秒整数,不晚于当前时间;注册用户role=PRIVATE,游客GUEST。

cardExtra 是 JSON 字符串,不是嵌套对象;只序列化一次,签名后不重新格式化。不要传银行卡号、CVV或钱包密码。姓名、邮箱、电话通过顶层字段传递,cardExtra.account_info中不要重复添加email/phone。

Google Pay 完整请求体

下载 Google Pay JSON

{
  "merchantOrderNo": "WALLET_GOOGLE_REPLACE_UNIQUE",
  "amount": "1.00",
  "currency": "AUD",
  "product": "AUD-PAYPLUS-GOOGLE-M85",
  "payType": "GOOGLE_PAY",
  "name": "John Smith",
  "phone": "412345678",
  "email": "john@example.com",
  "clientIp": "<PAYER_PUBLIC_IP>",
  "notifyUrl": "https://your-domain.com/payment/notify",
  "returnUrl": "https://your-domain.com/payment/result",
  "cardExtra": "{\"connection_info\":{\"country\":\"AU\",\"state\":\"NSW\",\"zip_code\":\"2000\",\"media_source\":\"website\"},\"account_info\":{\"merchant_user_id\":\"customer_10001\",\"create_time\":1790812800000,\"role\":\"PRIVATE\",\"area_code\":\"61\",\"first_name\":\"John\",\"last_name\":\"Smith\"}}"
}

Apple Pay 完整请求体

下载 Apple Pay JSON

{
  "merchantOrderNo": "WALLET_APPLE_REPLACE_UNIQUE",
  "amount": "1.00",
  "currency": "AUD",
  "product": "AUD-PAYPLUS-APPLE-M85",
  "payType": "APPLE_PAY",
  "name": "John Smith",
  "phone": "412345678",
  "email": "john@example.com",
  "clientIp": "<PAYER_PUBLIC_IP>",
  "notifyUrl": "https://your-domain.com/payment/notify",
  "returnUrl": "https://your-domain.com/payment/result",
  "cardExtra": "{\"connection_info\":{\"country\":\"AU\",\"state\":\"NSW\",\"zip_code\":\"2000\",\"media_source\":\"website\"},\"account_info\":{\"merchant_user_id\":\"customer_10001\",\"create_time\":1790812800000,\"role\":\"PRIVATE\",\"area_code\":\"61\",\"first_name\":\"John\",\"last_name\":\"Smith\"}}"
}

Python 3 请求示例(标准库,无额外依赖)

下载 Python 示例。先下载任一请求JSON并替换示例资料。密钥从服务端环境变量HISSPAY_APP_ID、HISSPAY_APP_SECRET读取,不填入前端代码或仓库。

默认仅打印请求体,不发送订单:

python3 wallet_request.py google-pay-request.json
python3 wallet_request.py apple-pay-request.json

准备好真实资料与唯一订单号后,选择一种方式发送一次正式请求。--send会创建真实支付订单:

python3 wallet_request.py google-pay-request.json --send
# 或:python3 wallet_request.py apple-pay-request.json --send
#!/usr/bin/env python3
"""Python 3, standard library. Dry run by default; --send creates ONE real order."""
import hashlib
import json
import os
import secrets
import sys
import time
import urllib.request
from pathlib import Path

URL = "https://transaction.hisspay.com/transaction/payin/v1/apply"

def sign(body, app_id, secret, timestamp, nonce):
    headers = {"appId": app_id, "timestamp": timestamp, "nonce": nonce}
    values = {**body, **headers}
    if any(not isinstance(v, str) for v in values.values()):
        raise ValueError("Use string top-level fields; cardExtra must be JSON text")
    canonical = "&".join(k + "=" + values[k] for k in sorted(values))
    headers["sign"] = hashlib.sha256((canonical + secret).encode("utf-8")).hexdigest()
    return headers

class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, *args, **kwargs):
        return None

def main():
    if len(sys.argv) not in (2, 3) or (len(sys.argv) == 3 and sys.argv[2] != "--send"):
        raise SystemExit("Usage: python3 wallet_request.py request.json [--send]")
    body = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
    if len(sys.argv) == 2:
        print(json.dumps(body, ensure_ascii=False, indent=2))
        return
    # Replace ALL example customer data, URLs and order number before --send.
    if body.get("clientIp") == "<PAYER_PUBLIC_IP>" or "REPLACE_UNIQUE" in body.get("merchantOrderNo", ""):
        raise SystemExit("Replace example payer IP and unique order number first")
    headers = sign(body, os.environ["HISSPAY_APP_ID"], os.environ["HISSPAY_APP_SECRET"],
                   str(int(time.time() * 1000)), secrets.token_hex(16))
    headers["Content-Type"] = "application/json"
    request = urllib.request.Request(URL,
        data=json.dumps(body, ensure_ascii=False, separators=(",", ":")).encode("utf-8"),
        headers=headers, method="POST")
    # No automatic application retry or redirects. On timeout, query the original order.
    with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response:
        print(response.read().decode("utf-8"))

if __name__ == "__main__":
    main()

Java 17+ 请求示例(JDK标准库,无额外依赖)

下载 Java 示例 · 下载付款人参数模板。将文件放在同一目录,编辑模板中的全部示例数据;两种钱包分别使用不同的唯一订单号。环境变量HISSPAY_APP_ID、HISSPAY_APP_SECRET与Python一致。

javac WalletRequest.java
# 以下仅打印JSON,不请求网络:
java WalletRequest google wallet-payer.properties
java WalletRequest apple wallet-payer.properties
# 准备好真实资料后,选择一种方式发送一次正式请求:
java WalletRequest google wallet-payer.properties --send
# 或:java WalletRequest apple wallet-payer.properties --send
import java.net.URI;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.security.MessageDigest;
import java.time.Duration;
import java.util.*;

// Java 17+, no external dependencies. Default: print request only.
public class WalletRequest {
    static final String URL = "https://transaction.hisspay.com/transaction/payin/v1/apply";
    static String quote(String s) {
        StringBuilder b = new StringBuilder("\"");
        for (char c : s.toCharArray()) {
            switch (c) {
                case '"': b.append("\\\""); break;
                case '\\': b.append("\\\\"); break;
                case '\n': b.append("\\n"); break;
                case '\r': b.append("\\r"); break;
                case '\t': b.append("\\t"); break;
                default: if (c < 32) b.append(String.format("\\u%04x", (int)c)); else b.append(c);
            }
        }
        return b.append('"').toString();
    }
    static String json(Map<String, ?> values) {
        StringJoiner j = new StringJoiner(",", "{", "}");
        values.forEach((k, v) -> j.add(quote(k) + ":" +
            (v instanceof Map ? json((Map<String, ?>)v) : v instanceof Long ? v.toString() : quote((String)v))));
        return j.toString();
    }
    static String required(Properties p, String k) {
        String v = p.getProperty(k);
        if (v == null || v.isBlank()) throw new IllegalArgumentException("Missing " + k);
        return v;
    }
    static Map<String, String> body(String wallet, Properties p) {
        if (!wallet.equals("google") && !wallet.equals("apple")) throw new IllegalArgumentException("Use google or apple");
        Map<String, Object> connection = new LinkedHashMap<>();
        connection.put("country", "AU");
        connection.put("state", required(p, "state"));
        connection.put("zip_code", required(p, "zip"));
        connection.put("media_source", "website");
        Map<String, Object> account = new LinkedHashMap<>();
        account.put("merchant_user_id", required(p, "userId"));
        account.put("create_time", Long.parseLong(required(p, "created")));
        account.put("role", required(p, "role"));
        account.put("area_code", "61");
        account.put("first_name", required(p, "first"));
        account.put("last_name", required(p, "last"));
        Map<String, Object> context = new LinkedHashMap<>();
        context.put("connection_info", connection); context.put("account_info", account);
        Map<String, String> b = new LinkedHashMap<>();
        for (String k : List.of("merchantOrderNo", "amount", "name", "phone", "email", "clientIp", "notifyUrl", "returnUrl"))
            b.put(k, required(p, k));
        b.put("currency", "AUD");
        b.put("product", wallet.equals("google") ? "AUD-PAYPLUS-GOOGLE-M85" : "AUD-PAYPLUS-APPLE-M85");
        b.put("payType", wallet.equals("google") ? "GOOGLE_PAY" : "APPLE_PAY");
        b.put("cardExtra", json(context)); // String, NOT a nested JSON object.
        return b;
    }
    static Map<String, String> sign(Map<String, String> body, String appId, String secret, String timestamp, String nonce) throws Exception {
        Map<String, String> headers = new LinkedHashMap<>();
        headers.put("appId", appId); headers.put("timestamp", timestamp); headers.put("nonce", nonce);
        TreeMap<String, String> values = new TreeMap<>(body); values.putAll(headers);
        StringJoiner canonical = new StringJoiner("&");
        values.forEach((k, v) -> canonical.add(k + "=" + v));
        byte[] digest = MessageDigest.getInstance("SHA-256").digest((canonical.toString() + secret).getBytes(StandardCharsets.UTF_8));
        headers.put("sign", HexFormat.of().formatHex(digest));
        return headers;
    }
    public static void main(String[] args) throws Exception {
        if (args.length < 2 || args.length > 3 || (args.length == 3 && !args[2].equals("--send")))
            throw new IllegalArgumentException("Usage: java WalletRequest google|apple payer.properties [--send]");
        Properties p = new Properties();
        try (var reader = Files.newBufferedReader(Path.of(args[1]), StandardCharsets.UTF_8)) { p.load(reader); }
        Map<String, String> b = body(args[0], p);
        String payload = json(b);
        if (args.length == 2) { System.out.println(payload); return; }
        if (b.get("clientIp").equals("<PAYER_PUBLIC_IP>") || b.get("merchantOrderNo").contains("REPLACE_UNIQUE"))
            throw new IllegalArgumentException("Replace example payer IP and unique order number first");
        String appId = Objects.requireNonNull(System.getenv("HISSPAY_APP_ID"), "HISSPAY_APP_ID");
        String secret = Objects.requireNonNull(System.getenv("HISSPAY_APP_SECRET"), "HISSPAY_APP_SECRET");
        Map<String, String> headers = sign(b, appId, secret, Long.toString(System.currentTimeMillis()), UUID.randomUUID().toString().replace("-", ""));
        HttpRequest.Builder req = HttpRequest.newBuilder(URI.create(URL)).timeout(Duration.ofSeconds(30))
            .header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(payload, StandardCharsets.UTF_8));
        headers.forEach(req::header);
        HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).followRedirects(HttpClient.Redirect.NEVER).build();
        // Send once. On timeout/error, query the original order; do not automatically resubmit.
        HttpResponse<String> response = client.send(req.build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
        System.out.println("HTTP " + response.statusCode()); System.out.println(response.body());
    }
}

签名与结果处理

两个示例都将请求体字段与appId、timestamp、nonce合并,按字段名升序拼接key=value,以&连接,末尾直接追加appSecret,不加分隔符、不做URL编码;UTF-8 SHA-256输出小写十六进制。cardExtra使用原字符串值参与签名,而不是外层JSON转义后的文本。

下单响应code=0且data.payUrl有效时,打开data.payUrl托管收银台,不使用iframe。下单受理不等于付款成功,returnUrl仅用于页面跳转;最终按服务端通知或查单确认。按第10节验证下游通知签名、订单号、金额和币种,再幂等入账。

超时、网络断开或结果不确定时保留原merchantOrderNo,先查询原单,不换单号重复下单。查询接口为POST /transaction/payin/v1/query,请求体例如 {"merchantOrderNo":"原商户订单号"},使用同样签名规则和新的timestamp、nonce。成功创建订单也不能证明真实钱包付款与入账验收完成。

16. 泰国(THB)代收与代付

开通状态(2026-10-27):THB 代收(PromptPay 扫码)已按商户逐个开通,收到开通通知(含产品编码)后即可接入,产品编码见第 1 节目录;THB 代付需单独开通,以开通通知为准,未收到开通通知前不要调用 THB 代付(未开通时下单会被拒绝)。

本节是 THB 代收、代付在本接口上的统一接入要求:平台为您开通的所有 THB 代收产品使用同一套字段规则,所有 THB 代付产品也一样,平台调整或增加付款通道时您不需要改代码。本节不表示该产品已向您的应用开放:产品编码、单笔金额范围、费率、结算周期以及可用银行以平台开通通知为准,未开通前不要下单。签名、请求头、nonce、通用字段、查单、余额和通知验签规则不变,见第 3–5 节、第 8–10 节和第 14 节。下文示例中的姓名、账号、手机号和域名均为虚构值。

16.1 银行编码

THB 代收的 cardExtra.payerBankCode 与 THB 代付的 branchCode 使用同一套编码,只能取下表的值(区分大小写,不加前缀或后缀)。表外的值或其他写法都会被拒绝。

银行编码银行代收代付
SCBSiam Commercial Bank(汇商银行)支持支持
KBANKKasikornbank(开泰银行)支持支持
KTBKrungthai Bank(泰京银行)支持支持
BAYBank of Ayudhya / Krungsri(大城银行)支持支持
GSBGovernment Savings Bank(政府储蓄银行)支持支持
TTBTMBThanachart Bank(TTB 银行)支持支持
BBLBangkok Bank(盘谷银行)不支持支持

代收付款银行只能是表中「代收」为「支持」的 6 家。代付实际可用的收款银行按付款通道配置,以开通通知列出的为准:平台只对已与付款通道逐家确认的银行出款,可能少于 7 家;通道未确认任何银行时代付不可用。使用未列出的银行编码时不会付款(返回形式见 16.4)。

16.2 金额、范围与费用

  • currency 固定为 THB,订单币种必须与签约的 THB 产品一致。
  • amount 为泰铢主币种金额,必须大于 0,最多两位小数,如 "1500"、"1500.00"、"1500.50"。超过两位小数返回 10006。
  • 单笔金额范围:代收与代付默认均为 500.00–49999.00 THB(含两端)。开通通知给出更窄的范围时以通知为准。超出签约路由范围的请求同步返回 10006:代收 msg 形如 The minimum payable amount is 500.00.(即使是超过上限也可能显示这条最低金额文案,不要依赖 msg 判断上下限);代付 msg 统一为 Payout request rejected(第 11 节)。平台在提交付款通道前还会再核对一次通道的单笔范围:代收不满足时返回 9999 且订单不会提交(见 16.3),代付不满足时的返回形式见 16.4。
  • 平台按两位小数精确核对金额:付款金额或付款通道确认金额与订单金额不一致的订单,不会自动入账或出款,保留待人工核对(查单 paymentStatus 为 PENDING_CONFIRMATION 或保持处理中)。THB 代收成功时 realAmount 等于 amount(沙箱尾数 .06 场景故意返回不同的 realAmount,用于演练第 4 节的差额处理,生产 THB 不会出现)。
  • 代收费用:realAmount 是扣费前的实际收款金额;商户 THB 账户的结算净额按您签约的 THB 代收费率与固定费用计算(第 4 节「实际到账金额规则」)。
  • 代付费用:收款人应收金额就是请求中的 amount,手续费不从 amount 中扣减。受理时平台从您的 THB 可用余额中占用 amount + amount × 代付费率(向上保留 4 位小数)+ 单笔代付费用,费率与单笔费用以您的 THB 代付签约为准;成功后按此扣款,失败按账务规则释放。可用余额不足时返回 10008,下单前请用第 9 节查询 THB 可用余额并预留手续费。

16.6 THB 余额、联调与上线检查

  • 余额查询使用第 9 节接口,传 {"currency":"THB"};返回的是商户在平台的 THB 账户余额。
  • 沙箱提供 THB 代收与代付模拟产品,字段校验按本节统一契约(代付户名上限、可用银行及不合规时的返回形式与生产当前默认一致,见沙箱指南),按金额尾数模拟成功、失败、处理中、超时、重复通知等场景,详见沙箱测试指南「泰国 THB 模拟」。沙箱模拟不连接银行,不产生真实付款。
  • 上线前按第 13 节清单验证,并额外确认:代收 cardExtra 字符串与签名一致、户名与付款账号一致、16.1 编码映射正确、不传 payType;代付金额、手续费与可用余额核对正确,使用真实收款账户的小额测试并确认成功与失败两种通知的处理;代付超时或长期处理中时不重复出款。

拿到密钥,开始构建

在线开户即可获得测试凭证与产品编码,沙盒跑通后一键切生产。

服务与费用说明

HissPay 提供支付接入、订单管理、通知与对账等技术服务。支付处理及资金清算、结算由签约的持牌支付机构负责;HissPay 不接收、持有或经手交易资金。

展示费率由持牌支付机构的支付处理费用与 HissPay 技术服务费构成,并非全部由 HissPay 收取。两部分费用、计费方式及适用条件以商户签署的协议和费用清单为准。