17 个接口 + 2 套环境骨架,V2 接口自动签名。环境变量全部留空,导入后自己填。
下载 tax-rpa-bruno-collection.zip 20 KBSHA-256 5cf6ee4b607cf3e07b6e289c514bea8f5241c0f88a520fbf6bbb64fb6430aa40
Bruno 是一个开源的 API 客户端,作用和 Postman、Insomnia 类似:管理请求、切换环境、 发请求看响应。区别在于两点,正好是我们把它选成联调工具的原因:
.bru),一个接口一个文件,可以直接进 Git、能 diff、能 review。下面是装好我们的接口包之后的样子:左边是按业务分好组的 17 个接口, 右边是集合自带的说明文档。

和文档站的分工
文档站回答"这个字段是什么意思、边界在哪",Bruno 回答"我现在能不能打通"。 两边的接口定义出自同一份 openapi.yaml,不会各说各话。
免安装 / 免注册,下载解压即可用。
本次构建未包含桌面端安装包,请到 Bruno 官网 下载,或联系平台获取。
这是第三方软件
Bruno 由 Bruno 团队开发,平台只是转发官方发行包,未作任何修改。 你也可以直接从 Bruno 官网 下载, 版本不限,接口包对版本没有要求。
接口包就是那 17 个接口的定义,由平台的 openapi.yaml 生成。 两种拿法,按你的情况选一种就行。
拿通用包,导入后自己填环境变量。适合要把包提交进自己仓库、 或者多人共用一份定义的场景。
17 个接口 + 2 套环境骨架,V2 接口自动签名。环境变量全部留空,导入后自己填。
下载 tax-rpa-bruno-collection.zip 20 KBSHA-256 5cf6ee4b607cf3e07b6e289c514bea8f5241c0f88a520fbf6bbb64fb6430aa40
解压后在左侧 Collections 面板点 ⋮ 选 Open collection, 选中解压出来的 税务发票数据开放平台 目录:

是 Open 不是 Import
Open collection 直接打开磁盘上的目录,改动落回文件、可以进版本库。 Import collection 是给 Postman 等外部格式用的,这里不要选。
右上角切换 测试环境 / 生产环境:

点环境名进变量表,把下面几项填上。 Variables 页签是普通变量,Secrets 页签是密钥:

| 变量 | 填什么 | 在哪个页签 |
|---|---|---|
channelCode | 渠道编码,如 BANK | Variables |
externalOrderId | 你的业务订单号 | Variables |
orderNo | 订单查询返回的 job_id | Variables |
channelKey | 渠道 API Key | Secrets |
callbackSecret | Callback Secret,签名用 | Secrets |
secret 变量不落文件
Bruno 把 Secrets 页签里的值存在本机,不写进 .bru 文件。 所以默认版接口包可以安全地提交进你自己的 Git 仓库。
在下面填好你自己的参数,浏览器当场打包 —— 解压导入后环境已经配好, 不用再手工填一遍。
默认不写。两项会作为 Bruno 的 secret 变量留空,导入后在 Bruno 里填, 存本机不进文件 —— 这样生成的包可以安全地传给同事或提交进 Git。
生成过程全在本地
zip 是在你的浏览器里用集合模板拼出来的,参数和密钥不会上传到任何地方。
导入方式和默认版一样:Open collection 选中解压出来的目录。区别只是 环境变量已经预填好,如果没勾选"把密钥写进包里",就只剩 channelKey 和 callbackSecret 两项要在 Secrets 页签补上。
V2 那三个发票交付接口强制签名,/api/channel/data/* 在渠道启用强制签名时也要签。 集合级的 pre-request 脚本会自动处理,你不需要手工算 HMAC:
// collection.bru(节选)
const canonical = [timestamp, nonce, method, url.pathname, rawQuery, bodyHash].join('\n');
const signature = CryptoJS.HmacSHA256(canonical, secret).toString(CryptoJS.enc.Hex);
req.setHeader('X-Channel-Timestamp', timestamp);
req.setHeader('X-Channel-Nonce', nonce);
req.setHeader('X-Channel-Signature', 'sha256=' + signature);几个实现上的取舍,出问题时值得知道:
openapi.yaml 推导, 不是硬编码。callbackSecret 会直接抛错,而不是发出去等 401。/api/channel/data/*)只在填了密钥时才签 —— 渠道处于 OPTIONAL 模式时只带 Key 也能调,不强迫你配密钥。算法细节见鉴权与签名。
flowchart LR
A[创建授权链接] --> B[浏览器打开 authorization_url]
B --> C[查询订单<br/>拿 job_id]
C --> D[填进 orderNo]
D --> E[查询产品状态]
E --> F[取数 / 下载报告]authorization_url 复制到浏览器完成授权。state 变成 SUCCESS,把 job_id 填进环境变量 orderNo。state=SUCCEEDED 且 available=true。Bruno 有命令行版,可以把联调集合直接当回归用例跑:
npm i -g @usebruno/clibru run --env 测试环境 --env-var channelKey=$RPA_CHANNEL_KEY --env-var callbackSecret=$RPA_CALLBACK_SECRET凭据从 CI 的 secret 注入,不写进任何文件。
| 你要做的事 | 去哪 |
|---|---|
| 查字段含义、取值范围、边界 | 接口参考 与数据说明 |
| 看一眼某个接口返回长什么样 | 接口参考页的 Test Request |
| 正式联调、切生产、跑回归 | Bruno |
为什么在线调用不推荐用于生产
浏览器发起的请求受同源策略约束,要求目标环境把文档站的源加进 RPA_CORS_ORIGINS; 而且要把渠道 Key 敲进网页。测试环境用它很方便,生产环境建议只走 Bruno。