Skip to content

Payloads dos Webhooks

Exemplos dos payloads enviados para cada tipo de evento. Todos os webhooks são enviados como HTTP POST com Content-Type: application/json.

Headers de segurança

Cada notificação inclui os headers X-Owem-Signature (HMAC-SHA256), X-Owem-Timestamp, X-Owem-Event-Id e X-Owem-Event-Type. Consulte Webhooks — Visão Geral para detalhes sobre validação.


Referência de Status

Nem todos os eventos significam que a transação está concluída. Use a tabela abaixo para saber quando o dinheiro foi efetivamente liquidado.

EventoStatusSignificadoDinheiro liquidado?
pix.charge.createdcreatedQR code gerado ou cash-in iniciado. Aguardando pagamento.Não — apenas criado
pix.charge.paidpaidPIX recebido e liquidado em conta. Saldo atualizado, taxa cobrada.Sim
pix.charge.expiredexpiredQR code expirou sem pagamento.N/A
pix.charge.cancelledcancelledQR code cancelado explicitamente pelo merchant antes do pagamento.N/A
pix.payout.queuedqueuedPIX enviado enfileirado por rate limit (ClientLimiter ou bucket DICT). Sem débito ainda.Não — aguardando quota
pix.payout.processingprocessingPIX enviado, aguardando confirmação do destino. Saldo reservado (hold).Não — pode reverter
pix.payout.confirmedsettledPIX enviado confirmado pelo destino. Débito definitivo.Sim
pix.payout.failedrejectedPIX enviado rejeitado pelo destino. Hold liberado, saldo restaurado.Não
pix.payout.returnedreturnedPIX enviado devolvido após liquidação.Sim (reverso)
pix.refund.requestedrequestedDevolução PIX solicitada (MED). Bloqueio cautelar criado.Parcial
pix.refund.completedsettled / completedDevolução PIX concluída e liquidada. Débito definitivo.Sim
pix.return.receivedsettledDevolução PIX recebida e liquidada (crédito na conta).Sim
pix.infraction.createdACKNOWLEDGEDInfração PIX reportada contra você. Requer ação.Parcial — bloqueio cautelar se >R$1k
pix.infraction.resolvedCLOSED / CANCELLEDInfração resolvida (devolução executada ou negada).N/A — efeito em outro evento
pix.infraction.defense_submitteddefense_submittedDefesa submetida pelo merchant. Aguardando BACEN.N/A
webhook.testtestEvento de teste disparado manualmente via portal Admin/Merchant.N/A

Regras de reconciliação:

  • Considere entradas de saldo apenas nos status: paid (crédito PIX IN) e returned (reversão de um PIX OUT previamente enviado).
  • Considere saídas de saldo apenas nos status: settled (débito PIX OUT confirmado) e completed (débito MED refund definitivo), e settled em pix.return.received (reversão de um PIX IN previamente recebido).
  • Todos os demais status (created, queued, processing, rejected, expired, requested, ACKNOWLEDGED, defense_submitted, etc.) são intermediários — não disparam movimento contábil do seu lado.
  • Não tratar pix.payout.processing como confirmação; aguarde o evento terminal (pix.payout.confirmed ou pix.payout.failed).

Campos comuns

Todos os payloads de webhook incluem estes campos:

CampoTipoDescrição
event_typestringTipo do evento que disparou o webhook (ex: pix.charge.paid)
statusstringStatus da operação — consulte a Referência de Status
account_idintegerNúmero da sua conta na Owem
entity_idstring (UUID)Identificador da entidade Owem

Valores monetários: Todos os valores são em subcentavos (1 BRL = 10.000 subcentavos). Para converter para reais: valor / 10000. Exemplo: 300000 / 10000 = R$ 30,00.


pix.charge.paid

Enviado quando um PIX é recebido e liquidado na conta. Este é o evento que confirma que o dinheiro entrou.

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

