Skip to content

Webhook 载荷

每种事件类型发送的 payload 示例。所有 webhook 都以 HTTP POST 发送,Content-Type: application/json

安全头

每个通知都包含 X-Owem-Signature(HMAC-SHA256)、X-Owem-TimestampX-Owem-Event-IdX-Owem-Event-Type 头。参见 Webhooks — 概述 了解验证的详细信息。


状态参考

并非所有事件都意味着交易已完成。使用下表了解何时资金实际结算。

事件状态含义资金已结算?
pix.charge.createdcreatedQR 码已生成或 cash-in 已启动。等待付款。 — 仅创建
pix.charge.paidpaidPIX 已接收并在账户中结算。余额已更新,手续费已收取。
pix.charge.expiredexpiredQR 码在未付款情况下过期。N/A
pix.charge.cancelledcancelledmerchant 在付款前明确取消了 QR 码。N/A
pix.payout.queuedqueued已发送的 PIX 由于速率限制(ClientLimiter 或 DICT bucket)入队。尚无借记。 — 等待配额
pix.payout.processingprocessingPIX 已发送,等待目的地确认。余额已保留(hold)。 — 可能撤销
pix.payout.confirmedsettledPIX 已发送并被目的地确认。最终借记。
pix.payout.failedrejectedPIX 已发送,被目的地拒绝。Hold 已释放,余额已恢复。
pix.payout.returnedreturned已发送的 PIX 在结算后退回。(反向)
pix.refund.requestedrequested已请求 PIX 退款(MED)。创建了预防性封锁。部分
pix.refund.completedsettled / completedPIX 退款已完成并结算。最终借记。
pix.return.receivedsettled收到 PIX 退款并已结算(在账户中贷记)。
pix.infraction.createdACKNOWLEDGED对您报告 PIX 违规。需要操作。部分 — 如果 >R$1k 则预防性封锁
pix.infraction.resolvedCLOSED / CANCELLED违规已解决(退款已执行或已拒绝)。N/A — 影响在其他事件中
pix.infraction.defense_submitteddefense_submittedmerchant 已提交抗辩。等待 BACEN。N/A
webhook.testtest通过 Admin/Merchant portal 手动触发的测试事件。N/A

对账规则

  • 仅在以下状态中考虑进入余额:paid(PIX IN 贷记)和 returned(先前发送的 PIX OUT 的反向)。
  • 仅在以下状态中考虑离开余额:settled(已确认的 PIX OUT 借记)、completed(最终 MED refund 借记)以及 pix.return.receivedsettled(先前收到的 PIX IN 的反向)。
  • 所有其他状态(createdqueuedprocessingrejectedexpiredrequestedACKNOWLEDGEDdefense_submitted 等)都是中间的 — 不会触发您那边的会计移动。
  • 不要将 pix.payout.processing 视为确认;等待终止事件(pix.payout.confirmedpix.payout.failed)。

公共字段

所有 webhook 载荷都包含这些字段:

