支付宝是用 POST 方式发送通知信息,只有在支付宝的交易管理中存在该笔交易,且发生了交易状态的改变,支付宝才会通过该方式发起服务器通知(即时到账交易状态为 等待买家付款 的状态默认是不会发送通知的)
程序执行完后必须打印输出 success。如果商户反馈给支付宝的字符不是 success 这 7 个字符,支付宝服务器会不断重发通知,直到超过 24 小时22 分钟。一般情况下,25 小时以内完成 8 次通知(通知的间隔频率一般是:4 m、10 m、10 m、1 h、2 h、6 h、15 h)。
当商户收到服务器异步通知并打印出 success 时,服务器异步通知参数 notify_id 才会失效。也就是说在支付宝发送同一条异步通知时(包含商户并未成功打印出 success 导致支付宝重发数次通知),服务器异步通知参数 notify_id 是不变的。
相关参数说明及代码
参数 参数名称 类型 必填 描述 范例
notify_time 通知时间 Date 是 通知的发送时间。 格式为yyyy-MM-dd HH:mm:ss。 2015-14-27 15:45:58
notify_type 通知类型 String(64) 是 通知的类型。 trade_status_sync
notify_id 通知校验ID String(128) 是 通知校验 ID ac05099524730693a8b330c5ecf72da9786
app_id 支付宝分配给开发者的应用Id String(32) 是 支付宝分配给开发者的应用 Id。 2.01407E+15
charset 编码格式 String(10) 是 编码格式,如 utf-8、gbk、gb2312 等。 utf-8
version 接口版本 String(3) 是 调用的接口版本, 固定为:1.0。 1
sign_type 签名类型 String(10) 是 商户生成签名字符串所使用的签名算法类型,目前支 RSA2 和 RSA,推荐使用 RSA2。 RSA2
sign 签名 String(256) 是 请参考?异步返回结果的验签。 601510b7970e52cc63db0f44997cf70e
trade_no 支付宝交易号 String(64) 是 支付宝交易凭证号。 2.01311E+27
out_trade_no 商户订单号 String(64) 是 原支付请求的商户订单号。 6.82379E+15
out_biz_no 商户业务号 String(64) 否 商户业务 ID,主要是退款通知中返回退款申请的流水号。 HZRF001
buyer_id 买家支付宝用户号 String(16) 否 买家支付宝账号对应的支付宝唯一用户号。 以 2088 开头的纯 16 位数字。 2.0881E+15
buyer_logon_id 买家支付宝账号 String(100) 否 买家支付宝账号。 15901825620
seller_id 卖家支付宝用户号 String(30) 否 卖家支付宝用户号。 2.0881E+15
seller_email 卖家支付宝账号 String(100) 否 卖家支付宝账号。 zhuzhanghu@alitest.com
trade_status 交易状态 String(32) 否 交易目前所处的状态,见下张表?交易状态说明。 TRADE_CLOSED
total_amount 订单金额 "Number(9,2)" 否 本次交易支付的订单金额,单位为人民币(元)。 20
receipt_amount 实收金额 "Number(9,2)" 否 商家在交易中实际收到的款项,单位为人民币(元)。 15
invoice_amount 开票金额 "Number(9,2)" 否 用户在交易中支付的可开发票的金额。 10
buyer_pay_amount 付款金额 "Number(9,2)" 否 用户在交易中支付的金额。 13.88
point_amount 集分宝金额 "Number(9,2)" 否 使用集分宝支付的金额。 12
refund_fee 总退款金额 "Number(9,2)" 否 退款通知中,返回总退款金额,单位为元,支持两位小数。 2.58
subject 订单标题 String(256) 否 商品的标题/交易标题/订单标题/订单关键字等,是请求时对应的参数,原样通知回来。 当面付交易
body 商品描述 String(400) 否 该订单的备注、描述、明细等。对应请求时的 body 参数,原样通知回来。 当面付交易内容
gmt_create 交易创建时间 Date 否 该笔交易创建的时间。格式为 yyyy-MM-dd HH:mm:ss。 2015/4/27 15:45
gmt_payment 交易付款时间 Date 否 该笔交易的买家付款时间。格式为 yyyy-MM-dd HH:mm:ss。 2015/4/27 15:45
gmt_refund 交易退款时间 Date 否 该笔交易的退款时间。格式为 yyyy-MM-dd HH:mm:ss。 45:57.3
gmt_close 交易结束时间 Date 否 该笔交易结束时间。格式为 yyyy-MM-dd HH:mm:ss。。 2015/4/29 15:45
fund_bill_list 支付金额信息 String(512) 否 支付成功的各个渠道金额信息,详见下表?资金明细信息说明。 "[{“amount”:“15.00”,“fundChannel”:“ALIPAYACCOUNT”}]"
passback_params 回传参数 String(512) 否 公共回传参数,如果请求时传递了该参数,则返回给商户时会在异步通知时将该参数原样返回。本参数必须进行 UrlEncode 之后才可以发送给支付宝。 merchantBizType%3d3C%26merchantBizNo%3d2016010101111
voucher_detail_list 优惠券信息 String 否 本交易支付时所使用的所有优惠券信息,详见下表?优惠券信息说明。 "[{“amount”:“0.20”,“merchantContribute”:“0.00”,“name”:“一键创建券模板的券名称”,“otherContribute”:“0.20”,“type”:“ALIPAY_DISCOUNT_VOUCHER”,“memo”:“学生卡8折优惠”}]"
交易状态说明
枚举名称 枚举说明
WAIT_BUYER_PAY 交易创建,等待买家付款。
TRADE_CLOSED 未付款交易超时关闭,或支付完成后全额退款。
TRADE_SUCCESS 交易支付成功。
TRADE_FINISHED 交易结束,不可退款。
通知触发条件
触发条件名 触发条件描述 触发条件默认值
TRADE_FINISHED 交易完成 true(触发通知)
TRADE_SUCCESS 支付成功 true(触发通知)
WAIT_BUYER_PAY 交易创建 false(不触发通知)
TRADE_CLOSED 交易关闭 true(触发通知)
资金明细信息说明
参数 参数名称 类型 参数说明 是否可为空 样例
fundChannel 支付渠道 String 支付渠道,参见 支付渠道说明。 可空 ALIPAYACCOUNT
amount 支付金额 String 使用指定支付渠道支付的金额,单位为元。 可空 15.00
支付渠道代码 支付渠道
COUPON 支付宝红包
ALIPAYACCOUNT 支付宝余额
POINT 集分宝
DISCOUNT 折扣券
PCARD 预付卡
FINANCEACCOUNT 余额宝
MCARD 商家储值卡
MDISCOUNT 商户优惠券
MCOUPON 商户红包
PCREDIT 蚂蚁花呗
优惠券信息说明
参数 参数名称 类型 必填 描述 范例
name 券名称 String(64) 是 券名称。 XX超市5折券
type 券类型 String(32) 是 券类型,当前支持三种类型:ALIPAY_FIX_VOUCHER - 全场代金券 ALIPAY_DISCOUNT_VOUCHER - 折扣券 ALIPAY_ITEM_VOUCHER - 单品优惠注:不排除将来新增其他类型的可能,商家接入时请注意兼容性,避免硬编码。 ALIPAY_FIX_VOUCHER
amount 优惠券面额 Number(9,2) 是 优惠券面额,它应该等于商家出资加上其他出资方出资。 10.00
merchant_contribute 商家出资 Number(9,2) 否 商家出资(特指发起交易的商家出资金额)。 9.00
other_contribute 其他出资方出资金额 Number(9,2) 否 其他出资方出资金额,可能是支付宝,可能是品牌商,或者其他方,也可能是他们的共同出资。 1.00
memo 优惠券备注信息 String(256) 否 优惠券备注信息。 学生专用优惠
支付宝app接入异步回调
1 class AliPayNotify(tornado.web.RequestHandler):
2 def post(self):
3 def check_pay(params): # 定义检查支付结果的函数
4 sign = params.pop('sign', None) # 取出签名
5 params.pop('sign_type') # 取出签名类型
6 params = sorted(params.items(), key=lambda e: e[0], reverse=False) # 取出字典元素按key的字母升序排序形成列表
7 message = "&".join(u"{}={}".format(k, v) for k, v in params).encode() # 将列表转为二进制参数字符串
8
9 try:
10 public_key = '4Et4H9eKrffZJ9F3ZdgporsYl8U7E5+RqClbioDHqNWOsd6jtQfO94SPiUdAFyvRgEDWj8rum4IjERBgwGS1lb8rycCqA1xUlH3U+8Qg6OpxSR8aTL4jhTSfriUhz3jPHqgIilr3mfpoJ+P' #支付宝公钥
11 status = verify_with_rsa(public_key.encode('utf-8').decode('utf-8'), message,sign) # 验证签名并获取结果
12 return status # 返回验证结果
13 except: # 如果验证失败,返回假值。
14 return False
15
16 recv = self.request.arguments
17
18
19 for k, v in recv.items():
20 recv[k] = str(v[0], encoding='utf-8')
21 out_trade_no = recv.get('out_trade_no')
22 if out_trade_no:
23 #写数据库
24 AliPayUpdate(out_trade_no, recv)
25 if (check_pay(recv)):
26 self.write('success')
27 else:
28 print('验签失败')
29 self.write('Fail'