1. 商户入网
星驿支付文档中心
  • AI快速对接
    • xypay-skills使用说明
  • 文档说明
    • 阅读对象
    • 版本说明
  • 术语
    • 支付模式
    • 名词解释
    • 支付产品
      • 付款码支付
      • 聚合码支付
      • PC支付
      • 小程序支付
        • 支付宝小程序支付
        • 微信小程序支付
      • APP支付
        • 微信支付
        • 支付宝支付
      • H5支付
        • 微信H5支付
        • 支付宝H5支付
        • 云闪付H5支付
        • 手机浏览器H5支付
      • Native支付
        • 支付宝支付
        • 云闪付支付
      • 终端支付
        • 智能云MIS
        • 智能APP
  • 接口规则
    • 协议规则
    • 常见问题
    • 安全规范
  • 支付交易
    • 交易前指引
      • 微信认证操作流程
      • 支付宝认证操作流程
      • H5页面微信支付对接前准备
      • H5页面支付宝支付对接前准备
      • 支付流程
      • 支付接入注意事项
      • 消费者IP获取指引
      • 微信小程序资金管控操作指南
    • 基础支付
      • 付款码支付
      • JSAPI支付
      • 订单查询
      • 扫码支付-星驿码
      • 扫码支付-官方码
      • 扫码支付-场景码
      • 关闭订单
      • 撤销订单
      • 退款
      • 退款查询
      • 授权码查询openid
      • 获取微信刷脸凭证
      • 获取银联用户标识
      • 风控ip检查
    • 半屏小程序支付
      • 使用说明
      • 小程序半屏-星驿付
      • 小程序半屏-场景
    • 扫码预授权
      • 扫码预授权
      • 预授权查询
      • 预授权撤销
      • 预授权撤销查询
      • 预授权完成
      • 预授权完成查询
      • 预授权完成撤销
      • 预授权完成撤销查询
    • 订单推送
      • 推送终端交易
      • 关闭推送终端交易
      • 碰一下推单状态查询
      • 碰一下订单取消
      • 碰一下订单推送
    • 智能终端SDK
      • 智能终端SDK
    • 交易通知及对账
      • 交易对账文件-场景应用
      • 交易对账文件-ISV
      • 交易和退款结果通知
      • 交易手续费通知
      • 后返对账文件-ISV
    • 刷卡预授权
      • 预授权完成撤销
      • 预授权撤销
    • 行业开票
      • 开票申请
      • 发票冲红
      • 发票结果查询
      • 发票结果通知
  • 商户管理
    • 进件前指引
      • 进件说明
      • 图片示例
      • 微信认证操作流程
      • 支付宝认证操作流程
      • 附件下载
    • 商户入网
      • 商户进件上传图片
        POST
      • 普通商户进件
        POST
      • 普通商户信息修改
        POST
      • 小微商户进件
        POST
      • 小微商户信息修改
        POST
      • 审核结果查询
        POST
      • 商户审核结果通知
        POST
      • 待审核商户撤回
        POST
      • 商户信息查询
        POST
      • 结算卡修改
        POST
      • 商户快捷修改
        POST
      • 受益人信息查询
        POST
      • 商户报备查询
        POST
      • 商户报备结果通知
        POST
      • 商户状态修改
        POST
      • 终端报备查询
        POST
      • 商户阶梯费率配置
        POST
      • 商户阶梯费率查询
        POST
    • 商户协议签约
      • 入网协议签约接口调用流程
      • 普通商户用户开户
      • 小微商户用户开户
      • 发短信验证码
      • 获取签约链接
      • 校验验证码
      • 校验验证码-补签
      • 签约结果通知
    • 微信支付宝认证
      • 微信申请单提交
      • 微信申请单撤销
      • 微信申请单状态查询
      • 微信商户授权状态查询
      • 支付宝申请单提交
      • 支付宝申请单撤销
      • 支付宝申请单状态查询
      • 支付宝商户授权状态查询
    • 商户开发配置
      • 绑定APPID配置
      • 微信支付目录配置
      • 微信公众号查询
      • 商户开发配置查询
      • 重发报备
      • 微信小程序冻结状态查询
      • 微信小程序冻结通知(非接口)
    • 商户限额调整
      • 商户限额查询
      • 商户提额申请
      • 商户提额记录查询
    • 商户风险处置
      • 商户风险处置通知
      • 风险商户图片上传
      • 微信官方风险商户文件
      • 支付宝官方风险商户文件
      • 风险商户异常流水查询
      • 风险商户调查列表
      • 风险商户调查详情
      • 风险调查单历史查询
      • 风险调查材料下载
      • 风险调查单处理
    • 商户手续费开票
      • 开具发票
      • 开票详情
      • 待开发票信息查询
      • 合并开票商户信息查询
      • 电子普票重发邮箱
      • 开票历史查询
    • 无界收款
      • 无界收款图片上传
      • 无界收款开通
      • 无界收款审核查询
      • 无界收款审核结果通知
  • 资金结算
    • D0开通及提现相关问题Q&A
    • D0结算业务
      • 产品介绍
      • 获取人脸识别链接
      • 人脸认证结果查询
      • D0开通
      • D0信息修改
      • D0状态查询
      • D0开通失败申诉
      • D0申诉结果查询
      • D0申诉结果通知
    • 特殊结算业务
      • 产品介绍
      • 结算业务申请
      • 结算业务变更
      • 结算业务结果查询
      • 结算业务结果通知
    • 提现查账
      • 手工提现
      • 到账记录查询
      • 到账记录批量查询
      • 秒到提现记录查询
      • 账户余额查询
      • 挂账记录查询
      • 补付申请
      • 提现结果通知
      • 账户余额变动通知
      • 提现对账文件
      • 批量结算提现通知
      • 到账附言配置
      • 查询到账附言
  • 星账云管家
    • 星账云管家
    • 功能开通
      • 功能开通(XZY001)
      • 编辑(XZY003)
      • 编辑上传付款凭证(XZY002)
      • 修改生效状态(XZY004)
      • 查询详情信息(XZY005)
      • 产品开通审核通知(XZY006)
    • 公共接口
      • 上传文件(XZY013)
    • 分账
      • 交易
        • 分账结算电子回单下载(XZY037)
        • 余额查询接口(XZY041)
        • 分账结果回调(XZY016)
        • 分账合并入账电子回单下载(XZY039)
        • 订单查询(XZY015)
        • 分账(XZY014)
        • 完结分账(XZY040)
        • 查询交易订单分账金额信息(XZY041)
        • 分账撤销退回(XZY017)
      • 客户管理
        • 新增客户(XZY018)
        • 分账授权申请接口-收单统一结算(XZY043)
        • 批量分账授权申请接口-收单统一结算(XZY044)
        • 合作状态调整(XZY020)
        • 解约/重启签约(XZY-001-002)
        • 编辑客户(XZY023)
        • 替换客户结算卡(XZY022)
        • 审核通知(XZY019)
        • 查询分账客户信息(XZY021)
    • 归集
      • 开户/授权
        • 归集授权申请接口-收单统一结算(XZY037)
        • 审核通知(XZY025)
        • 合作状态调整(XZY026)
        • 查询归集客户信息(XZY027)
        • 替换结算卡(XZY028)
        • 编辑信息(XZY029)
      • 交易
        • 归集合并入账电子回单下载(XZY040)
        • 归集结算电子回单下载(XZY038)
        • 余额查询接口(XZY042)
        • 订单查询(XZY031)
        • 归集(XZY030)
        • 归集结果回调(XZY032)
        • 归集撤销退回(XZY033)
    • 提现
      • 提现订单查询(XZY035)
      • 结算回调通知(XZY050)
      • 提现电子回单下载(XZY040)
      • 提现(XZY036)
    • 账户
      • 结算资金流水查询(XZY047)
      • 结算卡资金流水查询(XZY049)
  • 设备管理与推送
    • 设备管理
      • 收款设备绑定
      • 收款设备解绑
      • 收款设备绑定查询
      • 设备绑定/解绑结果通知
      • 音箱绑定
      • 音箱绑定查询
      • 音箱解绑
      • 设备信息修改
    • 设备推送
      • 音箱播报
      • 交易打印
  • 营销活动
    • 银行活动
      • 产品介绍
      • 图片上传
      • 商户补贴额度列表查询
      • 银行活动报名
      • 银行活动报名结果查询
      • 银行活动报名结果通知
      • 银行活动列表查询
      • 银行活动退出
    • 特殊行业活动
      • 产品介绍
      • 特殊行业活动报名申请
      • 特殊活动报名结果通知
      • 特殊行业商户活动查询
      • 特殊行业活动图片上传
    • 综合账户
      • 营销增资-订单
      • 营销增资-金额
      • 营销增资查询
      • 综合账户余额查询
      • 综合账户流水查询
      • 撤销营销增资-金额
    • 支付宝分期商家贴息
      • 贴息活动报名配置
      • 查询贴息活动
      • 修改活动里的费率
      • 贴息活动取消报名
      • 贴息活动商户列表查询
    • 增值服务
      • 获取增值营销产品列表
      • 获取增值营销产品明细
      • 获取分享链接
      • 推广结果列表查询
      • 推广结果详情
  • 慧徕店开放平台
    • 慧+SPI
      • 对接前准备
      • 商户同步
        • 开发配置
          • 请求域名
          • 加签&验签
        • 商户同步
        • 商户同步查询
        • 商户同步回调
      • 应用模块
        • 产品介绍
        • 开发配置
          • 请求域名
          • 加签&验签
        • 应用及增值服务列表查询
        • 商户应用注册及增值服务状态查询
        • 应用注册
        • 应用注册状态查询
        • 应用注册回调通知
        • 增值服务激活
        • 增值服务激活状态查询
        • 增值服务激活回调通知
      • 聚合支付SPI
        • 产品介绍
        • 开发配置
          • 签名方式
          • 公共参数
          • 验签方式
        • 支付API
        • 付款码支付
        • 扫码支付-官方码
        • JSAPI支付
        • 扫码支付-聚合码
        • 微信半屏小程序支付
        • 订单查询
        • 交易结果通知
        • 退款
        • 退款查询
        • 关闭订单
        • 获取银联用户标识
        • 公共参数
    • 应用开发API
      • 验签说明
      • 应用支付
      • 门店信息同步
      • 门店增值服务激活
  • 微信物业缴费
    • 小区楼房信息推送
    • 用户账单信息同步
    • 用户账单信息删除
    • 物业缴费订单查询
    • 代扣申请签约/解约通知
    • 代扣申请签约/解约结果同步
    • 微信代扣信息同步
    • 申请代扣扣费
  • 支付广告
    • SDK资源文件
    • 微信小程序广告
    • 支付宝小程序广告
    • 支付宝H5广告
  • 数据字典
    • MCC
      • 搜索查询二级mcc
      • 获取一级mcc目录
      • 获取二级mcc目录
    • 地区码
      • 获取省
      • 获取市
      • 获取区县
    • 落地银行
      • 落地银行查询
      • 落地银行下级机构查询
    • 银行信息
      • 获取银行省信息-联行号
      • 获取银行市信息-联行号
      • 银行信息查询
      • 查询联行号信息
      • 根据银行卡号获取银行信息
    • 连锁品牌
      • 获取连锁品牌信息
  • 分账服务
    • 订单分账
      • 订单分账
      • 订单分账结果查询
      • 订单分账撤销
      • 订单分账对帐文件
    • 余额分账
      • 余额分账
      • 余额分账结果查询
      • 可分账余额查询
    • 分账配置
      • 分账图片上传
      • 分账商户配置
      • 分账商户配置结果查询
      • 分账商户配置结果通知
      • 分账商户移除
      • 快捷创建资金接收方
      • 修改分账比例与金额
      • 商圈信息查询
  • 数据模型
    • PostPayRsp?
    • CompAccSubDocFileResponse
    • TermInfo
    • FileHeader
    • TitokDishItem
    • CompAccSubSumVo
    • CompAccSubDocRow
    • IsvRspListTermInfo
    • FileBody
    • TitokDataUploadReq
    • CompAccSubSumRow
    • GetTermInfoReq
    • StandardResponse
    • RunResultVo
    • ErrorResponse
  1. 商户入网

