跳到主要内容

微信 JSAPI 支付(微信公众号)

WeChat JSAPI process-flow
注意

公众号支付必须从微信应用内浏览器发起。 它们无法从其他浏览器(例如 Chrome 或 Safari)启动。

JSAPI 支付类型

Note: 加拿大地区的商户,请参阅部分了解支付请求和响应参数,其中“pay_type”为800207。

JSAPI 支付有两种不同的实现方法。


1. 拥有实名认证的公众号JSAPI支付

对于这种集成,商户需要在微信上注册自己的公众号,我们会将公众号与商户的QFPay支付账户绑定。 在这种情况下,商家可以创建和发布自己的内容、访问客户信息并收集自己的关注者。 选择该实现方式时,商户需要获取“oauth_code”、用户“openid”,并通过官方微信平台触发微信支付。 商户只需参考QFPay交易查询API接口即可。

Step 1: 开发者在微信公众号平台完成实名认证后,即可使用微信公众号支付。 认证完成后,开发者可以获得认证公众账号的openid参数。 请参考官方微信文档,了解更多信息。

Step 2: 通过提供指定的openid请求QFPAY订单支付接口/trade/v1/ payment并返回pay_params数据,具体说明请参考 支付API端点.

Step 3: 商户认证申请时打开JSAPI支付授权目录发起支付。 更多详情请参考 微信支付官方文档.


2. 未拥有实名认证的公众号JSAPI支付

对于此类支付,商户可以基于QFPay的公众号进行。 此整合仅适用于使用间接结算选项(即由 QFPay 提供结算)的商户。 对于此实现,商户应使用 QFPay 的 API 获取“oauth_code”、用户“openid”并触发微信支付,如下所述。

获取微信oauth_code

GET WeChat oauth_code request:

{
https://test-openapi-hk.qfapi.com/tool/v1/get_weixin_oauth_code?app_code=5D81D64E602043F7AF51CEXXXXXXXXXX&sign=F4D8FB00894F213993B33116BC1B4E10&redirect_uri=https://sdk.qfapi.com
}
import hashlib
import requests
from flask import Flask, redirect
from flask import request
import json
import random
import datetime
import string
import urllib
import urllib.parse

# Enter Client Credentials
environment = 'https://test-openapi-hk.qfapi.com'
app_code = "******"
client_key = "******"

# Create MD5 signature
def make_req_sign(data, key):
keys = list(data.keys())
keys.sort()
p = []
for k in keys:
v = data[k]
p.append('%s=%s'%(k,v))
unsign_str = ('&'.join(p) + key).encode("utf-8")
s = hashlib.md5(unsign_str).hexdigest()
return s.upper()

def get_out_code():
# Body payload
redirect_uri = 'http://49ae4dbd47a6.ngrok.io/getcode'
data = {'app_code': app_code, 'redirect_uri': redirect_uri}
sign = make_req_sign(data, client_key)

return environment+"/tool/v1/get_weixin_oauth_code?app_code="+app_code+"&sign="+sign+"&redirect_uri="+redirect_uri #+"&mchid="+mchid

Redirect to URL after the GET oauth_code request has been successful:

{
"http://xg.fshop.top/index.php/wap/pay/wxredirect?showwxpaytitle=1&code=011QipnO1yMIla1VJdoO1FUrnO1Qipnv"
}

HTTP请求

GET ../tool/v1/get_weixin_oauth_code

app_codesign 都必须作为参数提交,而不是在 http 标头中提交。 该URL请求必须在微信环境中发送。 每次发起支付都需要重新获取微信oauth_codeopenid

请求参数

參數名稱參數編碼是否必填參數類型描述
开发者IDapp_codeString(32)app_code由QFPay分配给合作伙伴
回调地址redirect_uriString(512)请求成功后,用户将被重定向到回调地址
商戶IDmchidString(16)“mchid”是QFPay为每个商户分配的唯一标识
簽名signString根据统一框架获得的签名

获取微信openid


HTTP Request:

{
https://openapi.qfpay.com/tool/v1/get_weixin_openid?code=011QipnO1yMIla1VJdoO1FUrnO1Qipnv
}

def get_open_id(data):

try:
r = requests.get(environment+"/tool/v1/get_weixin_openid",params=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, client_key)})
print (r.request.url)
print (r.content)
if r.json()["respcd"]=="0000":
return r.json()["openid"]
else:
pass
except:
print("An exception occurred")

The above command returns JSON structured like this:

{
"resperr": "",
"respcd": 0000,
"respmsg": "",
"openid": "oo3Lss8d0hLOuyTuSJMVwLTk68JE"
}
每次调用支付接口都必须获取新的oauth_codeopenid。 为了请求“openid”,必须在 http 标头中提交“X-QF-APPCODE”和“X-QF-SIGN”。

HTTP请求

GET ../tool/v1/get_weixin_openid

请求参数

