最新更新时间:2021.12.10 版本说明
微信支付按天提供微信支付账户的资金流水账单文件,服务商可以通过该接口获取子商户账单文件的下载地址。文件内包含子商户资金操作相关的业务单号、收支金额、记账时间等信息,供商户进行核对。
• 资金账单中的数据反映的是子商户微信账户资金变动情况;
• 当日账单在次日上午9点开始生成,建议商户在上午10点以后获取;
• 资金账单中涉及金额的字段单位为“元”;
• 该接口只能下载三个月以内的资金流水账单。
• 需提前在【服务商平台 -> 产品中心】开通“下载二级商户资金账单”产品权限。
适用对象:服务商 电商平台
请求URL:https://api.mch.weixin.qq.com/v3/bill/sub-merchant-fundflowbill
请求方式:GET
path指该参数为路径参数
query指该参数需在请求URL传参
body指该参数需在请求JSON传参
参数名 | 变量 | 类型[长度限制] | 必填 | 描述 |
---|---|---|---|---|
子商户号 | sub_mchid | string[1, 32] | 是 | query下载指定子商户的账单。 示例值:19000000001 |
账单日期 | bill_date | string[10, 10] | 是 | query格式yyyy-MM-dd 示例值:2019-06-11 |
资金账户类型 | account_type | string[1, 16] | 是 | query枚举值: BASIC:基本账户 OPERATION:运营账户 FEES:手续费账户 示例值:BASIC |
加密算法 | algorithm | string[1, 31] | 是 | query枚举值: AEAD_AES_256_GCM:AEAD_AES_256_GCM加密算法 SM4_GCM:SM4_GCM加密算法,密钥长度128bit 示例值:AEAD_AES_256_GCM |
压缩格式 | tar_type | string[1, 8] | 否 | query不填则以不压缩的方式返回数据流 枚举值: GZIP:返回格式为.gzip的压缩包账单 示例值:GZIP |
https://api.mch.weixin.qq.com/v3/bill/sub-merchant-fundflowbill?sub_mchid=19000000001&bill_date=2019-06-11&account_type=BASIC&algorithm=AEAD_AES_256_GCM&tar_type=GZIP
参数名 | 变量 | 类型[长度限制] | 必填 | 描述 |
---|---|---|---|---|
下载信息总数 | download_bill_count | int | 是 | 下载信息总数 示例值:1 |
+下载信息明细 | download_bill_list | array | 是 | 下载信息明细 |
{
"download_bill_count": 1,
"download_bill_list": [
{
"bill_sequence": 1,
"download_url": "https://api.mch.weixin.qq.com/v3/bill/downloadurl?token=xxx",
"encrypt_key": "a0YK7p+9XaKzE9N4qtFfG/9za1oqKlLXXJWBkH+kX84onAs2Ol/E1fk+6S+FuBXczGDRU8I8D+6PfbwKYBGm0wANUTqHOSezzfbieIo2t51UIId7sP9SoN38W2+IcYDviIsu59KSdyiL3TY2xqZNT8UDcnMWzTNZdSv+CLsSgblB6OKGN9JONTadOFGfv1OKkTp86Li+X7S9bG62wsa572/5Rm4MmDCiKwY4bX2EynWQHBEOExD5URxT6/MX3F1D3BNYrE4fUu1F03k25xVlXnZDjksy6Rf3SCgadR+Cepc6mdfF9b2gTxNsJFMEdYXbqL0W1WQZ3UqSPQCguK6uLA==",
"hash_type": "SHA1",
"hash_value": "79bb0f45fc4c42234a918000b2668d689e2bde04",
"nonce": "a8607ef79034c49c"
}
]
}
账单文件包括明细数据和汇总数据两部分,每一部分都包含一行表头和若干行具体数据。
明细数据每一行对应一笔资金操作,同时每一个数据前加入了字符,以避免数据被Excel按科学计数法处理。如需汇总金额等数据,可以批量替换掉该字符。
当子商户资金账单文件太大(未压缩情况下约大于16GB)时,微信支付会对账单文件进行分割,此时接口会返回多个下载地址。商户分别根据下载地址下载账单文件并解密。解密后,将多个文件按账单文件序号(变量名:bill_sequence)的顺序合并为完整的资金账单文件。
商户需要注意,当返回多个下载地址时,商户依然需要在下载地址有效时间内发起下载请求。因此建议商户获取到下载地址后,并发请求下载。
子商户资金账单文件采用商户指定的加密算法(支持AES-256-GCM算法和SM4-GCM算法)进行加密,商户需要进行解密才能得到账单明文。解密流程是:
步骤1 下载账单文件,得到账单文件密文ciphertext;
步骤2 使用商户证书私钥解密从接口获取的加密密钥(变量名:encrypt_key)得到密钥明文key;
步骤3 利用步骤一、二中得到的账单密文ciphertext,密钥key和接口返回的随机字符串nonce解密账单,得到账单明文。
GCM即可以进行加密,又可以对信息的完整性进行校验,因此基于GCM加密的账单,解密成功则表示账单完整性校验通过。
基于AES-256-GCM算法加密的账单文件解密代码示例
账单文件解密代码示例请参考[WechatPay-API-v3 证书和回调报文解密],注意:返回的账单文件是二进制密文,需以字节数组形式处理,不需要进行Base64解码。
下面对解密代码中使用的参数进行说明:
{
// 密文
"ciphertext": "下载得到的账单文件密文",
// 加密使用的密钥
"key": "用商户证书私钥解密加密密钥得到的明文",
// 加密使用的随机字符串
"nonce": "接口返回的随机字符串",
// 附加数据包(填空)
"associated_data": ""
}
基于SM4算法加密的账单文件解密代码示例
with open(r"./ciphertext", 'rb') as f:
ciphertext_tag_bytes = f.read()
ciphertext_tag_hex = binascii.b2a_hex(ciphertext_tag_bytes)
# 账单密文最后16字节是消息验证码
ciphertext_bytes = binascii.unhexlify(ciphertext_tag_hex[:-32])
tag_bytes = binascii.unhexlify(ciphertext_tag_hex[-32:])
key="cbf063b0b33781c3"
key_bytes = str.encode(key)
iv="09ba90b74310"
iv_bytes = str.encode(iv)
aad = ''
# 账单明文
decrypt_plain = SM4_GCM_Decrypt_NoPadding_NIST_SP800_38D(ciphertext_bytes, key_bytes, iv_bytes, aad, tag_bytes)
RSA-2048加解密
如果HTTP头的Authorization的认证类型采用WECHATPAY2-SHA256-RSA2048, 则从接口获取的加密密钥(变量名:encrypt_key)是使用商户证书公钥进行RSA加密返回的密文,商户需解密后才能得到密钥原文。
解密流程如下:对encrypt_key先做Base64解码,然后对解码结果使用商户证书私钥进行RSA解密,指定填充方式为最优非对称加密填充(OAEP)。
下面我们使用命令行演示如何解密,更多的示例可以参考[WechatPay-API-v3 敏感信息加密]。
解密AES密钥得到key:
# 解密AES密钥得到key:
$ 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。
# 解密AES密钥得到key
SM2Init()
cipher = 'MIGKAiEA4FdfXZIG9oaS4v0CrCcFWAhQR0mR04cwZwFqP6lWwfACIQCGIdcc9PD9ZXmjvpyhbY0/lcww+UCp3+LP1yelYWpdbQQg5D4m4+JIyCyUwhwGuxMGPZR+bNmc2AVhlPQWj99WfT8EIOiAP7dYMFbc3HUHTt8F0RpGQns6zWhc3snUeMdkAWXF'
priv = "2f9f54d3a8793c50af8c61d10f88856cfcad6297f33b910b7f1093846083e835"
SM2CipherMode_C1C3C2_ASN1 = 0
decrypt_plain = SM2DecryptWithMode(base64.b64decode(cipher), priv, SM2CipherMode_C1C3C2_ASN1)
# 预期返回 SM2 Decrypt binary data, Plain is -------c6fafbae361863c146f0a1c27ff9c1a2
print("SM2 Decrypt binary data, Plain is -------"+decrypt_plain.decode('utf-8'))
状态码 | 错误码 | 描述 | 解决方案 |
---|---|---|---|
500 | SYSTEM_ERROR | 系统错误 | 系统异常,请使用相同参数稍后重新调用 |
403 | NO_AUTH | 权限异常 | 请检查sub_mchid是否为服务商的子商户 |
403 | NO_AUTH | 权限异常 | 请电商平台在产品中心开通下载二级商户资金账单产品权限 |
400 | PARAM_ERROR | 参数错误 | 请使用正确的参数重新调用 |
400 | INVALID_REQUEST | 参数错误 | 请检查bill_date,仅支持下载3个月以内的资金流水账单 |
400 | NO_STATEMENT_EXIST | 请求的账单文件不存在 | 请检查二级商户在指定日期是否有资金操作 |
400 | STATEMENT_CREATING | 账单生成中 | 请先检查二级商户在指定日期内是否有资金操作,若有,则在T+1日上午10点后再重新下载 |
429 | FREQUENCY_LIMITED | 请求过于频繁 | 请降低调用频率 |