简要描述

本文主要面向有一定开发基础的用户查阅对接,请仔细接口文档,如有疑问可以下载支付DEMO查看对接代码样例。 接口支持收款码通道、签约接口通道支付方式。 免签和签约接口相同,不同处为创建支付订单参数“支付方式 payType”的传值。
接口测试推荐工具:Postmam 或在线工具 https://getman.cn

接口地址

提供HTTPHTTPS两种协议接口,功能一样,您可以按需选择。
商户后台→用户中心页面查看接口地址

请求方式

请求方法:POST
参数传递:Query 请求地址URL拼接参数
query指该参数需在请求URL传参

参数拼接示例:

  1. http://接口地址?orderNo=20190629023134U93661199&amount=1&payType=wechat&merchantNum=tencent&sign=febf5e0e46fcc6bcadfc94c5fb46b0c2&notifyUrl=https://zfapi.nnt.ltd/api/paySuccessNoticeTest

请求参数值说明

参数 必须 类型 说明
merchantNum string query商户号。用户中心查看,不是用户名。
orderNo string query商户订单号。仅允许字母或纯数字,建议不超过32字符,不能有中文
amount number query订单金额。请求的支付金额(单位:元),最多小数点后保留2位
returnType string query接口内容返回类型。
参数请查看下文的returnType可选值说明
notifyUrl string query支付结果通知网址又称异步回调网址。200字符以内,
http(s)开头的公网地址。商户业务系统用来接收支付结果通知数据的回调地址,通知url必须为外网可直接访问的url,且不能携带参数,收到通知后请根据规范返回成功标志,请根据通知参数规范使用Postmam等工具功能测试后传入。
示例值:https://www.xxxx.com/payfm/payCalback.php
returnUrl string query成功后展示网址。200字符以内,
http(s)开头的公网地址,若携带参数请先urlEncode编码后传入。请勿用作支付成功验证,更不要和notifyUrl值传入一样。顾客支付成功后会查看到的网址,系统自动跳转打开,常见为业务系统的支付成功提示、订单中心、会员中心网址等,又称同步跳转地址。
payType string query支付方式。
请根据所需对接的支付方式正确传值,需要在商户后台配置相应的收款号,参数请查看下文的payType可选值说明
attch string query附加信息,回调时候原样返回
subject string query商品标题。100字符以内,签约通道会原样传到支付平台
body string query商品描述。200字符以内,签约通道会原样传到支付平台
payDuration integer query订单支付有效期,单位:分钟;默认值5,最大值15。例:payDuration=5表示订单支付有效期5分钟
sign string query签名。通过MD5加密指定的值拼接计算得出的签名值。签名值=md5(商户号+商户订单号+支付金额+异步通知地址+接入密钥);其中“+”表示字符串拼接,请注意拼接顺序。接入密钥在支付FM商户后台【用户中心】处获取。
returnType 传值说明

是否默认 类型 说明
json string 接口返回json数据
page string 接口直接重定向到支付页面,部分开发语言非页面form表单直接提交的有可能无法重定向,请通过json获取支付链接自行跳转。
payType 传值说明

支付方式收款号配置的在商户后台,名称一致。

是否默认 类型 说明 通道类型
wechat string 收款码 - 微信 免签
alipay string 收款码 - 支付宝(上传模式和动态码模式) 免签
unipay string 收款码 - 云闪付 免签
qujie.qrcode string 收款码 - 趣街小二商家版 免签
jsnx.qrcode string 收款码 - 农商行收银宝 免签
bankapp string 网银APP收款 免签
alipaysign string 支付宝网站支付接口(电脑或手机自适应) 签约
alipay.direct.pc string 支付宝电脑网站支付 签约
alipay.direct.wap string 支付宝手机网站支付 签约
alipay-facetoface string 支付宝当面付 签约
wxpayh5 string 微信支付H5 签约
wxpaynative string 微信支付Native 签约
wxpayjsapi string 微信支付JSAPI 签约

返回参数值说明

支付订单创建成功后,returnType传值为json时HTTP状态码为200且返回JSON数据; 支付订单未成功创建HTTP状态码为400且返回JSON数据

参数 必须 类型 说明
success boolean 正常标志
code number 信息编码。200代表正常。此编码非HTTP状态码,别混淆了。
timestamp number 毫秒时间戳。
msg string 信息描述。
data json 数据内容,支付订单创建成功有值。