Exemplo — transferência direta (sem 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"
  }
}
CampoTipoDescrição
event_typestringSempre pix.charge.paid
statusstringSempre paid
account_idintegerNúmero da conta que recebeu o PIX
amountintegerValor recebido em subcentavos. 300000 = R$ 30,00
fee_amountintegerTarifa cobrada em subcentavos. 400 = R$ 0,04
end_to_end_idstringIdentificador E2E do BACEN (único por transação PIX)
entity_idstring (UUID)Identificador da entidade Owem
tx_idstring ou nullID da transação. Presente quando vinculado a um QR code. null para transferências diretas
qr_code_idstring ou nullUUID do QR code vinculado. null para transferências diretas
counterparty_namestring ou nullNome do pagador (remetente)
payer_documentstring ou nullCPF/CNPJ do pagador (somente dígitos)
payer_ispbstring ou nullISPB (8 dígitos) da instituição do pagador
payer_bank_namestring ou nullNome da instituição do pagador, resolvido via cache BCB (896 bancos)
external_idstring ou nullSeu identificador externo. Presente quando o QR code foi criado via API com external_id. null para transferências diretas ou QR sem external_id
paid_atstring (ISO 8601)Data/hora da liquidação (UTC)
recipient_keystring ou nullChave PIX que recebeu o pagamento (EVP, CPF, CNPJ, email ou telefone)
recipient_key_typestring ou nullTipo da chave PIX recebedora: evp, phone, email, cpf, cnpj
receiverobjectDados completos do recebedor (você). Inclui name, document, account, ispb, institution_name

Variação de payload: reconciliação pós-deploy

Em cenários raros (pod do backend morto antes do webhook sair, replay retroativo após incidente), o worker PostDeployReconciliation pode disparar pix.charge.paid com campos reduzidos — tipicamente sem receiver, payer_ispb, payer_bank_name, recipient_key nem recipient_key_type. Os campos que sempre estão presentes: event_type, status, account_id, amount, end_to_end_id, fee_amount, counterparty_name, payer_document, external_id, paid_at, tx_id (quando vinculado a QR).

Seu consumidor deve tratar todos os campos não-obrigatórios como opcionais (nil/ausente) e reconciliar pelo end_to_end_id.

qr_code_id é um UUID v4 canônico

O campo qr_code_id é sempre serializado como UUID v4 em formato canônico (36 caracteres com hífens: f401d5e3-a2b1-4c8e-9f3d-1234567890ab) — nunca como binário cru, base64 ou hex sem hífens. Use para correlação direta com a resposta de POST /api/external/pix/cash-in (campo transaction_id no seu request retorna o tx_id do QR, e qr_code_id aqui é a chave primária interna).


pix.charge.expired

Disparado automaticamente quando QR code expira sem pagamento. Executado pelo worker QrExpirationChecker com cron */5 * * * * (a cada 5 minutos, sobre QR codes cuja expires_at já passou).

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"
}
CampoTipoDescrição
event_typestringSempre pix.charge.expired
statusstringSempre expired
account_idintegerConta que emitiu o QR code
entity_idstring (UUID)Identificador da entidade Owem
tx_idstringID da cobrança/QR code
amountintegerValor esperado em subcentavos (não cobrado)
external_idstring ou nullSeu identificador externo, se enviado na criação
expired_atstring (ISO 8601)Momento em que o worker detectou a expiração (UTC) — pode ser posterior ao expires_at real do QR em até ~5 min

pix.charge.cancelled

Enviado quando um QR code é cancelado explicitamente pelo merchant antes de ser pago, via ação no portal (backend: Fluxiq.UseCases.Pix.QRCodes.cancel_qrcode/2). Não é disparado em expiração automática (use pix.charge.expired) nem em pagamento (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"
}
CampoTipoDescrição
tx_idstringID da cobrança/QR code
amountintegerValor esperado em subcentavos (não cobrado)
external_idstring ou nullSeu identificador externo, se enviado na criação
cancelled_atstring (ISO 8601)Momento em que o cancelamento foi efetivado (UTC)

Distinção entre cancelled, expired e paid

  • pix.charge.cancelled: merchant cancelou intencionalmente antes do pagamento
  • pix.charge.expired: tempo de vida do QR esgotou (worker QrExpirationChecker a cada 5 min)
  • pix.charge.paid: cobrança liquidou com sucesso

pix.charge.created

Enviado quando um QR code é gerado ou um cash-in é iniciado. Nenhum movimento financeiro ocorreu.

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"
}
CampoTipoDescrição
event_typestringSempre pix.charge.created
statusstringSempre created
amountintegerValor esperado em subcentavos
tx_idstringID da cobrança/QR code
external_idstring ou nullSeu identificador externo, retornado tal como enviado. null se não informado ou QR gerado pelo portal

