简要描述

本文主要面向有一定开发基础的用户查阅对接,请仔细接口文档,如有疑问可以下载支付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 支付宝收款码 免签
bankapp string 网银APP收款 免签
unipay string 云闪付收款码 免签
qujie.qrcode string 趣街小二商家版收款码 免签
jsnx.qrcode string 农商行收银宝收款码 免签
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. }