data内容参数:

参数 必须 类型 说明
id string 平台订单号。接口请求成功有值
payUrl string 支付链接。 接口请求成功有值。 跳转到该路径即可支付。如您的业务系统为APP请调用手机浏览器访问此链接,不建议在APP内直接访问

参考示例

请求示例

此处罗列一些常用请求的部分代码供参考,完整代码可以参考demo篇章。注意: java系统若使用老版hutool工具请求https接口可能会报错需升级到JDK11或使用http协议请求或使用demo中方法请求。

示例1:非FORM表单POST直接请求URL:

  1. http://接口地址URL?orderNo=20190629023134U93661199&amount=1&payType=wechat&merchantNum=tencent&sign=febf5e0e46fcc6bcadfc94c5fb46b0c2&notifyUrl=https://zfapi.nnt.ltd/api/paySuccessNoticeTes&payDuration=5

示例2 :form表单POST提交

  1. <html>
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  4. <title>跳转支付中……</title></head>
  5. <body>
  6. <form style="display:none" id="fPay" method="post" action="接口地址URL">
  7. <input name="merchantNum" type="text" value="$merchantNum"/>
  8. <input name="amount" type="text" value="$amount"/>
  9. <input name="payType" type="text" value="$payType"/>
  10. <input name="returnUrl" type="text" value="$returnUrl"/>
  11. <input name="notifyUrl" type="text" value="$notifyUrl"/>
  12. <input name="orderNo" type="text" value="$orderID"/>
  13. <input name="subject" type="text" value="$subject"/>
  14. <input type="hidden" name="returnType" value="$returnType"/>
  15. <input name="sign" type="text" value="$sign"/>
  16. </form>
  17. <script type="text/javascript">
  18. // 自动提交也可以手动通过按钮触发表单提交
  19. window.onload= function(){document.getElementById("fPay").submit();}
  20. </script>
  21. </body>
  22. </html>

示例3:PHP构造curl方式提交,可以参考demo

  1. $url="接口地址URL";
  2. $native = array("merchantNum" => $merchantNum,
  3. "payType" => $payType,
  4. "amount" => $amount,
  5. "orderNo" => $orderNo,
  6. "notifyUrl" => $notifyUrl,
  7. "returnUrl" => $returnUrl,
  8. "sign" => $sign,
  9. "returnType" => $returnType);
  10. $param = http_build_query($native);
  11. $ch = curl_init();
  12. curl_setopt($ch, CURLOPT_POST, 1);
  13. curl_setopt($ch, CURLOPT_URL, $url);
  14. curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
  15. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  16. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  17. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  18. $response = curl_exec($ch);
  19. curl_close($ch);
  20. return array($response);

推荐方式示例4:php的json方式,完成的参考demo

  1. <?php
  2. $returnType = "json";
  3. $api_url = "接口地址"; //在用户中心页面查看 接口地址
  4. $native = array(
  5. "merchantNum" => $merchantNum,
  6. "payType" => $payType,
  7. "amount" => $amount,
  8. "orderNo" => $orderNo,
  9. "notifyUrl" => $notifyUrl,
  10. "returnUrl" => $returnUrl,
  11. "sign" => $sign,
  12. "returnType" => $returnType
  13. );
  14. $param = http_build_query($native);
  15. $return = http_request($api_url, $param, 'application/x-www-form-urlencoded;charset=utf-8');//http_request方法源码参考完整版本demo
  16. if(strpos($return,'{') === 0){
  17. $return = json_decode($return, true);
  18. if($return['success']){
  19. //json方式展示支付链接有如下几种
  20. //header("location:".$return['data']['payUrl']);
  21. header("Refresh:0.1;url=" . $return['data']['payUrl']); //会在0.1秒后执行跳转
  22. }else{
  23. echo "请求异常";
  24. }
  25. }else{
  26. echo "请求异常";
  27. }
  28. exit;
  29. ?>

