⑤ 查开票结果
把工行的 5 个原始状态翻成一个业务态,给你发票号 + 税额;带 withInvoice=true 时顺带把票文件也取回来。数据类接口。
属「工商银行 · 业务型接口」——底层编排 乐企直联原子接口,你只调这一个。
接口(数据类)
POST https://openapi.kailingteck.com/api/v1/rinv/invoice/status
鉴权:X-App-Key + X-Timestamp + X-Sign(= sha256(appKey + 时间戳 + 报文 + appSecret))。
请求参数
| 字段 | 必填 | 大白话说明 |
|---|---|---|
orderId | 必填 | 你侧订单号(与④一致) |
withInvoice | 选填 | true=顺带把发票文件一起取回 |
invoiceFormat | 选填 | 票文件格式:1 ofd / 2 pdf / 3 xml(默认 2) |
vendorId | 选填 | 服务商ID |
userId | 选填 | 散户ID |
请求示例
{
"orderId": "ORD1",
"withInvoice": true,
"invoiceFormat": "2"
}返回
所有接口都用同一层信封:code/msg/requestId/timestamp/data。业务字段都在 data 里,下表列的就是 data 的内容。code 为 CYT_00000 表示调用成功。
返回参数(data)
| 字段 | 大白话说明 |
|---|---|
status | ★业务状态。waiting_confirm 待散户确认 → waiting_pay 待付款 → invoicing 开票中 → done 已完成;failed 开票失败;cancelled 已取消(⑦取消开票之后的终态);done_upload_failed 开票完成但上传税局失败(票文件下载不到,看顶层 uploadFailReason,修复后调⑧的「上传重试」);processing 处理中 |
invoiceCode | 发票号码(开出来才有) |
taxAmount | 合计税额(工行/税局算好的,不是我们算的)——这是发票票面上的增值税税额 |
taxRealAmount | ★实缴税费合计:工行实际代扣的全部税费总额,通常大于等于票面税额 taxAmount,差额是个税等非票面税费。财务对账用它 |
actuallyReceivedAmount | ★散户实际到手金额(付款金额扣完实缴税费后的净额,以工行返回为准) |
invoiceLevyItemResponse | ★税费征收分项明细(数组):每项含征收项目/品目名称与代码、计税依据 taxBasis、税率 taxRate、应缴税额 taxPayable、应补退税额 taxCreditPayable、税款所属期。回答「这张票各税种各扣了多少」就靠它 |
payAmount | 合计金额(票面含税) |
states.confirm | 工行原始:自然人确认状态 00 未确认 / 01 自然人已确认 / 02 全部确认完成 |
states.pay | 工行原始:支付状态 02 成功 |
states.invoice | 工行原始:开票状态 00 初始 / 01 开票中 / 02 成功 / 03 失败 |
states.upload | 工行原始:发票上传状态 04 上传成功 |
states.tax | 工行原始:缴税状态 04 缴税成功 |
invoice.byteData | base64 编码的票文件(只有 withInvoice=true 且已开票成功时才有) |
invoice.format | 票文件格式 |
raw | 工行预查询接口的原始全字段 |
返回示例(成功)
{
"code": "CYT_00000",
"msg": "success",
"data": {
"orderId": "ORD1",
"status": "done",
"invoiceCode": "26367200000123456789",
"taxAmount": "42.81",
"payAmount": "5018.35",
"states": {
"confirm": "02",
"pay": "02",
"invoice": "02",
"upload": "04",
"tax": "04"
},
"invoice": {
"byteData": "JVBERi0xLjQK……(base64)",
"format": "2"
},
"mock": false
}
}返回示例(失败 / 业务拦截)
// 开票失败
{
"code": "CYT_00000",
"data": {
"orderId": "ORD1",
"status": "failed",
"states": { "invoice": "03" }
}
}异常与报错
| 情形 | 含义与处理 |
|---|---|
| status 长期停在 waiting_confirm | 散户还没在工行侧确认这一票,需要引导散户去确认 |
| status 长期停在 waiting_pay | 老板还没付款。付款是扳机,不付不开票 |
| status=failed | 看 raw 里工行给的失败原因。常见:企业忘了在电子税务局手动下载一次发票、额度不足 |
| status=done_upload_failed / states.upload=05 | ★票开出来了但上传税局失败,票文件下载不到。看顶层 uploadFailReason;典型:「他用或联用企业开票人未授权开票」=开票人没在电子税务局做乐企授权——授权补齐后调⑧的「上传重试」重新上传即可,不用重新开票 |
| invoice 字段没有 | 要么没传 withInvoice=true,要么还没开票成功 |
前端怎么用
// 轮询直到 data.status === 'done' if (res.data.status === 'done') download(res.data.invoice.byteData);
税额是工行算好后取回的,平台不参与计算。五个原始状态都放在 states 里,排查时看它比看 status 更细。
所有接口通用的报错(平台层)
| 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 | 尚未配置工行凭据,返回的是演示数据、并未真调工行 |