商户审核结果通知

测试环境
https://xyf-server-test.postar.cn
测试环境
https://xyf-server-test.postar.cn
POST
/商户进件/修改异步通知
使用场景:商户、ISV

请注意:邮驿付&星驿付后期会对返回参数保留扩展的权力,扩展方式为新增参数但不会删除参数,请商户在解析邮驿付&星驿付返回参数时要支持邮驿付&星驿付可能扩展参数这种情况。#

项目为虚拟机构(FWH开头机构号)时,当前暂不支持接收商户进件异步通知,需主动调用“审核结果查询”接口获取商户审核状态;项目为610机构开头时,支持商户申请与修改审核后推送异步通知。
返回值必带:{"rspCod":"","rspMsg":"success"}
接收成功时,请务必带上"rspMsg":"success",否则平台将一直发送该条通知,一分钟推一次,总共推10次,如果10次都失败,会在15分钟时补充推送,直到超过15分钟后就不再发送。

异步返回结果验签#

假设接收到通知的示例如下:
注意:以下示例报文仅供参考,实际返回的详细报文请以实际返回为准。
{"agetId":"61000000103774","pdata":"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"}
第一步:将加密参数(pdata)使用 RSA 公钥解密成明文:
{"ACCOUNT_NAME":"王玉茹","ACCOUNT_NO":"6215699120","AGE_CUST_ID":"61000000103774","AGE_NAME":"郑秀华收单01一级","AUTH_DATE":"2025-11-08 17:07:10","AUTH_RESULT":"00","AUTH_TYPE":"0","BANK_NAME":"BOC","BUS_NAME":"福建合码通信息服务有限责任公司","CUST_ID":"60000001056036","CUST_TYPE":"1","IND_TYPE":"计算机软件开发、系统集成、数据处理服务,7372","IS_SIGNAXQ":"0","MERGER_ID":"","MERGER_NAME":"","MERGER_PH":"","NOT_THROW_REASON":"","PHONE":"1378372","THIRD_NO":"85735017372U03H","sign":"nxz/UodhiAIPrBkoc3QWGeFMe6YjNrFiwtrjCZ9Dp1gtWMZs9fAOk+IwrVReSDS+SIW44UU/5/VX6PmTfIooXghiYx40zhPwbMDEmDWkSZ0SW1h9VzE+uZfi8gMJGy35NYQvl9O0ShYVBw2hnEUyD9JGd+TlGOHsZ6eRgYXlDguepceN9JV4OuMKM7jDP/wFUNuB292S0rM1MtolJmjrfNTgvxwTvRu1ykz+L/QLpM5N0PJnGmpPOkV0ij4/UALGArH+yV2YOgPekzFbP0WZJyY4LI/fSVPN8/Qk7W0wu5dzsVAnRNWNyAq4kAECRzABOZRlrKVJLeimwL2PmKr7Rw=="}
第二步:在明文参数列表中,除去 sign 参数外,其他参数均为待验签的参数。
第三步:将剩下明文参数进行字典排序,组成字符串,得到拼接串:
ACCOUNT_NAME=王玉茹&ACCOUNT_NO=6215699120&AGE_CUST_ID=61000000103774&AGE_NAME=郑秀华收单01一级&AUTH_DATE=2025-11-08 17:07:10&AUTH_RESULT=00&AUTH_TYPE=0&BANK_NAME=BOC&BUS_NAME=福建合码通信息服务有限责任公司&CUST_ID=60000001056036&CUST_TYPE=1&IND_TYPE=计算机软件开发、系统集成、数据处理服务,7372&IS_SIGNAXQ=0&MERGER_ID=&MERGER_NAME=&MERGER_PH=&NOT_THROW_REASON=&PHONE=1378372&THIRD_NO=85735017372U03H
第四步:将拼接串使用 SHA256 编码,生成字符串1:
94af9639c04c9343d1f8627950baece652274722c4377f62e201e73c7e6fef67
第五步:将明文中签名参数(sign)使用 RSA 公钥解密为字符串2。
第六步:将字符串1和字符串2进行比较,相同即为验签通过,反之验签失败。

