工商银行 · 业务型接口(推荐)
对标腾讯的「支付及开票」——把工行那 19 个原子接口收成 8 个业务动词。反开系统日常只调这 8 个; 工行的复杂(签名/加密/多步编排/状态翻译)全由开灵中台在内部消化。要精细控制才下沉到 原子接口(乐企直联)。
给你的 AI 用 · 一键接入
把「AI 接入包」整份复制给你的 AI(Claude / Cursor / 通义),它就能照着写出这 8 个接口的全套对接代码。 工行的签名与加密全在开灵中台,你只需按包里第 1 节做一次简单签名。
不想写代码先试试?点在线调试台,填上密钥就能当场调通、看到工行真实返回,零安装。
泳道图 A · 散户入驻(要做两步:先刷脸、再建档,缺一不可)
看 蓝色粗线 = 反开系统调的业务接口(就 2 下);细线 = 开灵中台内部替你调的工行接口。★ 实名 → 查额度 → 建档 这条依赖顺序,埋在「查散户状态」里自动跑。
依赖铁律(文档定死):查额度用 outUserId 当钥匙、不收身份证,所以必须先扫脸实名(绑定 outUserId↔身份证)才能查 500 万;额度不够就不建档,不浪费。
泳道图 B · 每卖一票(反开系统调 2 次)
反开系统就 转账并开票 → 查开票结果 两下,和调腾讯 transfer_apply / transfer_status 一个感觉。查额度/下单/付款/查状态全在开灵内部。
税额是"取回来的",不是"算出来的":算税 / 缴税 / 合规校验全由国家税务总局乐企平台完成,开灵中台不自算——只把开票明细传上去、把工行算好的税额取回来展示。
8 个业务动词(19 原子 → 8 业务)
| # | 业务动词 | 对标腾讯 | 内部工行接口 | 一句话 |
|---|---|---|---|---|
| 1 | 企业开通 | 服务商授权 | #1 | 拿授权链接 |
| 2 | 散户入驻·第一步 发起扫脸 | 用户实名 | #2 | 拿扫脸链接给散户本人刷脸 |
| 2之二 | ★ 散户入驻·第二步 建收款人档案 | — | #4 | 报姓名/身份证/银行卡建档。刷脸≠入驻,这一步不做工行侧没有这个收方 |
| 3 | 查散户状态 | — | #3+#5+#6 | 实名/入驻/额度 一把梭,只查不建;canInvoice=false 时看 blockedBy 定位卡点 |
| 4 | ★ 转账并开票 | transfer_apply | #6闸门+#7+#8 | 传{散户,金额,明细,单号}→拿付款链接 |
| 5 | 查开票结果 | transfer_status | #10 / #9(+#11) | 5态→一个业务态+发票号;withInvoice 顺带取票 |
| 6 | 散户改卡 / 注销 | — | #12 / #13 | 维护 |
| 7 | 红冲 / 作废 | — | #15 / #17 | 异常冲红 |
| 8 | 下载发票 | — | #11 | 单独下票(常用已被 ⑤ 覆盖) |
唯一待工行确认:付款能不能走「场景支付」(企业 U盾预授权、直接扣款、不跳页)——支持则 ④ 能像腾讯一步完成,否则返回付款链接让老板点。
接口详情 · 请求 / 返回样例(8 个动词已 mock 联调通过)
{ "vendorId":"服务商ID", "leqiId":"乐企机构号", "authType":"01", "authNo":"授权人证件号", "jumpUrl":"完成后回跳地址" }{ "pageUrl":"https://…/redirect/xxx", "mock":false }页面类:前端 location.href = pageUrl,企业去电子税务局做税务授权。
{ "userId":"你侧散户唯一ID", "name":"张三", "idNo":"身份证号", "phone":"手机号", "jumpUrl":"回跳" }{ "pageUrl":"https://…/redirect/xxx", "transNo":"T1786630352940", "mock":false }把返回的 transNo 记下来 —— 查状态时用它查实名结果。
{ "userId":"散户ID", "name":"唐雪妮", "idNo":"身份证号", "phone":"手机号",
"bankCard":"收款卡号", "isIcbcCard":true, "idStartDate":"2015-06-18", "idEndDate":"2035-06-18" }{ "userId":"…", "accepted":true, "autoAudited":false, "hint":"已受理,等工行审核" }★刷脸只是实名认证,不等于已入驻。必须再做这一步把银行卡报给工行建档,否则工行侧不存在这个收方,④开票会被退回。非工行卡要另传 bankName 与 bankCode。受理后还要工行审核,用③轮询 onboarded。
{ "userId":"散户ID", "vendorId":"服务商ID", "transNo":"入驻返回的T号", "taxNo":"企业税号" }{ "realNamed":true, "onboarded":false, "blockedBy":"onboard",
"blockedReason":"自然人未在工行完成收方入驻(实名通过不等于已入驻)",
"receiverStatus":"…", "auditStatus":"…", "authorizeStatus":"…", "freezeStatus":"…",
"quota":{ "over500W":"…","overYear200W":"…","overYear210W":"…","overMonth10W":"…","backAmount":"…" },
"canInvoice":true, "raw":{…工行原始全字段} }一次拿到 实名 / 入驻 / 额度 / 审核 / 授权 / 冻结 全景。canInvoice = 已实名 且 已入驻 且 没撞额度红线;为 false 时看 blockedBy 定位卡在哪一步(realname / onboard / quota)。
{ "orderId":"你侧订单号", "userId":"散户ID", "vendorId":"服务商ID", "taxNo":"企业税号", "trxChannel":"03", "jumpUrl":"回跳" }成功:{ "orderId":"…", "canInvoice":true, "payUrl":"https://…/redirect/xxx" }
额度红线:{ "canInvoice":false, "reason":"额度红线,不可开票", "quota":{…} }内部:查额度闸门 → 预下单(带 goodsInfo 开票明细)→ 工行返回受理/支付页。老板付款后工行自动:开票 + 缴税 + 打款给散户。税额由工行/税局算,付款后从⑤取回,中台不自算。
{ "orderId":"你侧订单号", "withInvoice":true }{ "orderId":"…", "status":"done", "invoiceCode":"发票号", "taxAmount":"税额", "payAmount":"付款额",
"states":{ "confirm":"…","pay":"…","invoice":"…","upload":"…","tax":"…" },
"invoice":{ "byteData":"base64票文件" } }status:waiting_confirm → waiting_pay → invoicing → done(失败=failed)。withInvoice=true 顺带把票文件取回。税额是工行算好取回的,不是我们算的。
改卡:{ "userId":"…","vendorId":"…","bankCard":"新卡号","bankName":"…","bankCode":"…" }
注销:{ "userId":"…","vendorId":"…" }{ "userId":"…", "result":"处理结果", "raw":{…} }红冲:{ "orderId":"原订单号","amount":"金额","projectName":"项目名" }
作废:{ "orderId":"原订单号" }红冲(页面类):{ "pageUrl":"https://…/redirect/xxx" }
作废:{ "status":"…","result":"…","raw":{…} }红冲后个税 / 手续费由工行自动冲退,散户不吃亏。
{ "orderId":"订单号", "invoiceFormat":"2", "isRedOrblue":"01" }{ "orderId":"…", "byteData":"base64票文件", "format":"2" }单独下票用;日常查结果(⑤)带 withInvoice 就够了。
统一鉴权:X-App-Key + X-Timestamp + X-Sign(= sha256(appKey + 时间戳 + 报文 + appSecret))。 返回信封:{ code:"CYT_00000", msg, requestId, timestamp, data }。 当前工行凭据未配置时,data.mock=true 并返回占位;后台填好工行凭据后同一接口自动切真,无需改代码。