pix.payout.confirmed

Enviado quando um PIX enviado é confirmado pela instituição destino. Débito 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"
  }
}
CampoTipoDescrição
event_typestringSempre pix.payout.confirmed
statusstringSempre settled — débito definitivo
amountintegerValor enviado em subcentavos
fee_amountintegerTarifa cobrada em subcentavos
end_to_end_idstringIdentificador E2E do BACEN
transaction_idstring (UUID)Identificador único da transação
external_idstring ou nullSeu identificador externo
pix_keystringChave PIX do destinatário
pix_key_typestringTipo da chave: CPF, CNPJ, EMAIL, PHONE, EVP
descriptionstring ou nullDescrição informada pelo remetente
initiated_atstring (ISO 8601)Momento em que este webhook foi disparado (UTC). Não é o timestamp do request original de cash-out nem do settlement BACEN. Para correlacionar com o momento que você enviou o POST, use o created_at do GET /api/external/transactions/ref/{external_id}; para o momento exato da entrega do webhook, use o header X-Owem-Timestamp
recipientobjectDados bancários do destinatário (resolvidos via DICT)
recipient.namestring ou nullNome do titular da conta destino
recipient.documentstring ou nullCPF/CNPJ do destinatário (somente dígitos)
recipient.ispbstring ou nullISPB da instituição destino
recipient.accountstring ou nullNúmero da conta destino
recipient.agencystring ou nullAgência da conta destino
recipient.institution_namestring ou nullNome da instituição destino (resolvido via cache BCB)
senderobjectDados bancários da conta remetente (sua conta Owem)
sender.namestring ou nullNome do titular da conta remetente
sender.documentstring ou nullCPF/CNPJ do remetente (somente dígitos)
sender.ispbstring ou nullISPB da Owem Pay (37839059)
sender.accountstring ou nullNúmero da conta remetente
sender.agencystring ou nullAgência da conta remetente

pix.payout.processing

Enviado quando um PIX enviado está sendo processado. O saldo está reservado (hold) mas não é definitivo. Este evento é opcional — se você só quer ser notificado no estado terminal, ignore-o e espere pelo pix.payout.confirmed ou 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"
  }
}
CampoTipoDescrição
event_typestringSempre pix.payout.processing
statusstringSempre processing — saldo reservado, pode reverter
amountintegerValor em subcentavos
fee_amountintegerTarifa em subcentavos (mesma tarifa que aparece em confirmed/failed posteriormente — é calculada na criação do cash-out, não após)
end_to_end_idstringIdentificador E2E do BACEN
transaction_idstring (UUID)Identificador único da transação
external_idstring ou nullSeu identificador externo
pix_keystringChave PIX do destinatário
pix_key_typestringTipo da chave: CPF, CNPJ, EMAIL, PHONE, EVP
descriptionstring ou nullDescrição informada pelo remetente
initiated_atstring (ISO 8601)Momento do dispatch deste webhook (UTC) — ver nota em pix.payout.confirmed
recipientobjectDados bancários do destinatário (resolvidos via DICT)
recipient.namestring ou nullNome do titular da conta destino
recipient.documentstring ou nullCPF/CNPJ do destinatário (somente dígitos)
recipient.ispbstring ou nullISPB da instituição destino
recipient.accountstring ou nullNúmero da conta destino
recipient.agencystring ou nullAgência da conta destino
recipient.institution_namestring ou nullNome da instituição destino
senderobjectDados bancários da conta remetente (sua conta Owem)
sender.namestring ou nullNome do titular da conta remetente
sender.documentstring ou nullCPF/CNPJ do remetente (somente dígitos)
sender.ispbstring ou nullISPB da Owem Pay (37839059)
sender.accountstring ou nullNúmero da conta remetente
sender.agencystring ou nullAgência da conta remetente

Ordem dos eventos

Um pix.payout.processing é sempre seguido (segundos a minutos depois) por um pix.payout.confirmed ou pix.payout.failed. Em transações rápidas (settlement imediato), o processing pode ser omitido e você recebe diretamente o terminal.


pix.payout.failed

Enviado quando um PIX enviado é rejeitado. Hold liberado, saldo restaurado.

Atualizado em 10/04/2026