异步通知验签Demo#

1.
java
展开查看完整demo
2.
c#
展开查看完整demo
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace Api.XYFPay.Helper.Test
{
    public class RSA2Helper
    {
        private static string pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhWb4rG/iWIxLVM9u7LtAWWliOpLUG4gat7t1DACtwsdxIrxG2eIRvVyol6lMnulGE6kx7c2P9AiJZTcZ4iQjK1BTj0s4IhpPgGibF0xo6mesvw/1IyTQs02c+gCcy3C7qJgIVF4IhF7DA4RhHJ/wUixTITdbpw2JIVw+VRiEAPXOOi6uIOlvKflDWQW8AP/bYRWISxgb6finKhbMGNJgeUh/QAtsPOvocRVTCd/OvmSCcP8y+Qck8qbdJdgHOSuCNontHsa3TBHzJASkwJSnRmkdRuNq+fFgPMqItj9p0wu7KcI0wm+Llk5R+xeYdLOspmf4JMNh+XX7zP/B2AARgQIDAQAB";

        static void Main(string[] args)
        {
            try
            {
                var notifyBody = "{\"agetId\":\"61000000583951\",\"pdata\":\"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\"}";

                var parameters = JsonConvert.DeserializeObject<Dictionary<string, object>>(notifyBody);
                if (parameters == null || !parameters.TryGetValue("pdata", out object pdataObj))
                    throw new Exception("未找到 pdata 字段");

                string pdata = pdataObj.ToString();

                // 分段解密 pdata(整个 JSON 密文)
                byte[] plainBytes = DecryptByPublicKey(pdata, pubKey);
                string plainTextStr = Encoding.UTF8.GetString(plainBytes);
                Console.WriteLine("解密后的 JSON 明文: " + plainTextStr);

                var plainText = JsonConvert.DeserializeObject<Dictionary<string, object>>(plainTextStr);
                if (plainText == null || !plainText.TryGetValue("sign", out object signObj))
                    throw new Exception("pdata 中未找到 sign 字段");

                string sign = signObj.ToString();
                plainText.Remove("sign");

                // 按字典序排序并拼接
                var sortedParams = plainText.OrderBy(p => p.Key, StringComparer.Ordinal)
                    .Select(p => $"{p.Key}={p.Value}");
                string parameterString = string.Join("&", sortedParams);
                Console.WriteLine("待签名字符串: " + parameterString);

                // 计算本地 SHA256 (十六进制)
                string localSha256Hex = SHA256Encrypt(parameterString);
                Console.WriteLine("本地 SHA256: " + localSha256Hex);

                // 解密 sign
                byte[] signDecryptedBytes = DecryptByPublicKey(sign, pubKey);
                string signSha256Hex = Encoding.UTF8.GetString(signDecryptedBytes);
                Console.WriteLine("sign解密: " + signSha256Hex);

                // 比较
                if (signSha256Hex == localSha256Hex)
                    Console.WriteLine("验签通过");
                else
                    Console.WriteLine("验签失败");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"异常: {ex.Message}");
                Console.WriteLine(ex.StackTrace);
            }
        }

        /// <summary>
        /// 分段 RSA 公钥解密
        /// </summary>
        public static byte[] DecryptByPublicKey(string data, string publicKey)
        {
            byte[] encryptedData = Convert.FromBase64String(data);
            string xmlPublicKey = RSAPublicKeyJava2DotNet(publicKey);

            using (var rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(xmlPublicKey);
                int keySizeBytes = rsa.KeySize / 8; // 2048 位 → 256 字节

                // 检查长度是否为 keySizeBytes 的整数倍
                if (encryptedData.Length % keySizeBytes != 0)
                    throw new Exception($"密文长度 {encryptedData.Length} 不是 {keySizeBytes} 的整数倍,可能密钥不匹配或数据损坏。");

                // 初始化 BouncyCastle 解密器
                var keyParam = DotNetUtilities.GetRsaPublicKey(rsa);
                IBufferedCipher cipher = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");
                cipher.Init(false, keyParam);

                using (var outStream = new MemoryStream())
                {
                    int offset = 0;
                    while (offset < encryptedData.Length)
                    {
                        byte[] block = new byte[keySizeBytes];
                        Array.Copy(encryptedData, offset, block, 0, keySizeBytes);
                        byte[] decryptedBlock = cipher.DoFinal(block);
                        outStream.Write(decryptedBlock, 0, decryptedBlock.Length);
                        offset += keySizeBytes;
                    }
                    return outStream.ToArray();
                }
            }
        }

        /// <summary>
        /// Java RSA 公钥格式转 .NET 格式
        /// </summary>
        private static string RSAPublicKeyJava2DotNet(string publicKey)
        {
            var publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
                Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
                Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
        }

        /// <summary>
        /// SHA256 哈希(返回小写十六进制)
        /// </summary>
        public static string SHA256Encrypt(string data)
        {
            using (var sha256 = SHA256.Create())
            {
                byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(data));
                return BitConverter.ToString(hash).Replace("-", "").ToLower();
            }
        }
    }
}
3.
php
展开查看完整demo
4.
python
展开查看完整demo
5.
go
展开查看完整demo
6.
nodejs
展开查看完整demo
const crypto = require('crypto');

