Skip to content

Payloads de los Webhooks

Ejemplos de los payloads enviados para cada tipo de evento. Todos los webhooks son enviados como HTTP POST con Content-Type: application/json.

Headers de seguridad

Cada notificacion incluye los headers X-Owem-Signature (HMAC-SHA256), X-Owem-Timestamp, X-Owem-Event-Id y X-Owem-Event-Type. Consulte Webhooks — Vision General para detalles sobre validacion.


Referencia de Status

No todos los eventos significan que la transaccion esta concluida. Use la tabla abajo para saber cuando el dinero fue efectivamente liquidado.

EventoStatusSignificadoDinero liquidado?
pix.charge.createdcreatedQR code generado o cash-in iniciado. Aguardando pago.No — solo creado
pix.charge.paidpaidPIX recibido y liquidado en cuenta. Saldo actualizado, tarifa cobrada.Si
pix.charge.expiredexpiredQR code expiro sin pago.N/A
pix.charge.cancelledcancelledQR code cancelado antes del pago. Aun no disparado en produccion.N/A
pix.payout.queuedqueuedPIX enviado encolado por rate limit (ClientLimiter o bucket DICT). Sin debito aun.No — aguardando quota
pix.payout.processingprocessingPIX enviado, aguardando confirmacion del destino. Saldo reservado (hold).No — puede revertir
pix.payout.confirmedsettledPIX enviado confirmado por el destino. Debito definitivo.Si
pix.payout.failedrejectedPIX enviado rechazado por el destino. Hold liberado, saldo restaurado.No
pix.payout.returnedreturnedPIX enviado devuelto despues de liquidacion.Si (reverso)
pix.refund.requestedrequestedDevolucion PIX solicitada (MED). Bloqueo cautelar creado.Parcial
pix.refund.completedsettled / completedDevolucion PIX concluida y liquidada. Debito definitivo.Si
pix.return.receivedsettledDevolucion PIX recibida y liquidada (credito en la cuenta).Si
pix.infraction.createdACKNOWLEDGEDInfraccion PIX reportada contra usted. Requiere accion.Parcial — bloqueo cautelar si >R$1k
pix.infraction.resolvedCLOSED / CANCELLEDInfraccion resuelta (devolucion ejecutada o negada).N/A — efecto en otro evento
pix.infraction.defense_submitteddefense_submittedDefensa enviada por el merchant. Aguardando BACEN.N/A
webhook.testtestEvento de prueba disparado manualmente via portal Admin/Merchant.N/A

Reglas de reconciliacion:

  • Considere entradas de saldo solo en los status: paid (credito PIX IN) y returned (reverso de un PIX OUT previamente enviado).
  • Considere salidas de saldo solo en los status: settled (debito PIX OUT confirmado) y completed (debito MED refund definitivo), y settled en pix.return.received (reverso de un PIX IN previamente recibido).
  • Todos los demas status (created, queued, processing, rejected, expired, requested, ACKNOWLEDGED, defense_submitted, etc.) son intermedios — no disparan movimiento contable de su lado.
  • No tratar pix.payout.processing como confirmacion; aguarde el evento terminal (pix.payout.confirmed o pix.payout.failed).

Campos comunes

Todos los payloads de webhook incluyen estos campos:

CampoTipoDescripcion
event_typestringTipo del evento que disparo el webhook (ej: pix.charge.paid)
statusstringEstado de la operacion — consulte la Referencia de Status
account_idintegerNumero de su cuenta en Owem
entity_idstring (UUID)Identificador de la entidad Owem

Valores monetarios: Todos los valores son en subcentavos (1 BRL = 10.000 subcentavos). Para convertir a reales: valor / 10000. Ejemplo: 300000 / 10000 = R$ 30,00.


pix.charge.paid

Enviado cuando un PIX es recibido y liquidado en la cuenta. Este es el evento que confirma que el dinero entro.

Ejemplo — vinculado a QR code

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"
  }
}