推荐方式示例5:JAVA控制类核心代码,完整可参考demo

  1. Map<String, Object> paramMap = new HashMap<>();// post请求的参数
  2. paramMap.put("merchantNum", merchantNum);
  3. paramMap.put("orderNo", orderNo);
  4. paramMap.put("amount", amount);
  5. paramMap.put("notifyUrl", notifyUrl);
  6. paramMap.put("returnUrl", returnUrl);
  7. paramMap.put("payType", payType);
  8. paramMap.put("attch", attch);
  9. paramMap.put("sign", sign);
  10. paramMap.put("subject", "测试商品标题");
  11. paramMap.put("body", "测试商品说明");
  12. String paramStr = HttpUtil.toParams(paramMap);
  13. System.out.println(paramStr);
  14. HttpClient httpclient = HttpClientBuilder.create().build();
  15. HttpPost httpost = new HttpPost(url + "?" + paramStr); // 设置响应头信息
  16. HttpResponse retResp;
  17. String result;
  18. JSONObject ret = new JSONObject();
  19. try {
  20. retResp = httpclient.execute(httpost);
  21. result = EntityUtils.toString(retResp.getEntity(), "UTF-8");
  22. System.out.println(result);
  23. }
  24. catch (ClientProtocolException e1) {
  25. e1.printStackTrace();
  26. }
  27. catch (IOException e1) {
  28. e1.printStackTrace();
  29. }catch (ParseException e1) {
  30. e1.printStackTrace();
  31. }

返回示例

正确时返回:
returnType传值为json返回如下格式内容:
HTTP状态码为200

  1. {
  2. "success": true,
  3. "msg": "success",
  4. "code": 200,
  5. "timestamp": 1624553174921,
  6. "data": {
  7. "id": "1408103748495998976",
  8. "payUrl": "http://XXXXX/pay?orderNo=1408103748495998976"
  9. }
  10. }

错误时返回:

其他返回错误代码请根据描述信息排查
HTTP状态码为400

  1. {
  2. "success": false,
  3. "msg": "签名不正确",
  4. "code": 500,
  5. "timestamp": 1584413776852,
  6. "data": null
  7. }

备注

返回值说明

msg 说明
success 调用接口成功
用户账号无权限使用 调用接口传入的商户号不正确或者用户账号被限制使用
金额格式不正确 金额格式要为标准数值类型
金额不能小于或等于0 订单金额不能小于或等于0,请检查金额
免签通道订单金额不能小于1元 免签通道的接口调用订单金额至少为1元
签名不正确 签名不正确,请根据API签名规则检查MD5签名参数和结果是否正确
发起订单失败,通道不存在 通道不存在,请检查支付方式传值是否正确
商户接口额度不足,请充值 商户接口额度不足,请登录支付FM充值可收款接口额度
XXX:must not be blank或XXX:不能为空 请求参数值没有按照规范传递到我们接口,一般为请求方式或请求数据不合法导致。请检查参数名是否和文档要求一致,请求方式是post,参数是param方式不是json等

returnUrl保留参数说明

订单为已支付状态时,系统会根据传入的 returnUrl进行页面重定向跳转,以下参数为跳转时候系统默认携带,请勿携带传入。

携带参数初衷用于配合业务系统的页面展示,请勿用于订单已支付校验判断。

参数 说明
orderNo 商户订单号
mchOrderNo 商户订单号
platformOrderNo 平台订单号
amount 商户订单金额
actualPayAmount 实际支付金额

MD5签名示例

支付DEMO中有完整说明和建议使用的工具包,以下只是签名示例(JAVA),其他语言可以用示例参数签名,签名结果一致表示签名函数是可用的。 供技术调试对比MD5算法用:abc123456的MD5加密串:大写:0659C7992E268962384EB17FAFE88364,小写:0659c7992e268962384eb17fafe88364

  1. package ltd.nnt.zhifu.test;
  2. import java.math.BigInteger;
  3. import java.security.MessageDigest;
  4. import java.security.NoSuchAlgorithmException;
  5. public class MD5Utils {
  6. /**
  7. * 使用md5的算法进行加密
  8. */
  9. public static String md5(String plainText) {
  10. byte[] secretBytes = null;
  11. try {
  12. secretBytes = MessageDigest.getInstance("md5").digest(
  13. plainText.getBytes());
  14. } catch (NoSuchAlgorithmException e) {
  15. throw new RuntimeException("没有md5这个算法!");
  16. }
  17. String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
  18. // 如果生成数字未满32位,需要前面补0
  19. for (int i = 0; i < 32 - md5code.length(); i++) {
  20. md5code = "0" + md5code;
  21. }
  22. return md5code;
  23. }
  24. public static void main(String[] args) {
  25. System.out.println(md5("abc123456"));
  26. }
  27. }