function decryptByPublicKey(ciphertext, publicKeyBase64, blockSize) {
    const pubKey = crypto.createPublicKey({
        key: Buffer.from(publicKeyBase64, 'base64'),
        format: 'der',
        type: 'spki'
    });


    if (ciphertext.length % blockSize !== 0) {
        throw new Error(`密文长度 ${ciphertext.length} 不是 ${blockSize} 的整数倍`);
    }

    const parts = [];
    for (let offset = 0; offset < ciphertext.length; offset += blockSize) {
        const block = ciphertext.slice(offset, offset + blockSize);
        let decrypted;
        try {
            decrypted = crypto.publicDecrypt(
                { key: pubKey, padding: crypto.constants.RSA_PKCS1_PADDING },
                block
            );
        } catch (err) {
            console.error(`块 ${offset/blockSize} 解密失败:`, err.message);
            throw err;
        }
        parts.push(decrypted);
    }
    return Buffer.concat(parts);
}

function verifySign(jsonStr, publicKeyBase64) {
    const data = JSON.parse(jsonStr);
    const pdata = data.pdata;
    const ciphertext = Buffer.from(pdata, 'base64');

    // 自动推断块大小:从公钥获取模长,若获取不到则尝试 256
    let blockSize = 256;

    let decryptedStr;
    try {
        const plainBuffer = decryptByPublicKey(ciphertext, publicKeyBase64, blockSize);
        decryptedStr = plainBuffer.toString('utf8');
    } catch (err) {
        throw new Error(`解密 pdata 失败: ${err.message}`);
    }
    console.log('解密pdata:', decryptedStr);

    const inner = JSON.parse(decryptedStr);
    const signBase64 = inner.sign;
    delete inner.sign;

    const keys = Object.keys(inner).sort();
    const parts = keys.map(k => `${k}=${typeof inner[k] === 'object' ? JSON.stringify(inner[k]) : String(inner[k])}`);
    const signedStr = parts.join('&');
    console.log('拼接串:', signedStr);

    const hash = crypto.createHash('sha256').update(signedStr, 'utf8').digest('hex');
    console.log('本地SHA256:', hash);

    const signCipher = Buffer.from(signBase64, 'base64');
    const signPlain = decryptByPublicKey(signCipher, publicKeyBase64, blockSize);
    const signHex = signPlain.toString('utf8');
    console.log('sign解密:', signHex);

    return hash === signHex;
}