字段类型描述
event_typestring触发 webhook 的事件类型(例:pix.charge.paid
statusstring操作状态 — 见 状态参考
account_idinteger您在 Owem 的账户号码
entity_idstring (UUID)Owem 实体标识符

货币值:所有值都以子分(1 BRL = 10.000 子分)。要转换为雷亚尔:值 / 10000。示例:300000 / 10000 = R$ 30,00


pix.charge.paid

在收到 PIX 并在账户中结算时发送。此事件确认资金已进入。

示例 — 与 QR 码关联

json
{
  "event_type": "pix.charge.paid",
  "status": "paid",
  "account_id": 10014,
  "amount": 300000,
  "fee_amount": 400,
  "end_to_end_id": "E9040088820260402095758709999671",
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "tx_id": "u5f26sfyrq4plkw7tjwa",
  "qr_code_id": "f401d5e3-a2b1-4c8e-9f3d-1234567890ab",
  "counterparty_name": "MARIA SANTOS",
  "payer_document": "12345678901",
  "payer_ispb": "60701190",
  "payer_bank_name": "Itau Unibanco S.A.",
  "external_id": "order-9876",
  "paid_at": "2026-04-02T09:58:05Z",
  "recipient_key": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "recipient_key_type": "evp",
  "receiver": {
    "name": "PENHOTA GESTAO E INTERMEDIACAO LTDA",
    "document": "62188010000150",
    "account": "0000000019",
    "ispb": "37839059",
    "institution_name": "OWEM PAY IP"
  }
}

示例 — 直接转账(无 QR)

json
{
  "event_type": "pix.charge.paid",
  "status": "paid",
  "account_id": 10014,
  "amount": 300000,
  "fee_amount": 400,
  "end_to_end_id": "E9040088820260402095758709999671",
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "tx_id": null,
  "qr_code_id": null,
  "counterparty_name": "JOAO SILVA",
  "payer_document": "98765432100",
  "payer_ispb": "00000000",
  "payer_bank_name": "Banco do Brasil S.A.",
  "external_id": null,
  "paid_at": "2026-04-02T10:15:22Z",
  "recipient_key": "12345678901",
  "recipient_key_type": "cpf",
  "receiver": {
    "name": "PENHOTA GESTAO E INTERMEDIACAO LTDA",
    "document": "62188010000150",
    "account": "0000000019",
    "ispb": "37839059",
    "institution_name": "OWEM PAY IP"
  }
}
字段类型描述
event_typestring始终为 pix.charge.paid
statusstring始终为 paid
account_idinteger收到 PIX 的账户号码
amountinteger收到的值,以子分。300000 = R$ 30,00
fee_amountinteger收取的手续费,以子分。400 = R$ 0,04
end_to_end_idstringBACEN E2E 标识符(每笔 PIX 交易唯一)
entity_idstring (UUID)Owem 实体标识符
tx_idstring 或 null交易 ID。与 QR 码关联时存在。直接转账时为 null
qr_code_idstring 或 null关联的 QR 码 UUID。直接转账时为 null
counterparty_namestring 或 null付款方(发送方)名称
payer_documentstring 或 null付款方 CPF/CNPJ(仅数字)
payer_ispbstring 或 null付款方机构的 ISPB(8 位数字)
payer_bank_namestring 或 null付款方机构名称,通过 BCB 缓存解析(896 家银行)
external_idstring 或 null您的外部标识符。当 QR 码通过带 external_id 的 API 创建时存在。直接转账或无 external_id 的 QR 时为 null
paid_atstring (ISO 8601)结算日期/时间(UTC)
recipient_keystring 或 null收到付款的 PIX 密钥(EVP、CPF、CNPJ、email 或电话)
recipient_key_typestring 或 null接收方 PIX 密钥类型:evpphoneemailcpfcnpj
receiverobject接收方(您)的完整数据。包括 namedocumentaccountispbinstitution_name

载荷变化:部署后对账

在少数情况下(后端 pod 在 webhook 发出前死亡、事件后回溯重放),worker PostDeployReconciliation 可能触发 pix.charge.paid,字段减少 — 通常没有 receiverpayer_ispbpayer_bank_namerecipient_keyrecipient_key_type始终存在的字段:event_typestatusaccount_idamountend_to_end_idfee_amountcounterparty_namepayer_documentexternal_idpaid_attx_id(与 QR 关联时)。

您的消费者应将所有非必需字段视为可选(nil/缺失),并通过 end_to_end_id 对账。

qr_code_id 是规范的 UUID v4

qr_code_id 字段始终以规范格式的 UUID v4 序列化(36 字符带连字符:f401d5e3-a2b1-4c8e-9f3d-1234567890ab)— 从不作为原始二进制、base64 或无连字符的十六进制。用于与 POST /api/external/pix/cash-in 响应直接关联(您请求中的 transaction_id 返回 QR 的 tx_id,这里的 qr_code_id 是内部主键)。


pix.charge.expired

QR 码在未付款情况下过期时自动触发。由 worker QrExpirationChecker 执行,cron */5 * * * *(每 5 分钟一次,针对 expires_at 已过的 QR 码)。

json
{
  "event_type": "pix.charge.expired",
  "status": "expired",
  "account_id": 10014,
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "tx_id": "abc123def456ghi789",
  "amount": 500000,
  "external_id": "order-9876",
  "expired_at": "2026-04-02T14:30:00Z"
}
字段类型描述
event_typestring始终为 pix.charge.expired
statusstring始终为 expired
account_idinteger发出 QR 码的账户
entity_idstring (UUID)Owem 实体标识符
tx_idstring收款/QR 码 ID
amountinteger预期值,以子分(未收取)
external_idstring 或 null您的外部标识符,如果在创建时发送
expired_atstring (ISO 8601)worker 检测到过期的时刻(UTC)— 可能比 QR 的真实 expires_at 晚 ~5 分钟

pix.charge.cancelled

在 QR 码被 merchant 在付款前通过门户操作(后端:Fluxiq.UseCases.Pix.QRCodes.cancel_qrcode/2)明确取消时发送。在自动过期(使用 pix.charge.expired)或付款(pix.charge.paid)时不触发。

json
{
  "event_type": "pix.charge.cancelled",
  "status": "cancelled",
  "tx_id": "abc123def456ghi789",
  "amount": 500000,
  "account_id": 10014,
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "external_id": "order-9876",
  "cancelled_at": "2026-04-23T12:30:00Z"
}
字段类型描述
tx_idstring收款/QR 码 ID
amountinteger预期值,以子分(未收取)
external_idstring 或 null您的外部标识符,如果在创建时发送
cancelled_atstring (ISO 8601)取消生效的时刻(UTC)

cancelled、expired 和 paid 之间的区别

  • pix.charge.cancelled:merchant 在付款前有意取消
  • pix.charge.expired:QR 生命周期耗尽(worker QrExpirationChecker 每 5 分钟)
  • pix.charge.paid:收款成功结算

pix.charge.created

在 QR 码生成或 cash-in 启动时发送。没有财务移动发生。

json
{
  "event_type": "pix.charge.created",
  "status": "created",
  "account_id": 10014,
  "amount": 500000,
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "tx_id": "abc123def456ghi789",
  "external_id": "order-9876"
}
字段类型描述
event_typestring始终为 pix.charge.created
statusstring始终为 created
amountinteger预期值,以子分
tx_idstring收款/QR 码 ID
external_idstring 或 null您的外部标识符,按发送原样返回。未提供或通过门户生成的 QR 时为 null

pix.payout.confirmed

在已发送的 PIX 被目的地机构确认时发送。最终借记。

json
{
  "event_type": "pix.payout.confirmed",
  "status": "settled",
  "account_id": 10014,
  "amount": 500000,
  "fee_amount": 200,
  "end_to_end_id": "E3783905920260402101500000001",
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "transaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "external_id": "payment-456",
  "pix_key": "destinatario@email.com",
  "pix_key_type": "EMAIL",
  "description": "Pagamento fornecedor",
  "initiated_at": "2026-04-02T10:14:59Z",
  "recipient": {
    "name": "EMPRESA DESTINO LTDA",
    "document": "12345678000199",
    "ispb": "60701190",
    "account": "12345678",
    "agency": "0001",
    "institution_name": "Itau Unibanco S.A."
  },
  "sender": {
    "name": "MINHA EMPRESA LTDA",
    "document": "98765432000100",
    "ispb": "37839059",
    "account": "00001234",
    "agency": "0001"
  }
}
字段类型描述
event_typestring始终为 pix.payout.confirmed
statusstring始终为 settled — 最终借记
amountinteger发送值,以子分
fee_amountinteger收取的手续费,以子分
end_to_end_idstringBACEN E2E 标识符
transaction_idstring (UUID)交易唯一标识
external_idstring 或 null您的外部标识符
pix_keystring收款方 PIX 密钥
pix_key_typestring密钥类型:CPFCNPJEMAILPHONEEVP
descriptionstring 或 null发送方填写的描述
initiated_atstring (ISO 8601)此 webhook 触发的时刻(UTC)。不是 cash-out 原始 request 或 BACEN settlement 的时间戳。要与您发送 POST 的时刻关联,请使用 GET /api/external/transactions/ref/{external_id}created_at;对于 webhook 投递的确切时刻,请使用头 X-Owem-Timestamp
recipientobject收款方的银行数据(通过 DICT 解析)
recipient.namestring 或 null目标账户持有人姓名
recipient.documentstring 或 null收款方 CPF/CNPJ(仅数字)
recipient.ispbstring 或 null目标机构的 ISPB
recipient.accountstring 或 null目标账户号码
recipient.agencystring 或 null目标账户分行
recipient.institution_namestring 或 null目标机构名称(通过 BCB 缓存解析)
senderobject发送方账户(您的 Owem 账户)的银行数据
sender.namestring 或 null发送方账户持有人姓名
sender.documentstring 或 null发送方 CPF/CNPJ(仅数字)
sender.ispbstring 或 nullOwem Pay 的 ISPB(37839059
sender.accountstring 或 null发送方账户号码
sender.agencystring 或 null发送方账户分行

pix.payout.processing

在已发送的 PIX 正在处理时发送。余额已保留(hold)但不是最终的。此事件是可选的 — 如果您只想在终止状态时通知,请忽略它并等待 pix.payout.confirmedpix.payout.failed

载荷字段与 pix.payout.confirmed 相同,但 status: "processing" — 余额已保留,可能撤销。

事件顺序

pix.payout.processing 始终跟随(几秒到几分钟后)pix.payout.confirmedpix.payout.failed。在快速交易中(立即结算),processing 可能被省略,您直接收到终止事件。


pix.payout.failed

在发送的 PIX 被拒绝时发送。Hold 已释放,余额已恢复。

2026-04-10 更新

载荷包含结构化字段 reason_code(BACEN SPI 代码 2-6 字符)和 reason_description(英文描述)。新集成应使用这些字段进行故障的程序化路由。

互斥:当后端可以从拒绝中提取 BACEN 代码(例:"rejected: AC03")时,载荷仅发送 reason_code + reason_description — 遗留字段 reason移除。当故障没有可解析的 BACEN 代码(例:内部超时、无代码的 provider 错误)时,载荷仅发送 reason(自由字符串)— 没有 reason_code。在您的消费者中处理两种格式。

json
{
  "event_type": "pix.payout.failed",
  "status": "rejected",
  "account_id": 10014,
  "amount": 500000,
  "fee_amount": 200,
  "end_to_end_id": "E3783905920260402101500000001",
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "transaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "external_id": "payment-456",
  "pix_key": "destinatario@email.com",
  "pix_key_type": "EMAIL",
  "description": "Pagamento fornecedor",
  "initiated_at": "2026-04-02T10:14:59Z",
  "reason_code": "AC03",
  "reason_description": "Invalid creditor account number",
  "reason": "Conta destinatario nao encontrada",
  "recipient": {
    "name": "EMPRESA DESTINO LTDA",
    "document": "12345678000199",
    "ispb": "60701190",
    "account": "12345678",
    "agency": "0001",
    "institution_name": "Itau Unibanco S.A."
  },
  "sender": {
    "name": "MINHA EMPRESA LTDA",
    "document": "98765432000100",
    "ispb": "37839059",
    "account": "00001234",
    "agency": "0001"
  }
}
字段类型描述
event_typestring始终为 pix.payout.failed
statusstring始终为 rejected — hold 已释放,余额已恢复
amountinteger值,以子分
fee_amountinteger手续费,以子分。显示的手续费是会被收取的值 — 在 TB ledger 中,pending 转账会自动撤销,因此在被拒绝的交易中实际上没有手续费借记
end_to_end_idstringBACEN E2E 标识符
transaction_idstring (UUID)交易唯一标识
external_idstring 或 null您的外部标识符
pix_keystring收款方 PIX 密钥
pix_key_typestring密钥类型:CPFCNPJEMAILPHONEEVP
descriptionstring 或 null发送方填写的描述
initiated_atstring (ISO 8601)此 webhook 的 dispatch 时刻(UTC)
reason_codestring 或缺失结构化 BACEN SPI 代码(2-6 字符)。示例:AC03ED05AM02BE01MD06FOCR。当后端从拒绝中提取 BACEN 代码时存在。用于程序化路由
reason_descriptionstring 或缺失reason_code 的英文描述。与 reason_code 一起存在。示例:"Invalid creditor account number"
reasonstring 或缺失[Legacy] 原因的自由描述。在拒绝没有可解析的 BACEN 代码时存在 — 与 reason_code 互斥
recipient.*objectpix.payout.confirmed(收款方银行数据)
sender.*objectpix.payout.confirmed(发送方账户银行数据)

dispatch site 之间的载荷变化

pix.payout.failed 由多个路径触发 — pix.ex 中的主路径从字符串 "rejected: <CODE>" 中提取 BACEN 代码并应用上述 reason vs reason_code 互斥。次要路径(stale checker、retry worker、部署后对账)可能在同一载荷中发送 reasonreason_code,或仅发送 reason 而无结构。始终将两个字段视为可选,并在 reason_code 存在时优先使用。

最常见的 reason_code 代码(BACEN SPI)

代码英文含义建议操作
AC03Invalid creditor account number与最终客户确认收款方银行数据
AC06Creditor account blocked目标账户已封锁 — 不要重试
AM02Not allowed amount (limit exceeded)值超过目标或源的 PIX 限制
AM04Insufficient funds源端余额不足
BE01End customer not in whitelist收款方标识符未识别
ED05Settlement failedSettlement 失败 — 调查后可重试
MD06Refund requested by end customer最终客户请求的退款
FOCRForbidden credit return禁止贷记返回

完整列表:查询 BACEN SPI 消息目录


pix.payout.returned

在您发送的 PIX 被目的地银行在结算后退回时发送。罕见,但可能发生在几天后。merchant 的余额增加(进入)。

命名区别

三个不同的流程可能混淆:

  • pix.return.received:您收到的 PIX 正在退回给原始付款方。余额减少
  • pix.payout.returned(这个):您发送的 PIX 正在返回给您。余额增加
  • pix.refund.requested:您收到的 PIX 上的 MED 预防性封锁。资金冻结。

相同载荷,两个事件,两种不同的状态

后端在同一调用(文件 return_in_handler.ex)中触发 pix.return.receivedpix.payout.returned,使用相同的基础载荷,只重写 status 字段:

  • pix.return.receivedstatus: "settled"(您收到的 PIX 正在退回 → 余额减少)
  • pix.payout.returnedstatus: "returned"(您发送的 PIX 正在返回 → 余额增加)

如果您的对账逻辑按 status 过滤或按 (e2e, event_type) 去重,请确保先区分 event_type — 载荷几乎相同。

json
{
  "event_type": "pix.payout.returned",
  "status": "returned",
  "account_id": 10014,
  "amount": 500000,
  "original_amount": 500000,
  "refunded_amount": 500000,
  "fee_amount": 0,
  "net_amount": 500000,
  "is_partial": false,
  "total_refunded": 500000,
  "remaining_refundable": 0,
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "return_e2e_id": "D3783905920260410111500000001",
  "end_to_end_id": "E3783905920260402101500000001",
  "original_transaction_id": "PIXOUTa1b2c3d4e5f67890abcdef1234567890",
  "external_id": "payment-456",
  "return_reason": "MD06",
  "return_reason_description": "Refund requested by end customer",
  "counterparty_ispb": "60701190",
  "counterparty_name": "EMPRESA DESTINO LTDA",
  "counterparty_document": "12345678000199",
  "counterparty_institution_name": "Itau Unibanco S.A.",
  "returned_at": "2026-04-10T11:15:00Z"
}
字段类型描述
event_typestring始终为 pix.payout.returned
statusstring始终为 returned — 退款已结算并在您账户中贷记
amountintegerrefunded_amount 相同(为兼容性保留)
original_amountinteger原始 PIX OUT 的值,以子分
refunded_amountinteger此次退款中实际退回的值(可能为部分)
fee_amountinteger此次退款中收取的手续费(通常为 0
net_amountintegerrefunded_amount - fee_amount
is_partialbooleanrefunded_amount < original_amount 或仍有余额要退回时为 true
total_refundedinteger此原始交易的所有退款之和(包括此次)
remaining_refundableintegermax(original_amount - total_refunded, 0) — 仍可退回的余额
return_e2e_idstring退款的 E2E(前缀 D
end_to_end_idstring原始 PIX OUT 交易的 E2E(前缀 E
original_transaction_idstring原始 PIX OUT 的 transaction_id。用于与您的系统对账
external_idstring 或 null原始交易的您的外部标识符(如适用)
return_reasonstring退款的 BACEN 代码:MD06BE08FR01SL02
return_reason_descriptionstringreturn_reason 的英文描述
counterparty_ispbstring发起退款的机构 ISPB
counterparty_namestring对手方名称(原始 PIX 的目标机构)
counterparty_documentstring 或 null对手方 CPF/CNPJ
counterparty_institution_namestring 或 null对手方机构名称(BCB 缓存)
returned_atstring (ISO 8601)此 webhook 的 dispatch 时刻(UTC)

手续费不退还

原始 cash-out 的手续费在 pix.payout.returned退还。手续费是为成功发送而收取的,它确实发生了。如果业务规则要求向最终客户退还手续费,merchant 必须单独进行。


pix.refund.requested

在通过 MED(特殊退款机制)请求 PIX 退款时发送。资金已在收到原始 PIX 的 merchant 账户中预防性封锁。

仅 PIX In

此事件仅适用于收到的 PIX(cash-in)。如果您发送了 PIX 并被退回,您将收到 pix.return.received 而不是 pix.refund.*

json
{
  "event_type": "pix.refund.requested",
  "status": "requested",
  "account_id": 10014,
  "requested_amount": 300000,
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "block_id": "b1c2d3e4-f5g6-7890-hijk-lm1234567890",
  "infraction_report_id": "INF20260402001",
  "e2e_id": "E9040088820260402095758709999671",
  "external_id": null,
  "blocked_amount": 300000,
  "fee_amount": 0,
  "fraud_category": "OTHER",
  "deadline": "2026-04-09T14:30:00Z",
  "scenario": "cautelar",
  "created_at": "2026-04-02T14:30:00Z"
}
字段类型描述
event_typestring始终为 pix.refund.requested
statusstring始终为 requested — 预防性封锁活跃
requested_amountinteger请求退款的值,以子分
block_idstring (UUID)预防性封锁标识符
infraction_report_idstringOnZ 中违规的标识符
e2e_idstring正在争议的原始 PIX 交易的 E2E
external_idstring 或 null您的外部标识符(如适用)
blocked_amountinteger实际封锁的值,以子分
fee_amountintegerMED 手续费,以子分
fraud_categorystring声称的欺诈类别。可能值:SCAMACCOUNT_TAKEOVERCOERCIONFRAUDULENT_ACCESSOTHER。当对方未发送特定 FraudType 时,值为 OTHERREFUND_REQUEST 的默认)。
deadlinestring (ISO 8601)分析/抗辩的截止日期(UTC)
scenariostringMED 场景:cautelarfraude
created_atstring (ISO 8601)封锁的日期/时间(UTC)

pix.refund.completed

在 MED 退款成功完成时触发。在 MED 接受周期中通过 med/processor.ex:915 触发。

json
{
  "event_type": "pix.refund.completed",
  "status": "settled",
  "account_id": 10014,
  "amount": 300000,
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "block_id": "b1c2d3e4-f5g6-7890-hijk-lm1234567890",
  "infraction_report_id": "INF20260402001",
  "e2e_id": "E9040088820260402095758709999671",
  "external_id": null,
  "reason": "analysis_unfounded",
  "completed_at": "2026-04-02T14:30:00Z"
}
字段类型描述
event_typestring始终为 pix.refund.completed
statusstring始终为 completed — MED 退款已完成
amountinteger退回的值,以子分
block_idstring (UUID)预防性封锁标识符
infraction_report_idstringOnZ 违规标识符
e2e_idstring原始 PIX 交易的 E2E
external_idstring 或 null您的外部标识符(如适用)
reasonstring释放原因(例:analysis_unfoundedmanual_release
completed_atstring (ISO 8601)完成日期/时间(UTC)

pix.return.received

在收到 PIX 退款时发送。此事件在您之前收到的 PIX(cash-in)正在退回给原始付款方时生成。merchant 的余额减少

命名区别

  • pix.return.received(这个):您收到的 PIX 正在退回给原始付款方。余额减少
  • pix.payout.returned:您发送的 PIX 正在返回给您。余额增加

名称与常识含义相反 — 请注意。

json
{
  "event_type": "pix.return.received",
  "status": "settled",
  "account_id": 10014,
  "amount": 300000,
  "original_amount": 300000,
  "refunded_amount": 300000,
  "fee_amount": 0,
  "net_amount": 300000,
  "is_partial": false,
  "total_refunded": 300000,
  "remaining_refundable": 0,
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "return_e2e_id": "D9040088820260402111500000001",
  "end_to_end_id": "E9040088820260402095758709999671",
  "original_transaction_id": "PIXINE9040088820260402095758709999671",
  "external_id": null,
  "return_reason": "MD06",
  "return_reason_description": "Refund requested by end customer",
  "counterparty_ispb": "60701190",
  "counterparty_name": "EMPRESA X LTDA",
  "counterparty_document": "98765432100",
  "counterparty_institution_name": "Itau Unibanco S.A.",
  "returned_at": "2026-04-02T11:15:00Z"
}

字段列表与 pix.payout.returned 相同,但语义相反 — 详见上方"命名区别"。

去重

要对 webhook 重试去重,请使用头 X-Owem-Event-Id 或组合 (return_e2e_id, end_to_end_id)return_e2e_idD(退款)开头,end_to_end_idE(原始)开头。


webhook.test

手动触发的测试事件,用于验证 webhook 配置。

json
{
  "event_type": "webhook.test",
  "status": "test",
  "account_id": 10014,
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "message": "Webhook test event"
}

pix.infraction.created

在对方(通过 BACEN DICT)报告 PIX 违规时触发。需要在 defense_deadline 前抗辩或自动 MED 预防性封锁。

pix_compliance.ex:463 触发(函数 upsert_infraction,当 is_new=true 时)。

json
{
  "event_type": "pix.infraction.created",
  "infraction_id": "e7f4d23a-6f2a-4d1e-a3e6-fe8b32bba95d",
  "e2e_id": "E0416201020260404113012abcdef1234",
  "status": "ACKNOWLEDGED",
  "infraction_type": "REFUND_REQUEST",
  "amount": 1500000,
  "analysis_result": null,
  "analysis_details": null,
  "defense_deadline": "2026-04-21T23:59:59Z",
  "counterpart_ispb": "60701190",
  "account_id": 10011,
  "merchant_id": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7"
}
字段类型描述
event_typestring始终为 pix.infraction.created
infraction_idstring (UUID)违规内部 ID
e2e_idstring争议交易的 E2E
statusstringBACEN 状态:ACKNOWLEDGEDCLOSEDCANCELLED
infraction_typestringBACEN 类型:REFUND_REQUESTREFUND_CANCELLEDFRAUD
amountinteger值,以子分
defense_deadlinestring (ISO 8601)抗辩提交截止日期
counterpart_ispbstring (8 位)对手方机构的 ISPB
account_idinteger您受影响的账户
merchant_idstring (UUID)您的 merchant_id

需要操作

状态为 ACKNOWLEDGED 且值 > R$1.000 的违规会自动生成 MED 预防性封锁。您必须在 defense_deadline 前通过 POST /api/merchant/infractions/{id}/defense 响应,否则将执行退款。


pix.infraction.resolved

在违规被解决(admin 关闭或 auto-deny)时触发。如有则释放预防性封锁。

pix_compliance.ex:664admin/infractions/resolve_controller.ex:84 触发。

json
{
  "event_type": "pix.infraction.resolved",
  "infraction_id": "e7f4d23a-6f2a-4d1e-a3e6-fe8b32bba95d",
  "e2e_id": "E0416201020260404113012abcdef1234",
  "status": "CLOSED",
  "infraction_type": "REFUND_REQUEST",
  "amount": 1500000,
  "analysis_result": "DISAGREED",
  "analysis_details": "Verificado pelo time de compliance e sem evidencias concretas nao temos como fazer devolucao",
  "defense_deadline": "2026-04-21T23:59:59Z",
  "counterpart_ispb": "60701190",
  "account_id": 10011,
  "merchant_id": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7"
}
字段类型描述
analysis_resultstringAGREED(退回)、DISAGREED(拒绝)
analysis_detailsstring决定的理由
其他字段pix.infraction.created 相同

pix.infraction.defense_submitted

在 merchant 针对违规提交抗辩时触发(通过门户或 API)。

admin/infractions/defense_controller.ex:67merchant/infractions/defense_controller.ex:178 触发。

json
{
  "event_type": "pix.infraction.defense_submitted",
  "infraction_id": "e7f4d23a-6f2a-4d1e-a3e6-fe8b32bba95d",
  "e2e_id": "E0416201020260404113012abcdef1234",
  "status": "defense_submitted",
  "account_id": 10011,
  "merchant_id": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entity_id": "26a48541-edce-4581-8c6e-564e7f2e6cd7"
}
字段类型描述
event_typestring始终为 pix.infraction.defense_submitted
statusstring始终为 defense_submitted
infraction_idstring (UUID)被抗辩违规的 ID

等待 BACEN 分析

提交后,BACEN 分析抗辩 + 对方证据。通过 pix.infraction.resolved 返回结果。


pix.payout.queued

在 PIX OUT 自动加入重试队列时触发(retry queue pix_out_retry_queue_enabled 功能,自 session 155 起可用)。原因:每 merchant 的 ClientLimiter 速率限制或共享的 DICT BACEN bucket 耗尽。

pix.ex:315(模块 Fluxiq.UseCases.Payments.OutboundPayment.Pix)触发。

json
{
  "event_type": "pix.payout.queued",
  "status": "queued",
  "account_id": 10011,
  "merchant_id": "1b2db911-972f-4466-9be9-60a7c5450064",
  "transaction_id": "PIXOUT0200806193e0984f830569",
  "end_to_end_id": "E3783905920260421133012abcdef1234",
  "amount": 200,
  "external_id": "payment-456",
  "reason": "dict_client_rate_limited",
  "reason_code": "DICT_CLIENT_RATE_LIMITED",
  "reason_description": "Merchant exceeded per-minute DICT lookup quota",
  "queued_at": "2026-04-21T13:30:12Z",
  "estimated_retry_seconds": 3,
  "queue_ttl_seconds": 7200
}
字段类型描述
event_typestring始终为 pix.payout.queued
statusstring始终为 queued
account_idinteger发起 PIX OUT 的账户
merchant_idstring (UUID)您的 merchant_id
transaction_idstringOwem 交易标识符
end_to_end_idstring为 PIX OUT 生成的 BACEN E2E
amountinteger值,以子分
external_idstring 或 null您的外部标识符(如果在原始 request 中发送)
reasonstring入队原因(snake_case)。已知值:dict_client_rate_limited(每 merchant 限制)、dict_bucket_exhausted(共享 DICT BACEN bucket 耗尽)、dict_rate_limited(通用回退)
reason_codestringreason 对应的 UPPERCASE 内部代码。值:DICT_CLIENT_RATE_LIMITEDDICT_BUCKET_EXHAUSTEDDICT_RATE_LIMITED。不是 BACEN SPI 代码(如 AC03AM02)— 入队发生在发送到 BACEN 之前,因此代码是 Owem 内部的
reason_descriptionstring原因的英文描述
queued_atstring (ISO 8601)进入队列的时刻(UTC)
estimated_retry_secondsintegerworker 的重试间隔(默认 3 秒);队列不保证 3 秒 — 如果 bucket 释放延迟,可能需要更长
queue_ttl_secondsinteger队列中的最大 TTL(秒)(7200 = 2 小时)。过期后,请求变为 failed,原因 queue_ttl_expired

这里的 reason_code 不是 BACEN SPI

请注意,在 pix.payout.queued 中,reason_code 是 UPPERCASE 的内部 Owem 代码(DICT_CLIENT_RATE_LIMITED 等)。在 pix.payout.failed 中,reason_codeBACEN SPI 代码(例:AC03AM02ED05)。这两个字段同名但词汇不同 — 在您的消费者中分别处理每个事件。

自动排空

入队的请求会在 TTL 有效期间由 worker 约每 3 秒自动重试。正常情况下,当每 merchant 限制或 DICT BACEN bucket 释放容量后会继续处理,但这不是 3-10 分钟 SLA。下一个事件:pix.payout.processing(当它离开队列并发送到 BACEN 时)。如果 2 小时 TTL 过期而未成功,您会收到 pix.payout.failed,原因 reason="queue_ttl_expired"


如何解释 webhook

要确认资金已进入账户:等待 pix.charge.paid,status: "paid"。这是保证值已入账且手续费已收取的唯一事件。

要确认资金已离开账户:等待 pix.payout.confirmed,status: "settled"。状态 processing 是中间的 — 余额已保留但如果被拒绝可能撤销。

对于退款pix.return.received,status: "settled" 确认已结算并在账户中贷记的退款。

去重:使用头 X-Owem-Event-Id 或字段 end_to_end_id 作为幂等性键。

Owem Pay Instituição de Pagamento — ISPB 37839059