Ejemplo — transferencia directa (sin 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"
  }
}
CampoTipoDescripcion
event_typestringSiempre pix.charge.paid
statusstringSiempre paid
account_idintegerNumero de la cuenta que recibio el PIX
amountintegerValor recibido en subcentavos. 300000 = R$ 30,00
fee_amountintegerTarifa cobrada en subcentavos. 400 = R$ 0,04
end_to_end_idstringIdentificador E2E del BACEN (unico por transaccion PIX)
entity_idstring (UUID)Identificador de la entidad Owem
tx_idstring o nullID de la transaccion. Presente cuando esta vinculado a un QR code. null para transferencias directas
qr_code_idstring o nullUUID del QR code vinculado. null para transferencias directas
counterparty_namestring o nullNombre del pagador (remitente)
payer_documentstring o nullCPF/CNPJ del pagador (solo digitos)
payer_ispbstring o nullISPB (8 digitos) de la institucion del pagador
payer_bank_namestring o nullNombre de la institucion del pagador, resuelto via cache BCB (896 bancos)
external_idstring o nullSu identificador externo. Presente cuando el QR code fue creado via API con external_id. null para transferencias directas o QR sin external_id
paid_atstring (ISO 8601)Fecha/hora de la liquidacion (UTC)
recipient_keystring o nullClave PIX que recibio el pago (EVP, CPF, CNPJ, email o telefono)
recipient_key_typestring o nullTipo de la clave PIX receptora: evp, phone, email, cpf, cnpj
receiverobjectDatos completos del receptor (usted). Incluye name, document, account, ispb, institution_name

Variacion de payload: reconciliacion pos-deploy

En escenarios raros (pod del backend muerto antes del webhook salir, replay retroactivo despues de incidente), el worker PostDeployReconciliation puede disparar pix.charge.paid con campos reducidos — tipicamente sin receiver, payer_ispb, payer_bank_name, recipient_key ni recipient_key_type. Los campos que siempre estan presentes: event_type, status, account_id, amount, end_to_end_id, fee_amount, counterparty_name, payer_document, external_id, paid_at, tx_id (cuando vinculado a QR).

Su consumidor debe tratar todos los campos no-obligatorios como opcionales (nil/ausente) y reconciliar por el end_to_end_id.

qr_code_id es un UUID v4 canonico

El campo qr_code_id es siempre serializado como UUID v4 en formato canonico (36 caracteres con guiones: f401d5e3-a2b1-4c8e-9f3d-1234567890ab) — nunca como binario crudo, base64 o hex sin guiones. Use para correlacion directa con la respuesta de POST /api/external/pix/cash-in (campo transaction_id en su request retorna el tx_id del QR, y qr_code_id aqui es la clave primaria interna).


pix.charge.expired

Disparado automaticamente cuando QR code expira sin pago. Ejecutado por el worker QrExpirationChecker con cron */5 * * * * (cada 5 minutos, sobre QR codes cuyo expires_at ya paso).

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"
}
CampoTipoDescripcion
event_typestringSiempre pix.charge.expired
statusstringSiempre expired
account_idintegerCuenta que emitio el QR code
entity_idstring (UUID)Identificador de la entidad Owem
tx_idstringID del cobro/QR code
amountintegerValor esperado en subcentavos (no cobrado)
external_idstring o nullSu identificador externo, si enviado en la creacion
expired_atstring (ISO 8601)Momento en que el worker detecto la expiracion (UTC) — puede ser posterior al expires_at real del QR en hasta ~5 min

pix.charge.cancelled

Planeado

Este evento esta registrado como valido para suscripcion, pero aun no es disparado por el sistema. Usted puede incluirlo en la lista de events al crear un webhook (la API acepta), pero ninguna notificacion sera enviada hasta que la funcionalidad de cancelacion de QR Code sea implementada.


pix.charge.created

Enviado cuando un QR code es generado o un cash-in es iniciado. Ningun movimiento financiero ocurrio.

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"
}
CampoTipoDescripcion
event_typestringSiempre pix.charge.created
statusstringSiempre created
amountintegerValor esperado en subcentavos
tx_idstringID del cobro/QR code
external_idstring o nullSu identificador externo, retornado tal como enviado. null si no informado o QR generado por el portal

pix.payout.confirmed