// 使用
const notifyBody = `{"agetId":"61000000583951","pdata":"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"}`;

const publicKeyBase64 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhWb4rG/iWIxLVM9u7LtAWWliOpLUG4gat7t1DACtwsdxIrxG2eIRvVyol6lMnulGE6kx7c2P9AiJZTcZ4iQjK1BTj0s4IhpPgGibF0xo6mesvw/1IyTQs02c+gCcy3C7qJgIVF4IhF7DA4RhHJ/wUixTITdbpw2JIVw+VRiEAPXOOi6uIOlvKflDWQW8AP/bYRWISxgb6finKhbMGNJgeUh/QAtsPOvocRVTCd/OvmSCcP8y+Qck8qbdJdgHOSuCNontHsa3TBHzJASkwJSnRmkdRuNq+fFgPMqItj9p0wu7KcI0wm+Llk5R+xeYdLOspmf4JMNh+XX7zP/B2AARgQIDAQAB";

try {
    const ok = verifySign(notifyBody, publicKeyBase64);
    console.log(ok ? '验签通过' : '验签失败');
} catch (err) {
    console.error('验签出错:', err.message);
}

请求参数

Header 参数

Body 参数application/json

示例

返回响应

🟢200成功
application/json
Bodyapplication/json

请求示例请求示例
Java
Shell
C#
PHP
响应示例响应示例
{
    "rspCod": "000000",
    "rspMsg": "success"
}
修改于 2026-07-30 02:16:26
上一页
审核结果查询
下一页
待审核商户撤回
Built with