参数编码二级参数编码是否必填参数类型描述
微信 oauth_codecodeString该代码由 GET oauth_code 请求 返回。 它是唯一的,只能使用一次。
商户IDmchidString(16)“mchid”是QFPay为每个商户分配的唯一标识

响应参数

参数编码二级参数编码参数类型参数名字描述
openidString(64)微信 openid每个微信用户都会分配一个唯一的openid

微信申请支付

有关代码说明,请选择带有以下选项卡的 Python。
def payment(openid):
# Create parameter values for data payload
current_time = datetime.datetime.now().replace(microsecond=0)
# Body payload
txamt = '1' #In USD,EUR,etc. Cent. Suggest value > 200 to avoid risk control
txcurrcd = 'THB'
pay_type = '800207'
letters = string.digits
out_trade_no = ''.join(random.choice(letters) for i in range(20))
txdtm = current_time
key = client_key


data = {'txamt': txamt, 'txcurrcd': txcurrcd, 'pay_type': pay_type, 'out_trade_no': out_trade_no, 'txdtm': txdtm, 'sub_openid':openid}

try:
r = requests.post(environment+"/trade/v1/payment",params=data,headers={'X-QF-APPCODE':app_code,'X-QF-SIGN':make_req_sign(data, key)})
if r.json()["respcd"]=="0000":

return r.json()['pay_params']
else:
pass
except:
print("An exception occurred")


app = Flask(__name__)

@app.route("/payment",methods=['GET', 'POST'])
def api_payment():

if "MichroMessenger" in request.headers.get('User-Agent'): #get an oauth_code
print (get_out_code())
return redirect(get_out_code(), code=302)

@app.route("/getcode",methods=['GET', 'POST'])
def api_get_code():
print ("------------------------------------")
print (request.args)
print (request.args.get("code"))
code = request.args.get('code')
print (code)
if code != "": # user returned with oauth_code

sub_openid=get_open_id({"code": code}) # get open id using oauth_code
param=payment(sub_openid) # payment request to QFPay

# add necessary parameters and redirect
param["mchntnm"]="Pet Shop"
param["txamt"]="1"
param["currency"]="THB"
param["redirect_url"]="www.example.com"
return redirect("https://o2-th.qfapi.com/q/direct?"+urllib.parse.urlencode(param), code=302) # direct user"""
else:
print("unable to obtain code")
return

if __name__ == '__main__':
app.run(host="127.0.0.1",port = 80)

商户可选择开通微信实名认证。 目前实名认证仅适用于中国大陆公民,包括真实姓名和身份证号码。 如果提供身份证明,付款人的钱包信息(例如连接的银行卡)必须与商家提供的数据相同。 如果客户尚未将微信账户绑定银行卡,仍可进行付款。

HTTP 请求

POST ../trade/v1/payment PayType: 800207

请求参数

参数名字参数编码是否必填参数类型描述
公共支付参数请参阅有关交易的公共支付参数
微信授权码sub_openidString微信 OpenID. 请参阅 GET openid 文档
指定付款方式limit_payString用于限制信用卡交易
扩展客户信息extend_infoObject实名客户身份识别。 该参数目前仅适用于中国大陆公民,并且需要针对所选的PayType使用微信显式激活。 参数“user_creid”中包含消费者的身份证号码,“user_truename”中必须提供编码形式或汉字书写的付款人真实姓名。 一个例子如下所示; extend_info = '{"user_creid":"430067798868676871","user_truename":"\\u5c0f\\u6797"}'

响应参数

参数编码二级参数编码参数类型参数名字描述
pay_paramsappIdString(16)公众号idApp ID由开发者在微信开发者平台注册小程序后由腾讯提供
timeStampString(32)时间戳当前时间
nonceStrString(32)随机字符串不超过32位的随机字符串
packageString(128)交易明细接口返回的prepay_id参数值格式为:prepay_id=**
signTypeString(32)签名方法签名方法, 默认:MD5
paySignString(64)签名签名方法, 签名:MD5
公共响应参数请参阅有关交易的公共支付参数
txcurrcdString(3)交易货币。 查看货币 表以获取可用货币的完整列表

调用微信支付模块

直接向接口提交相关参数,此步骤无需在HTTP header中定义X-QF-APPCODEX-QF-SIGN

HTTP 请求

GET https://o2.qfpay.com/q/direct

请求参数

参数类型是否必填参数类型描述
mchntnmString(128)自定义企业名称。 如果参数是汉字,则需要UTF-8编码
txamtInt(11)金额(100 = $1),建议数值大于200,避免因支付金额过低而被交易风控。
currencyString(3)
goods_nameString(64)定制商品名称。 如果参数是汉字,则需要UTF-8编码
redirect_urlString(512)付款完成后重定向 URL。 urlencode 处理该参数
packageString(128)微信调用支付接口后返回参数
timeStampString(32)微信调用支付接口后返回参数
signTypeString(32)微信调用支付接口后返回参数
paySignString(64)微信调用支付接口后返回参数
appIdString(16)微信调用支付接口后返回参数
nonceStrString(32)微信调用支付接口后返回参数