下载单个子商户/二级商户资金账单

更新时间:2023.04.06

本接口适用于下载单个子商户和二级商户资金账单。

注意

  • 该接口响应的信息请求头中不包含微信接口响应的签名值,因此需要跳过验签的流程。
  • 账单文件的下载地址的有效时间为5min。
  • 建议商户比对实际下载账单文件的哈希值和从接口获取到的哈希值是否一致,以确认下载账单数据的完整性。
  • 微信将在次日9点开始生成前一天的对账单,建议商户在10点后获取。

# 接口说明

支持商户: 【普通服务商】 【电商平台】

请求方式: 【GET】

请求URL: 调用申请账单接口,返回参数“download_url”对应的URL

# 请求步骤说明

下载加密账单步骤分为:

  1. 下载账单
  2. 解密账单

# 步骤1:下载账单

  1. 使用申请账单接口获取download_url,参考下方申请账单返回参数示例。
  2. 使用微信支付APIv3标准对download_url进行签名,并发起请求即可下载账单文件的数据流,参考右侧请求示例。

提示

在下载账单时,当子商户资金账单文件太大(未压缩情况下约大于16GB)时,微信支付会对账单文件进行分割,此时接口会返回多个下载地址。商户分别根据下载地址下载账单文件并解密。解密后,将多个文件按账单文件序号(变量名:bill_sequence)的顺序合并为完整的资金账单文件。

商户需要注意,当返回多个下载地址时,商户依然需要在下载地址有效时间内发起下载请求。因此建议商户获取到下载地址后,并发请求下载。

申请账单返回参数示例

1{
2 "download_bill_count": 1,
3 "download_bill_list": [
4 {
5 "bill_sequence": 1,
6 "download_url": "https://api.mch.weixin.qq.com/v3/bill/downloadurl?token=xxx",
7 "encrypt_key": "a0YK7p+9XaKzE9N4qtFfG/9za1oqKlLXXJWBkH+kX84onAs2Ol/E1fk+6S+FuBXczGDRU8I8D+6PfbwKYBGm0wANUTqHOSezzfbieIo2t51UIId7sP9SoN38W2+IcYDviIsu59KSdyiL3TY2xqZNT8UDcnMWzTNZdSv+CLsSgblB6OKGN9JONTadOFGfv1OKkTp86Li+X7S9bG62wsa572/5Rm4MmDCiKwY4bX2EynWQHBEOExD5URxT6/MX3F1D3BNYrE4fUu1F03k25xVlXnZDjksy6Rf3SCgadR+Cepc6mdfF9b2gTxNsJFMEdYXbqL0W1WQZ3UqSPQCguK6uLA==",
8 "hash_type": "SHA1",
9 "hash_value": "79bb0f45fc4c42234a918000b2668d689e2bde04",
10 "nonce": "a8607ef79034c49c"
11 }
12 ]
13}

请求示例

1$ curl https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx -H '
2Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900009191",
3nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",
4signature="uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5
5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI
61XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8al
7LDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/
84nLBiCwIUFluw==",timestamp="1554208460",serial_no="1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C"'

# 步骤2:解密账单

# 解密流程

子商户资金账单文件采用商户指定的加密算法(支持AES-256-GCM算法和SM4-GCM算法)进行加密,商户需要进行解密才能得到账单明文。解密流程是:

  1. 通过步骤1:下载账单可以得到账单文件密文ciphertext;
  2. 使用商户证书私钥解密从接口获取的加密密钥(变量名:encrypt_key)得到密钥明文key,详细可参考:encrypt_key密钥解密
  3. 利用前面得到的账单密文ciphertext,密钥key和接口返回的随机字符串nonce解密账单,得到账单明文。

提示

GCM即可以进行加密,又可以对信息的完整性进行校验,因此基于GCM加密的账单,解密成功则表示账单完整性校验通过。

基于AES-256-GCM算法加密的账单文件解密代码示例

账单文件解密代码示例请参考WechatPay-API-v3 证书和回调报文解密,注意:返回的账单文件是二进制密文,需以字节数组形式处理,不需要进行Base64解码。

下面对解密代码中使用的参数进行说明:

1{
2 // 密文
3 "ciphertext": "下载得到的账单文件密文",
4 // 加密使用的密钥
5 "key": "用商户证书私钥解密加密密钥得到的明文",
6 // 加密使用的随机字符串
7 "nonce": "接口返回的随机字符串",
8 // 附加数据包(填空)
9 "associated_data": ""
10 }