Enviado cuando un PIX enviado es confirmado por la institucion destino. Debito definitivo.

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"
  }
}
CampoTipoDescripcion
event_typestringSiempre pix.payout.confirmed
statusstringSiempre settled — debito definitivo
amountintegerValor enviado en subcentavos
fee_amountintegerTarifa cobrada en subcentavos
end_to_end_idstringIdentificador E2E del BACEN
transaction_idstring (UUID)Identificador unico de la transaccion
external_idstring o nullSu identificador externo
pix_keystringClave PIX del destinatario
pix_key_typestringTipo de la clave: CPF, CNPJ, EMAIL, PHONE, EVP
descriptionstring o nullDescripcion informada por el remitente
initiated_atstring (ISO 8601)Momento en que este webhook fue disparado (UTC). No es el timestamp del request original de cash-out ni del settlement BACEN. Para correlacionar con el momento que usted envio el POST, use el created_at del GET /api/external/transactions/ref/{external_id}; para el momento exacto de la entrega del webhook, use el header X-Owem-Timestamp
recipientobjectDatos bancarios del destinatario (resueltos via DICT)
recipient.namestring o nullNombre del titular de la cuenta destino
recipient.documentstring o nullCPF/CNPJ del destinatario (solo digitos)
recipient.ispbstring o nullISPB de la institucion destino
recipient.accountstring o nullNumero de la cuenta destino
recipient.agencystring o nullAgencia de la cuenta destino
recipient.institution_namestring o nullNombre de la institucion destino (resuelto via cache BCB)
senderobjectDatos bancarios de la cuenta remitente (su cuenta Owem)
sender.namestring o nullNombre del titular de la cuenta remitente
sender.documentstring o nullCPF/CNPJ del remitente (solo digitos)
sender.ispbstring o nullISPB de Owem Pay (37839059)
sender.accountstring o nullNumero de la cuenta remitente
sender.agencystring o nullAgencia de la cuenta remitente

pix.payout.processing

Enviado cuando un PIX enviado esta siendo procesado. El saldo esta reservado (hold) pero no es definitivo. Este evento es opcional — si usted solo quiere ser notificado en el estado terminal, ignorelo y espere por el pix.payout.confirmed o pix.payout.failed.

json
{
  "event_type": "pix.payout.processing",
  "status": "processing",
  "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"
  }
}
CampoTipoDescripcion
event_typestringSiempre pix.payout.processing
statusstringSiempre processing — saldo reservado, puede revertir
amountintegerValor en subcentavos
fee_amountintegerTarifa en subcentavos (misma tarifa que aparece en confirmed/failed posteriormente — es calculada en la creacion del cash-out, no despues)
end_to_end_idstringIdentificador E2E del BACEN
transaction_idstring (UUID)Identificador unico de la transaccion
external_idstring o nullSu identificador externo
pix_keystringClave PIX del destinatario
pix_key_typestringTipo de la clave: CPF, CNPJ, EMAIL, PHONE, EVP
descriptionstring o nullDescripcion informada por el remitente
initiated_atstring (ISO 8601)Momento del dispatch de este webhook (UTC) — vea nota en pix.payout.confirmed
recipientobjectDatos bancarios del destinatario (resueltos via DICT)
recipient.namestring o nullNombre del titular de la cuenta destino
recipient.documentstring o nullCPF/CNPJ del destinatario (solo digitos)
recipient.ispbstring o nullISPB de la institucion destino
recipient.accountstring o nullNumero de la cuenta destino
recipient.agencystring o nullAgencia de la cuenta destino
recipient.institution_namestring o nullNombre de la institucion destino
senderobjectDatos bancarios de la cuenta remitente (su cuenta Owem)
sender.namestring o nullNombre del titular de la cuenta remitente
sender.documentstring o nullCPF/CNPJ del remitente (solo digitos)
sender.ispbstring o nullISPB de Owem Pay (37839059)
sender.accountstring o nullNumero de la cuenta remitente
sender.agencystring o nullAgencia de la cuenta remitente

Orden de los eventos

Un pix.payout.processing es siempre seguido (segundos a minutos despues) por un pix.payout.confirmed o pix.payout.failed. En transacciones rapidas (settlement inmediato), el processing puede ser omitido y usted recibe directamente el terminal.


pix.payout.failed

Enviado cuando un PIX enviado es rechazado. Hold liberado, saldo restaurado.

Actualizado en 10/04/2026

El payload incluye los campos estructurados reason_code (codigo BACEN SPI de 2–6 caracteres) y reason_description (descripcion en ingles). Nuevas integraciones deben usar esos campos para enrutamiento programatico de fallas.