O payload inclui os campos estruturados reason_code (código BACEN SPI de 2–6 caracteres) e reason_description (descrição em inglês). Novas integrações devem usar esses campos para roteamento programático de falhas.

Exclusão mútua: quando o backend consegue extrair um código BACEN da rejeição (ex: "rejected: AC03"), o payload envia apenas reason_code + reason_description — o campo legacy reason é removido. Quando a falha não tem código BACEN parseável (ex: timeout interno, erro de provider sem código), o payload envia apenas reason (string livre) — sem reason_code. Trate ambos os formatos no seu 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"
  }
}
CampoTipoDescrição
event_typestringSempre pix.payout.failed
statusstringSempre rejected — hold liberado, saldo restaurado
amountintegerValor em subcentavos
fee_amountintegerTarifa em subcentavos. A tarifa mostrada é o valor que teria sido cobrado — no ledger TB a transferência pending é revertida automaticamente, então na prática não há débito de tarifa em transações rejeitadas
end_to_end_idstringIdentificador E2E do BACEN
transaction_idstring (UUID)Identificador único da transação
external_idstring ou nullSeu identificador externo
pix_keystringChave PIX do destinatário
pix_key_typestringTipo da chave: CPF, CNPJ, EMAIL, PHONE, EVP
descriptionstring ou nullDescrição informada pelo remetente
initiated_atstring (ISO 8601)Momento do dispatch deste webhook (UTC)
reason_codestring ou ausenteCódigo BACEN SPI estruturado (2–6 caracteres). Exemplos: AC03, ED05, AM02, BE01, MD06, FOCR. Presente quando o backend extraiu código BACEN da rejeição. Use este campo para roteamento programático
reason_descriptionstring ou ausenteDescrição em inglês do reason_code. Presente junto com reason_code. Exemplo: "Invalid creditor account number"
reasonstring ou ausente[Legacy] Descrição livre do motivo. Presente apenas quando a rejeição não tem código BACEN parseável — mutuamente exclusivo com reason_code
recipientobjectDados bancários do destinatário (resolvidos via DICT)
recipient.namestring ou nullNome do titular da conta destino
recipient.documentstring ou nullCPF/CNPJ do destinatário (somente dígitos)
recipient.ispbstring ou nullISPB da instituição destino
recipient.accountstring ou nullNúmero da conta destino
recipient.agencystring ou nullAgência da conta destino
recipient.institution_namestring ou nullNome da instituição destino
senderobjectDados bancários da conta remetente (sua conta Owem)
sender.namestring ou nullNome do titular da conta remetente
sender.documentstring ou nullCPF/CNPJ do remetente (somente dígitos)
sender.ispbstring ou nullISPB da Owem Pay (37839059)
sender.accountstring ou nullNúmero da conta remetente
sender.agencystring ou nullAgência da conta remetente

Variações de payload entre dispatch sites

pix.payout.failed é disparado por múltiplos caminhos — o principal em pix.ex extrai código BACEN de strings "rejected: <CODE>" e aplica a exclusão mútua reason vs reason_code descrita acima. Caminhos secundários (stale checker, retry worker, reconciliação pós-deploy) podem enviar tanto reason quanto reason_code no mesmo payload, ou apenas reason sem estrutura. Trate sempre os dois campos como opcionais e prefira reason_code quando presente.

Códigos reason_code mais comuns (BACEN SPI)

CódigoSignificado em inglêsAção recomendada
AC03Invalid creditor account numberConfirmar dados bancários do destinatário com o cliente final
AC06Creditor account blockedConta destino bloqueada — não retentar
AM02Not allowed amount (limit exceeded)Valor excede limite de PIX do destino ou origem
AM04Insufficient fundsSaldo insuficiente na origem
BE01End customer not in whitelistIdentificador do destinatário não reconhecido
ED05Settlement failedFalha no settlement — pode retentar após investigação
MD06Refund requested by end customerDevolução solicitada pelo cliente final
FOCRForbidden credit returnDevolução de crédito proibida

Lista completa: consulte o Catálogo de Mensagens do SPI do BACEN.


pix.payout.returned

Enviado quando um PIX que você enviou é devolvido pelo banco destino após liquidação. Raro, mas pode ocorrer até vários dias depois. O saldo do merchant aumenta (entrada).

Distinção de nomenclatura