基于SM4算法加密的账单文件解密代码示例

1with open(r"./ciphertext", 'rb') as f:
2 ciphertext_tag_bytes = f.read()
3ciphertext_tag_hex = binascii.b2a_hex(ciphertext_tag_bytes)
4
5# 账单密文最后16字节是消息验证码
6ciphertext_bytes = binascii.unhexlify(ciphertext_tag_hex[:-32])
7tag_bytes = binascii.unhexlify(ciphertext_tag_hex[-32:])
8key="cbf063b0b33781c3"
9key_bytes = str.encode(key)
10iv="09ba90b74310"
11iv_bytes = str.encode(iv)
12aad = ''
13
14# 账单明文
15decrypt_plain = SM4_GCM_Decrypt_NoPadding_NIST_SP800_38D(ciphertext_bytes, key_bytes, iv_bytes, aad, tag_bytes)

# encrypt_key密钥解密

# RSA-2048加解密

如果HTTP头的Authorization的认证类型采用WECHATPAY2-SHA256-RSA2048, 则从接口获取的加密密钥(变量名:encrypt_key)是使用商户证书公钥进行RSA加密返回的密文,商户需解密后才能得到密钥原文。

解密流程:对encrypt_key先做Base64解码,然后对解码结果使用商户证书私钥进行RSA解密,指定填充方式为最优非对称加密填充(OAEP)。

请参考右侧我们使用命令行演示如何解密,更多的示例可以参考WechatPay-API-v3 敏感信息加密, 解密AES密钥得到key。

RSA-2048加解密示例

1# 解密AES密钥得到key:
2$ echo -n { encrypt_key } | openssl enc -A -base64 -d | openssl rsautl -decrypt -oaep -inkey {商户证书私钥文件}
# SM2加解密

如果HTTP头的Authorization的认证类型采用WECHATPAY2-SM2-WITH-SM3, 则从接口获取的加密密钥(变量名:encrypt_key)是使用SM2椭圆曲线公钥密码算法加密返回的密文,商户需解密后才能得到密钥原文。

解密流程:对encrypt_key先做Base64解码,然后对解码结果使用商户证书私钥进行SM2解密,密文格式是C1C3C2_ASN1。

SM2加解密示例

1# 解密AES密钥得到key
2SM2Init()
3cipher = 'MIGKAiEA4FdfXZIG9oaS4v0CrCcFWAhQR0mR04cwZwFqP6lWwfACIQCGIdcc9PD9ZXmjvpyhbY0/lcww+UCp3+LP1yelYWpdbQQg5D4m4+JIyCyUwhwGuxMGPZR+bNmc2AVhlPQWj99WfT8EIOiAP7dYMFbc3HUHTt8F0RpGQns6zWhc3snUeMdkAWXF'
4priv = "2f9f54d3a8793c50af8c61d10f88856cfcad6297f33b910b7f1093846083e835"
5SM2CipherMode_C1C3C2_ASN1 = 0
6decrypt_plain = SM2DecryptWithMode(base64.b64decode(cipher), priv, SM2CipherMode_C1C3C2_ASN1)
7# 预期返回 SM2 Decrypt binary data, Plain is -------c6fafbae361863c146f0a1c27ff9c1a2
8print("SM2 Decrypt binary data, Plain is -------"+decrypt_plain.decode('utf-8'))

# 返回信息

# 文件格式说明

账单文件包括明细数据和汇总数据两部分,每一部分都包含一行表头和若干行具体数据。

明细数据每一行对应一笔资金操作,同时每一个数据前加入了字符,以避免数据被Excel按科学计数法处理。如需汇总金额等数据,可以批量替换掉该字符。

# 示例文件

单个子商户资金账单: 解密后的资金账单示例 (opens new window)

电商平台二级商户资金账单: 解密后的账单示例 (opens new window)

# 错误码

# 公共错误码

状态码 错误码 描述 解决方案
400 PARAM_ERROR 参数错误 请根据错误提示正确传入参数
400 INVALID_REQUEST HTTP 请求不符合微信支付 APIv3 接口规则 请参阅 接口规则
401 SIGN_ERROR 验证不通过 请参阅 签名常见问题
500 SYSTEM_ERROR 系统异常,请稍后重试 请稍后重试

# 业务错误码

状态码 错误码 描述 解决方案
400 INVALID_REQUEST 参数错误 请按第一步申请账单的API指引,重新获取账单地址后再请求
403 NO_AUTH 权限异常 请检查本次请求的商户是否与第一步申请账单API的请求商户一致