Exclusion mutua: cuando el backend logra extraer un codigo BACEN del rechazo (ej: "rejected: AC03"), el payload envia solo reason_code + reason_description — el campo legacy reason es removido. Cuando la falla no tiene codigo BACEN parseable (ej: timeout interno, error de provider sin codigo), el payload envia solo reason (string libre) — sin reason_code. Trate ambos formatos en su consumidor.

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"
  }
}
CampoTipoDescripcion
event_typestringSiempre pix.payout.failed
statusstringSiempre rejected — hold liberado, saldo restaurado
amountintegerValor en subcentavos
fee_amountintegerTarifa en subcentavos. La tarifa mostrada es el valor que habria sido cobrado — en el ledger TB la transferencia pending es revertida automaticamente, por lo tanto en la practica no hay debito de tarifa en transacciones rechazadas
end_to_end_idstringIdentificador E2E del BACEN
transaction_idstring (UUID)Identificador unico de la transaccion
external_idstring o nullSu identificador externo
pix_keystringClave PIX del destinatario
pix_key_typestringTipo de la clave: CPF, CNPJ, EMAIL, PHONE, EVP
descriptionstring o nullDescripcion informada por el remitente
initiated_atstring (ISO 8601)Momento del dispatch de este webhook (UTC)
reason_codestring o ausenteCodigo BACEN SPI estructurado (2–6 caracteres). Ejemplos: AC03, ED05, AM02, BE01, MD06, FOCR. Presente cuando el backend extrajo codigo BACEN del rechazo. Use este campo para enrutamiento programatico
reason_descriptionstring o ausenteDescripcion en ingles del reason_code. Presente junto con reason_code. Ejemplo: "Invalid creditor account number"
reasonstring o ausente[Legacy] Descripcion libre del motivo. Presente solo cuando el rechazo no tiene codigo BACEN parseable — mutuamente exclusivo con reason_code
recipientobjectDatos bancarios del destinatario (resueltos via DICT)
recipient.namestring o nullNombre del titular de la cuenta destino
recipient.documentstring o nullCPF/CNPJ del destinatario (solo digitos)
recipient.ispbstring o nullISPB de la institucion destino
recipient.accountstring o nullNumero de la cuenta destino
recipient.agencystring o nullAgencia de la cuenta destino
recipient.institution_namestring o nullNombre de la institucion destino
senderobjectDatos bancarios de la cuenta remitente (su cuenta Owem)
sender.namestring o nullNombre del titular de la cuenta remitente
sender.documentstring o nullCPF/CNPJ del remitente (solo digitos)
sender.ispbstring o nullISPB de Owem Pay (37839059)
sender.accountstring o nullNumero de la cuenta remitente
sender.agencystring o nullAgencia de la cuenta remitente

Variaciones de payload entre dispatch sites

pix.payout.failed es disparado por multiples caminos — el principal en pix.ex extrae codigo BACEN de strings "rejected: <CODE>" y aplica la exclusion mutua reason vs reason_code descrita arriba. Caminos secundarios (stale checker, retry worker, reconciliacion pos-deploy) pueden enviar tanto reason como reason_code en el mismo payload, o solo reason sin estructura. Trate siempre los dos campos como opcionales y prefiera reason_code cuando este presente.

Codigos reason_code mas comunes (BACEN SPI)

CodigoSignificado en inglesAccion recomendada
AC03Invalid creditor account numberConfirmar datos bancarios del destinatario con el cliente final
AC06Creditor account blockedCuenta destino bloqueada — no reintentar
AM02Not allowed amount (limit exceeded)Valor excede limite de PIX del destino u origen
AM04Insufficient fundsSaldo insuficiente en el origen
BE01End customer not in whitelistIdentificador del destinatario no reconocido
ED05Settlement failedFalla en el settlement — puede reintentar despues de investigacion
MD06Refund requested by end customerDevolucion solicitada por el cliente final
FOCRForbidden credit returnDevolucion de credito prohibida

Lista completa: consulte el Catalogo de Mensajes del SPI del BACEN.


pix.payout.returned

Enviado cuando un PIX que usted envio es devuelto por el banco destino despues de liquidacion. Raro, pero puede ocurrir hasta varios dias despues. El saldo del merchant aumenta (entrada).

Distincion de nomenclatura

Tres flujos diferentes pueden ser confundidos:

  • pix.return.received: un PIX que usted recibio esta siendo devuelto al pagador original. Saldo DISMINUYE.
  • pix.payout.returned (este): un PIX que usted envio esta volviendo a usted. Saldo AUMENTA.
  • pix.refund.requested: bloqueo cautelar MED en un PIX que usted recibio. Fondos congelados.