Três fluxos diferentes podem ser confundidos:

  • pix.return.received: um PIX que você recebeu está sendo devolvido ao pagador original. Saldo DIMINUI.
  • pix.payout.returned (este): um PIX que você enviou está voltando a você. Saldo AUMENTA.
  • pix.refund.requested: bloqueio cautelar MED em um PIX que você recebeu. Fundos congelados.

Mesmo payload, dois eventos, dois status diferentes

O backend dispara pix.return.received e pix.payout.returned na mesma chamada (arquivo return_in_handler.ex) usando o mesmo payload base com o campo status reescrito:

  • pix.return.receivedstatus: "settled" (PIX que você recebeu está sendo devolvido → saldo diminui)
  • pix.payout.returnedstatus: "returned" (PIX que você enviou está voltando → saldo aumenta)

Se sua lógica de reconciliação filtra por status ou dedup por (e2e, event_type), certifique-se de distinguir event_type primeiro — o payload é quase idêntico.

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"
}
CampoTipoDescrição
event_typestringSempre pix.payout.returned
statusstringSempre returned — devolução liquidada e creditada em sua conta
amountintegerMesmo valor que refunded_amount (mantido para compatibilidade)
original_amountintegerValor do PIX OUT original em subcentavos
refunded_amountintegerValor efetivamente devolvido nesta devolução (pode ser parcial)
fee_amountintegerTarifa cobrada nesta devolução (geralmente 0)
net_amountintegerrefunded_amount - fee_amount
is_partialbooleantrue quando refunded_amount < original_amount ou ainda restar saldo a devolver
total_refundedintegerSoma de todas as devoluções já recebidas para esta transação original (inclui esta)
remaining_refundableintegermax(original_amount - total_refunded, 0) — saldo ainda passível de devolução
return_e2e_idstringE2E da devolução (prefixo D)
end_to_end_idstringE2E da transação PIX OUT original (prefixo E)
original_transaction_idstringtransaction_id do PIX OUT original. Use para correlação com seu sistema
external_idstring ou nullSeu identificador externo da transação original (se aplicável)
return_reasonstringCódigo BACEN da devolução: MD06, BE08, FR01, SL02
return_reason_descriptionstringDescrição em inglês do return_reason
counterparty_ispbstringISPB da instituição que iniciou a devolução
counterparty_namestringNome da contraparte (instituição destino do PIX original)
counterparty_documentstring ou nullCPF/CNPJ da contraparte
counterparty_institution_namestring ou nullNome da instituição contraparte (cache BCB)
returned_atstring (ISO 8601)Momento do dispatch deste webhook (UTC)

Tarifa não é reembolsada

A tarifa do cash-out original não é reembolsada em pix.payout.returned. A tarifa foi cobrada pelo envio bem-sucedido, que realmente aconteceu. Se a regra de negócio exigir reembolso da tarifa ao cliente final, o merchant deve fazer isso separadamente.


pix.refund.requested

Enviado quando uma devolução PIX é solicitada via MED (Mecanismo Especial de Devolução). Fundos foram bloqueados cautelarmente na conta do merchant que recebeu o PIX original.

Somente PIX In

Este evento só se aplica a PIX recebidos (cash-in). Se você enviou um PIX e ele foi devolvido, receberá pix.return.received em 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"
}
CampoTipoDescrição
event_typestringSempre pix.refund.requested
statusstringSempre requested — bloqueio cautelar ativo
requested_amountintegerValor solicitado para devolução em subcentavos
block_idstring (UUID)Identificador do bloqueio cautelar
infraction_report_idstringIdentificador da infração no OnZ
e2e_idstringE2E da transação PIX original que está sendo contestada
external_idstring ou nullSeu identificador externo (se aplicável)
blocked_amountintegerValor efetivamente bloqueado em subcentavos
fee_amountintegerTarifa MED em subcentavos
fraud_categorystringCategoria da fraude alegada. Valores possíveis: SCAM, ACCOUNT_TAKEOVER, COERCION, FRAUDULENT_ACCESS, OTHER. Quando a contraparte não envia um FraudType específico, o valor é OTHER (padrão para REFUND_REQUEST).
deadlinestring (ISO 8601)Prazo para análise/defesa (UTC)
scenariostringCenário MED: cautelar ou fraude
created_atstring (ISO 8601)Data/hora do bloqueio (UTC)

