⑧ 下载发票
单独下载某张发票文件。日常查结果(⑤)带 withInvoice 就够了,这个用于补下载、单独取票。数据类接口。
属「工商银行 · 业务型接口」——底层编排 乐企直联原子接口,你只调这一个。
下载发票
接口 · 下载发票(数据类)
POST https://openapi.kailingteck.com/api/v1/rinv/invoice/download
鉴权:X-App-Key + X-Timestamp + X-Sign(= sha256(appKey + 时间戳 + 报文 + appSecret))。
请求参数
| 字段 | 必填 | 大白话说明 |
|---|---|---|
orderId | 必填 | 订单号 |
invoiceFormat | 选填 | 格式:1 ofd / 2 pdf / 3 xml(默认 2) |
isRedOrblue | 选填 | 01 蓝票 / 02 红票(默认 01) |
请求示例
{
"orderId": "ORD1",
"invoiceFormat": "2",
"isRedOrblue": "01"
}返回
所有接口都用同一层信封:code/msg/requestId/timestamp/data。业务字段都在 data 里,下表列的就是 data 的内容。code 为 CYT_00000 表示调用成功。
返回参数(data)
| 字段 | 大白话说明 |
|---|---|
orderId | 回显订单号 |
byteData | ★票文件的 base64,解一次码就是文件本体(2026-09-16 起网关已把工行返回的双层编码解掉一层;此前自行按文件头做过双层兼容的接入方不受影响) |
format | 票文件格式:1 ofd / 2 pdf / 3 xml |
raw | 工行原始全字段 |
返回示例(成功)
{
"code": "CYT_00000",
"data": {
"orderId": "ORD1",
"byteData": "JVBERi0xLjQK……(base64)",
"format": "2",
"mock": false,
"raw": { }
}
}异常与报错
| 情形 | 含义与处理 |
|---|---|
| byteData 为空 | 这一单还没开票成功,先用⑤确认 status=done |
| 要红票 | 传 isRedOrblue=02;红冲后才有红票 |
前端怎么用
// data.byteData 是 base64,前端解码成文件下载 const blob = b64toBlob(res.data.byteData, 'application/pdf');
上传重试
接口 · 上传重试(数据类)
POST https://openapi.kailingteck.com/api/v1/rinv/invoice/uploadRetry
鉴权:X-App-Key + X-Timestamp + X-Sign(= sha256(appKey + 时间戳 + 报文 + appSecret))。
请求参数
| 字段 | 必填 | 大白话说明 |
|---|---|---|
orderId | 必填 | 上传失败那一单的订单号 |
userId | 选填 | 收款散户ID(收方编号)。不传时平台按订单号自动查出来补上,一般不用传 |
vendorId | 选填 | 企业子商户编号(付方编号)。不传时同上自动补齐,或取后台配置 |
请求示例
{
"orderId": "ORD1"
}返回
所有接口都用同一层信封:code/msg/requestId/timestamp/data。业务字段都在 data 里,下表列的就是 data 的内容。code 为 CYT_00000 表示调用成功。
返回参数(data)
| 字段 | 大白话说明 |
|---|---|
accepted | ★true=重试已受理;false=没受理,看 uploadFailReason |
uploadStatus | 工行上传状态:02 已受理 / 05 上传失败 |
uploadFailReason | 上传失败的原始原因(如「他用或联用企业开票人未授权开票」) |
raw | 工行原始返回 |
返回示例(成功)
{
"code": "CYT_00000",
"msg": "success",
"data": {
"orderId": "ORD1",
"accepted": true,
"uploadStatus": "02",
"mock": false
}
}前端怎么用
const r = await post('/api/v1/rinv/invoice/uploadRetry', { orderId });
if (!r.data.accepted) alert(r.data.uploadFailReason); // 先修原因再重试仅支持反向蓝票。场景:⑤查结果 status=done_upload_failed(states.upload=05,上传税局失败)时,先把失败原因修掉——最典型的是开票人没在电子税务局做乐企授权,授权补齐后调这里重新上传,不用重新开票;受理后用⑤轮询,upload 变 02、status 变 done 后即可下载票文件。
所有接口通用的报错(平台层)
| HTTP / code | 含义与处理 |
|---|---|
400 · CYT_40001 | 必填参数没传,data.hint 里写了缺哪个 |
401 · CYT_40100 / 40102 | 缺鉴权头,或签名算错。签名 = sha256(appKey + 时间戳 + 报文原文 + appSecret),参与签名的报文必须与实际发送的逐字节一致 |
401 · CYT_40103 | 时间戳与服务器相差超过 300 秒,校准本机时间后重试 |
403 · CYT_40301 | 这把密钥的产品或渠道不对(工行接口需要「反向开票」产品 + 「工商银行」渠道) |
429 · CYT_42901 | 超过每分钟 120 次限流,稍后重试 |
502 · CYT_50200 | 工行侧暂时不可达。注意工行测试环境每晚 19:00 后关闭、次日恢复,联调请排在工作时间 |
200 · data.mock=true | 尚未配置工行凭据,返回的是演示数据、并未真调工行 |