Mismo payload, dos eventos, dos status diferentes

El backend dispara pix.return.received y pix.payout.returned en la misma llamada (archivo return_in_handler.ex) usando el mismo payload base con el campo status reescrito:

  • pix.return.receivedstatus: "settled" (PIX que usted recibio esta siendo devuelto → saldo disminuye)
  • pix.payout.returnedstatus: "returned" (PIX que usted envio esta volviendo → saldo aumenta)

Si su logica de reconciliacion filtra por status o dedup por (e2e, event_type), asegurese de distinguir event_type primero — el payload es casi identico.

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"
}
CampoTipoDescripcion
event_typestringSiempre pix.payout.returned
statusstringSiempre returned — devolucion liquidada y acreditada en su cuenta
amountintegerMismo valor que refunded_amount (mantenido para compatibilidad)
original_amountintegerValor del PIX OUT original en subcentavos
refunded_amountintegerValor efectivamente devuelto en esta devolucion (puede ser parcial)
fee_amountintegerTarifa cobrada en esta devolucion (generalmente 0)
net_amountintegerrefunded_amount - fee_amount
is_partialbooleantrue cuando refunded_amount < original_amount o aun reste saldo a devolver
total_refundedintegerSuma de todas las devoluciones ya recibidas para esta transaccion original (incluye esta)
remaining_refundableintegermax(original_amount - total_refunded, 0) — saldo aun pasible de devolucion
return_e2e_idstringE2E de la devolucion (prefijo D)
end_to_end_idstringE2E de la transaccion PIX OUT original (prefijo E)
original_transaction_idstringtransaction_id del PIX OUT original. Use para correlacion con su sistema
external_idstring o nullSu identificador externo de la transaccion original (si aplicable)
return_reasonstringCodigo BACEN de la devolucion: MD06, BE08, FR01, SL02
return_reason_descriptionstringDescripcion en ingles del return_reason
counterparty_ispbstringISPB de la institucion que inicio la devolucion
counterparty_namestringNombre de la contraparte (institucion destino del PIX original)
counterparty_documentstring o nullCPF/CNPJ de la contraparte
counterparty_institution_namestring o nullNombre de la institucion contraparte (cache BCB)
returned_atstring (ISO 8601)Momento del dispatch de este webhook (UTC)

Tarifa no es reembolsada

La tarifa del cash-out original no es reembolsada en pix.payout.returned. La tarifa fue cobrada por el envio exitoso, que realmente ocurrio. Si la regla de negocio exige reembolso de la tarifa al cliente final, el merchant debe hacer eso por separado.


pix.refund.requested

Enviado cuando una devolucion PIX es solicitada via MED (Mecanismo Especial de Devolucion). Fondos fueron bloqueados cautelarmente en la cuenta del merchant que recibio el PIX original.

Solo PIX In

Este evento solo se aplica a PIX recibidos (cash-in). Si usted envio un PIX y fue devuelto, recibira pix.return.received en vez de 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"
}
CampoTipoDescripcion
event_typestringSiempre pix.refund.requested
statusstringSiempre requested — bloqueo cautelar activo
requested_amountintegerValor solicitado para devolucion en subcentavos
block_idstring (UUID)Identificador del bloqueo cautelar
infraction_report_idstringIdentificador de la infraccion en OnZ
e2e_idstringE2E de la transaccion PIX original que esta siendo impugnada
external_idstring o nullSu identificador externo (si aplicable)
blocked_amountintegerValor efectivamente bloqueado en subcentavos
fee_amountintegerTarifa MED en subcentavos
fraud_categorystringCategoria del fraude alegado. Valores posibles: SCAM, ACCOUNT_TAKEOVER, COERCION, FRAUDULENT_ACCESS, OTHER. Cuando la contraparte no envia un FraudType especifico, el valor es OTHER (estandar para REFUND_REQUEST).
deadlinestring (ISO 8601)Plazo para analisis/defensa (UTC)
scenariostringEscenario MED: cautelar o fraude
created_atstring (ISO 8601)Fecha/hora del bloqueo (UTC)

pix.refund.completed

Disparado cuando una devolucion MED es efectivada con exito. Dispara via med/processor.ex:915 durante el ciclo de MED aceptado.