pix.refund.completed

Disparado quando uma devolução MED é efetivada com sucesso. Dispara via med/processor.ex:915 durante o ciclo de MED aceito.

Formato do payload (confirmado pela 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"
}
CampoTipoDescrição
event_typestringSempre pix.refund.completed
statusstringSempre completed — devolução MED finalizada
amountintegerValor devolvido em subcentavos
block_idstring (UUID)Identificador do bloqueio cautelar
infraction_report_idstringIdentificador da infração OnZ
e2e_idstringE2E da transação PIX original
external_idstring ou nullSeu identificador externo (se aplicável)
reasonstringMotivo da liberação (ex: analysis_unfounded, manual_release)
completed_atstring (ISO 8601)Data/hora da conclusão (UTC)

pix.return.received

Enviado quando uma devolução PIX é recebida. Este evento é gerado quando um PIX que você recebeu anteriormente (cash-in) está sendo devolvido ao pagador original. O saldo do merchant diminui.

Distinção de nomenclatura

  • pix.return.received (este): um PIX que você recebeu está sendo devolvido ao pagador original. Saldo DIMINUI.
  • pix.payout.returned: um PIX que você enviou está voltando a você. Saldo AUMENTA.

Os nomes são inversos ao que o significado comum sugere — preste atenção.

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"
}
CampoTipoDescrição
event_typestringSempre pix.return.received
statusstringSempre settled — devolução liquidada
amountintegerMesmo valor que refunded_amount (mantido para compatibilidade)
original_amountintegerValor do PIX IN original em subcentavos
refunded_amountintegerValor efetivamente devolvido nesta devolução (pode ser parcial)
fee_amountintegerTarifa cobrada nesta devolução
net_amountintegerrefunded_amount - fee_amount
is_partialbooleantrue quando a devolução não cobre o valor total do PIX IN original
total_refundedintegerSoma de todas as devoluções já enviadas para esta transação (inclui esta)
remaining_refundableintegerSaldo ainda passível de devolução
return_e2e_idstringE2E da devolução (prefixo D)
end_to_end_idstringE2E da transação PIX IN original (prefixo E)
original_transaction_idstringtransaction_id do PIX IN original. Use para correlação com seu sistema
external_idstring ou nullSeu identificador externo da transação original (se aplicável)
return_reasonstringCódigo BACEN da devolução: MD06, BE08, FR01, SL02
return_reason_descriptionstringDescrição em inglês do return_reason
counterparty_ispbstringISPB da instituição que está recebendo a devolução
counterparty_namestringNome da contraparte (pagador original do PIX IN)
counterparty_documentstring ou nullCPF/CNPJ da contraparte
counterparty_institution_namestring ou nullNome da instituição contraparte (cache BCB)
returned_atstring (ISO 8601)Momento do dispatch deste webhook (UTC)

Deduplicação

Para deduplicar retries de webhook, use o header X-Owem-Event-Id OU a combinação (return_e2e_id, end_to_end_id). O return_e2e_id começa com D (devolução) e o end_to_end_id começa com E (original).


webhook.test

Evento de teste disparado manualmente para validar a configuração do 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 quando uma infração PIX é reportada pela contraparte (via BACEN DICT). Requer defesa até defense_deadline OU bloqueio cautelar automático (MED).

Disparado por pix_compliance.ex:463 (função upsert_infraction quando 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"
}
CampoTipoDescrição
event_typestringSempre pix.infraction.created
infraction_idstring (UUID)ID interno da infração
e2e_idstringE2E da transação contestada
statusstringStatus BACEN: ACKNOWLEDGED, CLOSED, CANCELLED
infraction_typestringTipo BACEN: REFUND_REQUEST, REFUND_CANCELLED, FRAUD
amountintegerValor em subcentavos
defense_deadlinestring (ISO 8601)Prazo para submissão de defesa
counterpart_ispbstring (8 dígitos)ISPB da instituição contraparte
account_idintegerSua conta afetada
merchant_idstring (UUID)Seu merchant_id

Ação obrigatória

Infrações com status ACKNOWLEDGED e valor > R$1.000 geram bloqueio cautelar automático (MED). Você deve responder via POST /api/merchant/infractions/{id}/defense antes do defense_deadline ou a devolução será executada.


