静态二维码指南
本指南说明如何通过 API 生成 PIX 静态二维码,以及为什么这是推荐的收款方式。
概览
静态二维码是可重复使用的代码:同一个 BR Code 可以接受多笔付款,来自不同付款 人、在不同时间。金额可以固定,也可以开放(由付款人在银行 App 中输入)。它适用于:
- 收银场景 —— 柜台上的牌子或贴纸、自助终端、餐桌
- 非正式的周期性收款 —— 月费、租金、会费
- 捐赠与小费 —— 开放金额,由付款人决定
- 固定支付链接 —— 不随订单变化的"在此付款"页面
如果您需要的是一次性收款,带有确定金额、有效期,并与订单一一对账,请使用 动态二维码。
按照 PIX 规范、仅凭您的密钥自行拼装静态 EMV/BR Code 字符串在技术上是可行的。款项 确实会入账,入账通知也会送达——但您将失去把付款与收款单据串联起来的那根线,也没有 查询、没有取消、没有策略。下一节会具体说明失去的是什么。
为什么要通过 API 生成
通过 API 创建的静态二维码天生带有属于您的 identifier,它在我们这里经过校验,
并登记在清算行。该标识符是把整笔付款串起来的那根线:它会出现在 webhook、对账单和
查询结果中。
在外部拼装的 BR Code 没有在任何地方登记这根线。款项会入账,webhook 也会发出,但其中 携带的标识符只取决于您在代码里嵌入了什么——如果确实嵌入了的话;除了钱本身,该二维码 在我们这边不存在任何记录。
| 通过 API 创建的二维码 | 您自行拼装的 BR Code | |
|---|---|---|
qrcode.paid webhook | 会收到,带有您的 identifier | 会收到,带有您嵌入的 txid——或者该字段为空 |
pix.in.completed webhook | 会收到,带有您的 identifier | 同上 |
| 对账单 | 流水条目带 identifier | 只有嵌入过 txid 才会带标识符 |
| 二维码查询 | GET .../pix/qr-code/lookup?identifier= 可用 | 根本不存在可查询的二维码 |
| 取消 | DELETE 让该代码停止流通 | 无法通过 API 取消 |
| 策略 | 创建时评估 qrCode 板块的规则 | 不评估任何规则 |
| 标识符冲突 | identifier 经过校验并登记 | txid 完全自由,可能与您某笔收款单据的标识符冲突 |
标识符成了一场赌博
清算行会把 BR Code 中嵌入的 txid 作为该笔付款的 identifier 回传。如果您在拼装时
放入了自己的 txid,它确实会出现在 webhook 和对账单中,这根线也确实能用。问题在于,
这个值从未经过我们的校验(38 个字符、[A-Za-z0-9._-] 字符集、保留前缀 fee-),在
我们这边也不对应任何二维码。一旦它恰好与同一账户下某个动态二维码的 identifier
相同,这笔付款就会被归到那笔收款单据上,导致该单据显示为已支付。
不过更常见的情形是:静态 BR Code 的 txid 字段填的是 ***——规范中为"无标识符"预留的
占位符。此时付款到达时根本不带任何标识符。两个 webhook 依然会发出,只是 identifier
为空,而唯一的对账方式只能是靠金额、时间和付款人做近似匹配。
我们这边不存在的东西
由于该二维码从未在我们这里创建,也就没有任何记录。按 identifier 查询什么都找不到,
DELETE 也没有可取消的对象——想让代码停止流通,只能去把印刷的牌子收回来。qrCode
策略板块的规则同样不会被评估,因为根本没有"创建"这个动作可供评估。而且没有人会核对
嵌入的密钥是否属于该账户、EMV 是否拼装正确:格式有误的代码只会在付款人的银行 App 中
失败,而您要等到客户来投诉才会知道。
API 无法"接管"在外部生成的代码。
POST /v1/accounts/{accountId}/pix/out/qr-code/decode 可以解码 BR Code,但它的用途
是支付他人的二维码,而不是登记您自己的收款二维码。如果二维码已经在外部拼装并
印刷流通,唯一的出路是通过 API 生成新的并予以替换。
选静态还是动态?
| 静态 | 动态 | |
|---|---|---|
| 路由 | POST .../pix/qr-code/static | POST .../pix/qr-code/dynamic |
| 金额 | 可选(省略即为开放金额) | 必填,且大于零 |
| 有效期 | 永不过期 | expirationDate(清算行默认:1 天) |
| 付款次数 | 同一代码可多次 | 一次 |
| 限定付款人 | 否 | allowedPayerTaxNumber |
| 过期 webhook | 不适用 | qrcode.expired |
| 典型用途 | 柜台、捐赠、月费 | 结账、发票、订单 |
第一步:创建静态二维码
请求
curl -X POST "https://tenant.api.corpx.com/v1/accounts/{accountId}/pix/qr-code/static" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: {tenant_id}" \
-H "Content-Type: application/json" \
-d '{
"pixKey": "your-pix-key-here",
"value": 49.90,
"identifier": "store-downtown-register-01"
}'
请求体参数
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
pixKey | string | 是 | 收款账户的 PIX 密钥(必须已注册) |
value | number | 否 | 固定金额(BRL)。省略或填 0 会创建开放金额二维码,由付款人输入金额 |
identifier | string | 建议填写 | 您为该二维码指定的标识符(最多 38 个字符,字符集 [A-Za-z0-9._-],不能以 fee- 开头)。省略时由 API 生成不含连字符的 UUID |
message | string | 否 | 最多 140 个字符的消息。请参见下方提示 |
message 不会进入静态 BR Code该字段会被接收并校验,但目前在创建静态二维码时不会转发给清算行——付款人看不
到它,响应中的 message/description 也不会被填充。如果您需要在收款中显示文字,
请使用会转发该消息的动态二维码。
identifier该标识符是您的对账键,并会在该二维码的每一笔付款中回传。在静态二维码中,它标识的
是收款点而非某一笔交易:store-downtown-register-01、table-14、
website-donation。这样当三笔付款到账时,您能分清各自来自哪块牌子。
成功响应 (201 Created)
{
"txid": "store-downtown-register-01",
"emv": "00020126580014br.gov.bcb.pix0136d2e1c0a4-8f5b-4c7e-9a1d-6b3f2e8c7a5052040000530398654049.905802BR5912YOUR COMPANY6004Lins62070503***6304A1B2",
"type": "static",
"status": "ACTIVE",
"value": 49.90,
"identifier": "store-downtown-register-01",
"accountId": "{accountId}",
"pixKey": "8026ff12-cb4a-4d19-9638-08bb15d450e2",
"allowChange": false,
"createdAt": "2026-02-10T12:00:00Z"
}
data 信封响应是扁平对象(顶层)。没有 data 信封,也没有
statusCode/title/message 字段。复制粘贴码在 emv 中,密钥在 pixKey 中。
| 字段 | 描述 |
|---|---|
emv | PIX 复制粘贴码(EMV 字符串)。请渲染为二维码 |
identifier | 您提交的标识符(或由 API 生成的) |
txid | 与 identifier 相同——静态二维码中两者取值一致 |
type | 该端点固定为 static |
status | 创建时为 ACTIVE |
value | 固定金额;开放金额二维码时为 0 |
allowChange | 付款人可修改金额时为 true |
请注意没有 expiresAt:静态二维码不会过期,在您取消之前一直有效。
API 不会按 identifier 对创建请求去重——该端点没有 Idempotency-Key 处理。在重新
创建一个可能已存在的二维码之前,请先用查询接口确认(第四步)。使用已占用的标识符
重新创建,其结果取决于清算行的响应,可能因冲突而失败。
第二步:展示二维码
用任意二维码库(qrcode.js、python-qrcode 等)根据 emv 字符串生成图片,同时提
供复制粘贴框:
<input type="text" value="00020126580014br.gov.bcb.pix..." readonly />
<button onclick="navigator.clipboard.writeText(this.previousElementSibling.value)">
复制
</button>
由于静态二维码不会过期,该图片可以打印、贴在牌子上或发布到网站——在二维码被取消之 前始终有效。
第三步:通过 Webhook 接收付款
该二维码收到的每一笔付款都会触发两个事件,且两者都带有您的 identifier:
qrcode.paid—— "我创建的二维码被支付了"(收款对账)pix.in.completed—— "我的账户已入账"(账务、余额、对账单)
您可以两个都订阅,也可以只订阅符合自身流程的那个;它们从不同角度描述同一笔钱。
qrcode.paid
{
"id": "qrcode-paid-E303062942026021014300000005ABCD",
"type": "qrcode.paid",
"occurredAt": "2026-02-10T14:30:12.000000000Z",
"schemaVersion": "1.0",
"environment": "production",
"tenantId": "tenant-yourcompany",
"accountId": "{accountId}",
"data": {
"qrcodeId": "store-downtown-register-01",
"identifier": "store-downtown-register-01",
"accountId": "{accountId}",
"tenantId": "tenant-yourcompany",
"type": "static",
"amount": 49.90,
"endToEnd": "E303062942026021014300000005ABCD",
"transactionId": "b7c1e0f2-3a4d-4e5f-8a9b-0c1d2e3f4a5b",
"status": "SUCCESS",
"receivedAt": "2026-02-10T14:30:12.000000000Z",
"payer": {
"name": "John Smith",
"document": "12345678901",
"bankIspb": "30306294",
"branch": "0020",
"account": "004912314"
},
"payee": {
"name": "YOUR COMPANY LTDA",
"document": "12345678000190"
}
}
}
在静态二维码中,qrcodeId 与 identifier 取值相同:即您在创建时选定的标识符。区分
不同付款的是 endToEnd。
同一个二维码被支付五次就会产生五个 qrcode.paid,各自带有自己的 endToEnd。不要把
第一个事件当作"收款已结清"就停止监听——该代码仍然有效。请用 endToEnd 作为您自己
入账记录的去重键。
静态二维码没有 qrcode.expired 和 qrcode.cancelled:它不会过期,而取消是您发起的
同步操作,其确认就是 DELETE 的 HTTP 响应。
第四步:对账
二维码的 identifier 会出现在您查找资金的两个地方:
在对账单中,每条流水都带 identifier 字段:
curl -X GET "https://tenant.api.corpx.com/v1/accounts/{accountId}/statement?from=2026-02-10&to=2026-02-10" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: {tenant_id}"
在付款查询中,可以直接按标识符检索:
curl -X GET "https://tenant.api.corpx.com/v1/accounts/{accountId}/pix/payments/lookup?identifier=store-downtown-register-01" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: {tenant_id}"
查询二维码状态
curl -X GET "https://tenant.api.corpx.com/v1/accounts/{accountId}/pix/qr-code/lookup?identifier=store-downtown-register-01" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: {tenant_id}"
响应与创建时相同,是同一个扁平对象;若已有付款,还会附带付款字段:
paidAmount、endToEndId、paidAt、payer。
在可重复使用的二维码上,查询反映的是清算行已知的最近一笔付款,首笔付款之后
status 就变为 PAID。它不会列出此前的付款。若需完整历史,请使用 qrcode.paid
webhook 或按时间段筛选的对账单。
可能的状态:ACTIVE、AWAITING-PAYMENT、PAID、CANCELLED、EXPIRED、
UNKNOWN —— 一律为大写。
第五步:取消二维码
静态二维码在被取消之前一直有效。当牌子撤下、收银台停用或活动结束时,请予以取消:
curl -X DELETE "https://tenant.api.corpx.com/v1/accounts/{accountId}/pix/qr-code?identifier=store-downtown-register-01" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: {tenant_id}"
响应 (200 OK):
{
"identifier": "store-downtown-register-01",
"status": "CANCELLED"
}
取消之后,已印刷的 BR Code 便无法再用于收款——扫码者会在银行 App 中收到错误。
策略
创建静态二维码会经过 tenant 或账户策略中的 qrCode 板块。违规时返回 422,
errorCode 为 policy_denied,并附带 violations 列表:
| 规则 | rule | 效果 |
|---|---|---|
| 创建静态码 | qrCode.canCreateStatic | 为 false 时拒绝创建 |
| 最小金额 | qrCode.minAmount | 拒绝金额低于下限的二维码 |
| 最大金额 | qrCode.maxAmount | 拒绝金额高于上限的二维码 |
金额规则不适用于开放金额二维码:创建时没有 value 就没有可比较的金额,两条规则
都会被跳过。如果您的金额管控必须始终生效,就不要使用开放金额二维码。详见
策略与规则。
所需范围
| 操作 | 范围 |
|---|---|
| 创建静态二维码 | qrcode.manage |
| 查询与取消 | qrcode.manage 或 read |
仅拥有 qrcode.manage 的凭证可以创建并跟踪二维码,而看不到账户的余额和对账单。参见
认证指南。
最佳实践
- 始终通过 API 生成 —— 在外部拼装 BR Code 会让您失去对账、查询和取消的能力
- 给收款点命名 —— 静态二维码的
identifier标识的是牌子/收银台/活动,而不是某一笔交易 - 按
endToEnd去重 —— 这是在同一个二维码上区分不同付款的依据 - 不要只依赖查询接口 —— 它只显示最近一笔付款;完整历史在 webhook 和对账单中
- 及时取消已撤下的二维码 —— 静态二维码不会自行过期
- 有策略金额限制时优先用固定金额 —— 开放金额二维码会跳过
minAmount/maxAmount规则
常见错误
错误格式为 { "errorCode": "...", "message": "..." }:
errorCode | HTTP | 原因 | 解决方案 |
|---|---|---|---|
missing_field | 400 | 缺少 pixKey | 请提交该账户已注册的密钥 |
invalid_identifier | 400 | identifier 超过 38 个字符、超出字符集 [A-Za-z0-9._-],或以 fee- 开头 | 调整标识符 |
invalid_field | 400 | message 超过 140 个字符 | 缩短消息 |
invalid_payload | 400 | JSON 格式错误 | 修正请求体 |
missing_param | 400 | 查询或取消时 query 中缺少 identifier | 提供 ?identifier=(别名:txid) |
not_found | 404 | 查询时未找到二维码 | 检查 identifier 和 accountId |
policy_denied | 422 | qrCode 板块的某条规则拒绝了创建 | 查看响应体中的 violations —— 策略与规则 |
partner_unavailable | 503 | 清算行不可用 | 请重试 |
示例:
{
"errorCode": "missing_field",
"message": "pixKey is required"
}
完整列表见错误。