Formato del payload (confirmado por el code path med/processor.ex:900-920):

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"
}
CampoTipoDescripcion
event_typestringSiempre pix.refund.completed
statusstringSiempre completed — devolucion MED finalizada
amountintegerValor devuelto en subcentavos
block_idstring (UUID)Identificador del bloqueo cautelar
infraction_report_idstringIdentificador de la infraccion OnZ
e2e_idstringE2E de la transaccion PIX original
external_idstring o nullSu identificador externo (si aplicable)
reasonstringMotivo de la liberacion (ej: analysis_unfounded, manual_release)
completed_atstring (ISO 8601)Fecha/hora de la conclusion (UTC)

pix.return.received

Enviado cuando una devolucion PIX es recibida. Este evento es generado cuando un PIX que usted recibio anteriormente (cash-in) esta siendo devuelto al pagador original. El saldo del merchant disminuye.

Distincion de nomenclatura

  • pix.return.received (este): un PIX que usted recibio esta siendo devuelto al pagador original. Saldo DISMINUYE.
  • pix.payout.returned: un PIX que usted envio esta volviendo a usted. Saldo AUMENTA.

Los nombres son inversos a lo que el significado comun sugiere — preste atencion.

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"
}
CampoTipoDescripcion
event_typestringSiempre pix.return.received
statusstringSiempre settled — devolucion liquidada
amountintegerMismo valor que refunded_amount (mantenido para compatibilidad)
original_amountintegerValor del PIX IN original en subcentavos
refunded_amountintegerValor efectivamente devuelto en esta devolucion (puede ser parcial)
fee_amountintegerTarifa cobrada en esta devolucion
net_amountintegerrefunded_amount - fee_amount
is_partialbooleantrue cuando la devolucion no cubre el valor total del PIX IN original
total_refundedintegerSuma de todas las devoluciones ya enviadas para esta transaccion (incluye esta)
remaining_refundableintegerSaldo aun pasible de devolucion
return_e2e_idstringE2E de la devolucion (prefijo D)
end_to_end_idstringE2E de la transaccion PIX IN original (prefijo E)
original_transaction_idstringtransaction_id del PIX IN original. Use para correlacion con su sistema
external_idstring o nullSu identificador externo de la transaccion original (si aplicable)
return_reasonstringCodigo BACEN de la devolucion: MD06, BE08, FR01, SL02
return_reason_descriptionstringDescripcion en ingles del return_reason
counterparty_ispbstringISPB de la institucion que esta recibiendo la devolucion
counterparty_namestringNombre de la contraparte (pagador original del PIX IN)
counterparty_documentstring o nullCPF/CNPJ de la contraparte
counterparty_institution_namestring o nullNombre de la institucion contraparte (cache BCB)
returned_atstring (ISO 8601)Momento del dispatch de este webhook (UTC)

Deduplicacion

Para deduplicar retries de webhook, use el header X-Owem-Event-Id O la combinacion (return_e2e_id, end_to_end_id). El return_e2e_id comienza con D (devolucion) y el end_to_end_id comienza con E (original).


webhook.test

Evento de prueba disparado manualmente para validar la configuracion del 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

Disparado cuando una infraccion PIX es reportada por la contraparte (via BACEN DICT). Requiere defensa hasta defense_deadline O bloqueo cautelar automatico (MED).

Disparado por pix_compliance.ex:463 (funcion upsert_infraction cuando 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"
}
CampoTipoDescripcion
event_typestringSiempre pix.infraction.created
infraction_idstring (UUID)ID interno de la infraccion
e2e_idstringE2E de la transaccion impugnada
statusstringStatus BACEN: ACKNOWLEDGED, CLOSED, CANCELLED
infraction_typestringTipo BACEN: REFUND_REQUEST, REFUND_CANCELLED, FRAUD
amountintegerValor en subcentavos
defense_deadlinestring (ISO 8601)Plazo para envio de defensa
counterpart_ispbstring (8 digitos)ISPB de la institucion contraparte
account_idintegerSu cuenta afectada
merchant_idstring (UUID)Su merchant_id

Accion obligatoria

Infracciones con status ACKNOWLEDGED y valor > R$1.000 generan bloqueo cautelar automatico (MED). Usted debe responder via POST /api/merchant/infractions/{id}/defense antes del defense_deadline o la devolucion sera ejecutada.


pix.infraction.resolved