pix.infraction.resolved

Disparado quando uma infração é resolvida (admin close ou auto-deny). Libera bloqueio cautelar se houver.

Disparado por pix_compliance.ex:664 e 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"
}
CampoTipoDescrição
analysis_resultstringAGREED (devolve), DISAGREED (nega)
analysis_detailsstringJustificativa da decisão
Demais camposIdênticos a pix.infraction.created

pix.infraction.defense_submitted

Disparado quando o merchant submete defesa contra infração (via portal ou API).

Disparado por admin/infractions/defense_controller.ex:67 e 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"
}
CampoTipoDescrição
event_typestringSempre pix.infraction.defense_submitted
statusstringSempre defense_submitted
infraction_idstring (UUID)ID da infração sendo defendida

Aguarda análise BACEN

Após submissão, BACEN analisa a defesa + evidências da contraparte. Resultado via pix.infraction.resolved.


pix.payout.queued

Disparado quando PIX OUT é automaticamente colocado em fila de retry (feature do retry queue pix_out_retry_queue_enabled, disponível desde sessão 155). Motivos: rate limit do ClientLimiter por merchant ou exaustão do bucket DICT BACEN compartilhado.

Disparado por pix.ex:315 (módulo 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
}
CampoTipoDescrição
event_typestringSempre pix.payout.queued
statusstringSempre queued
account_idintegerConta que originou o PIX OUT
merchant_idstring (UUID)Seu merchant_id
transaction_idstringIdentificador da transação Owem
end_to_end_idstringE2E BACEN gerado para o PIX OUT
amountintegerValor em subcentavos
external_idstring ou nullSeu identificador externo (se enviado no request original)
reasonstringMotivo do enfileiramento (snake_case). Valores conhecidos: dict_client_rate_limited (limite por merchant), dict_bucket_exhausted (bucket DICT BACEN compartilhado esgotado), dict_rate_limited (fallback genérico)
reason_codestringCódigo interno em UPPERCASE correlato ao reason. Valores: DICT_CLIENT_RATE_LIMITED, DICT_BUCKET_EXHAUSTED, DICT_RATE_LIMITED. Não é um código BACEN SPI (como AC03, AM02) — o enfileiramento acontece antes do envio ao BACEN, por isso os códigos são internos da Owem
reason_descriptionstringDescrição em inglês do motivo
queued_atstring (ISO 8601)Momento em que entrou na fila (UTC)
estimated_retry_secondsintegerIntervalo de retry do worker (3 s por default); a fila não garante 3 s — pode demorar se o bucket demorar para liberar
queue_ttl_secondsintegerTTL máximo na fila em segundos (7200 = 2 h). Após expirar, request vai para failed com motivo queue_ttl_expired

reason_code aqui não é BACEN SPI

Note que em pix.payout.queued o reason_code é um código interno Owem em UPPERCASE (DICT_CLIENT_RATE_LIMITED, etc.). Em pix.payout.failed o reason_code é código BACEN SPI (ex: AC03, AM02, ED05). Os dois campos têm o mesmo nome mas vocabulários diferentes — trate cada evento separadamente no seu consumidor.

Retry automático

Requests enfileiradas são retentadas automaticamente pelo worker a cada ~3s enquanto houver TTL. Em condições normais o processamento volta assim que o limite por merchant ou o bucket DICT BACEN liberar capacidade, mas isso não é SLA de 3–10 min. Próximo evento: pix.payout.processing (quando sair da fila e for enviado ao BACEN). Caso o TTL de 2 h expire sem sucesso, você recebe pix.payout.failed com reason="queue_ttl_expired".


Como interpretar os webhooks

Para confirmar que dinheiro entrou na conta: Aguarde pix.charge.paid com status: "paid". Este é o único evento que garante que o valor foi creditado e a taxa cobrada.

Para confirmar que dinheiro saiu da conta: Aguarde pix.payout.confirmed com status: "settled". O status processing é intermediário — o saldo está reservado mas pode ser revertido se rejeitado.

Para devoluções: pix.return.received com status: "settled" confirma devolução liquidada e creditada na conta.

Deduplicação: Use o header X-Owem-Event-Id ou o campo end_to_end_id como chave de idempotência.

Owem Pay Instituição de Pagamento — ISPB 37839059