Disparado cuando una infraccion es resuelta (admin close o auto-deny). Libera bloqueo cautelar si lo hay.

Disparado por pix_compliance.ex:664 y admin/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"
}
CampoTipoDescripcion
analysis_resultstringAGREED (devuelve), DISAGREED (niega)
analysis_detailsstringJustificativa de la decision
Demas camposIdenticos a pix.infraction.created

pix.infraction.defense_submitted

Disparado cuando el merchant envia defensa contra infraccion (via portal o API).

Disparado por admin/infractions/defense_controller.ex:67 y merchant/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"
}
CampoTipoDescripcion
event_typestringSiempre pix.infraction.defense_submitted
statusstringSiempre defense_submitted
infraction_idstring (UUID)ID de la infraccion siendo defendida

Aguarda analisis BACEN

Despues del envio, BACEN analiza la defensa + evidencias de la contraparte. Resultado via pix.infraction.resolved.


pix.payout.queued

Disparado cuando PIX OUT es automaticamente colocado en fila de retry (feature del retry queue pix_out_retry_queue_enabled, disponible desde sesion 155). Motivos: rate limit del ClientLimiter por merchant o agotamiento del bucket DICT BACEN compartido.

Disparado por pix.ex:315 (modulo 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
}
CampoTipoDescripcion
event_typestringSiempre pix.payout.queued
statusstringSiempre queued
account_idintegerCuenta que origino el PIX OUT
merchant_idstring (UUID)Su merchant_id
transaction_idstringIdentificador de la transaccion Owem
end_to_end_idstringE2E BACEN generado para el PIX OUT
amountintegerValor en subcentavos
external_idstring o nullSu identificador externo (si enviado en el request original)
reasonstringMotivo del encolamiento (snake_case). Valores conocidos: dict_client_rate_limited (limite por merchant), dict_bucket_exhausted (bucket DICT BACEN compartido agotado), dict_rate_limited (fallback generico)
reason_codestringCodigo interno en UPPERCASE correlato al reason. Valores: DICT_CLIENT_RATE_LIMITED, DICT_BUCKET_EXHAUSTED, DICT_RATE_LIMITED. No es un codigo BACEN SPI (como AC03, AM02) — el encolamiento sucede antes del envio al BACEN, por eso los codigos son internos de Owem
reason_descriptionstringDescripcion en ingles del motivo
queued_atstring (ISO 8601)Momento en que entro en la fila (UTC)
estimated_retry_secondsintegerIntervalo de retry del worker (3 s por default); la fila no garantiza 3 s — puede demorar si el bucket demora en liberar
queue_ttl_secondsintegerTTL maximo en la fila en segundos (7200 = 2 h). Despues de expirar, request va para failed con motivo queue_ttl_expired

reason_code aqui no es BACEN SPI

Note que en pix.payout.queued el reason_code es un codigo interno Owem en UPPERCASE (DICT_CLIENT_RATE_LIMITED, etc.). En pix.payout.failed el reason_code es codigo BACEN SPI (ej: AC03, AM02, ED05). Los dos campos tienen el mismo nombre pero vocabularios diferentes — trate cada evento por separado en su consumidor.

Drenaje automatico

Requests encoladas son reintentadas automaticamente por el worker cada ~3s mientras haya TTL. En condiciones normales el procesamiento vuelve cuando el limite por merchant o el bucket DICT BACEN libera capacidad, pero esto no es SLA de 3–10 min. Proximo evento: pix.payout.processing (cuando salga de la fila y sea enviado al BACEN). En caso que el TTL de 2 h expire sin exito, usted recibe pix.payout.failed con reason="queue_ttl_expired".


Como interpretar los webhooks

Para confirmar que dinero entro en la cuenta: Aguarde pix.charge.paid con status: "paid". Este es el unico evento que garantiza que el valor fue acreditado y la tarifa cobrada.

Para confirmar que dinero salio de la cuenta: Aguarde pix.payout.confirmed con status: "settled". El status processing es intermedio — el saldo esta reservado pero puede ser revertido si rechazado.

Para devoluciones: pix.return.received con status: "settled" confirma devolucion liquidada y acreditada en la cuenta.

Deduplicacion: Use el header X-Owem-Event-Id o el campo end_to_end_id como clave de idempotencia.

Owem Pay Instituição de Pagamento — ISPB 37839059