# 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`.

::: tip Headers de segurança
Cada notificação inclui os headers `X-Monetarie-Signature` (HMAC-SHA256), `X-Monetarie-Timestamp`, `X-Monetarie-Event-Id` e `X-Monetarie-Event-Type`. Consulte [Webhooks - Visão Geral](/webhooks) 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.

| Evento | Status | Significado | Dinheiro liquidado? |
|--------|--------|-------------|---------------------|
| `pix.charge.created` | `created` | QR code gerado ou cash-in iniciado. Aguardando pagamento. | **Não** - apenas criado |
| `pix.charge.paid` | `paid` | PIX recebido e **liquidado em conta**. Saldo atualizado, taxa cobrada. | **Sim** |
| `pix.charge.expired` | `expired` | QR code expirou sem pagamento. | N/A |
| `pix.charge.cancelled` | `cancelled` | QR code cancelado explicitamente pelo merchant antes do pagamento. | N/A |
| `pix.payout.queued` | `queued` | PIX enviado aguardando reprocessamento automático por limite DICT. Sem débito ainda. | **Não** -- aguardando disponibilidade |
| `pix.payout.processing` | `processing` | PIX enviado, aguardando confirmação do destino. Saldo reservado (hold). | **Não** - pode reverter |
| `pix.payout.confirmed` | `settled` | PIX enviado **confirmado** pelo destino. Débito definitivo. | **Sim** |
| `pix.payout.failed` | `rejected` | PIX enviado rejeitado pelo destino. Hold liberado, saldo restaurado. | **Não** |
| `pix.payout.returned` | `returned` | PIX enviado devolvido após liquidação. | **Sim** (reverso) |
| `pix.refund.requested` | `requested` | Devolução PIX solicitada (MED). Bloqueio cautelar criado. | Parcial |
| `pix.refund.completed` | `settled` / `completed` | Devolução PIX concluída e liquidada. Débito definitivo. | **Sim** |
| `pix.refund.failed` | `failed` | Devolução PIX que você iniciou foi rejeitada pelo SPI. Saldo restaurado. | **Não** (reverso) |
| `pix.return.received` | `settled` | Devolução PIX recebida e liquidada (crédito na conta). | **Sim** |
| `pix.infraction.created` | `ACKNOWLEDGED` | Infração PIX reportada contra você. Requer ação. | Parcial - pode haver valor em disputa |
| `pix.infraction.resolved` | `CLOSED` / `CANCELLED` | Infração resolvida (devolução executada ou negada). | N/A - efeito em outro evento |
| `pix.infraction.defense_submitted` | `defense_submitted` | Defesa submetida pelo merchant. Aguardando BACEN. | N/A |
| `webhook.test` | `test` | Evento 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`).

---

## Aviso de contrato (auditoria 2026-07-25)

O corpo entregue usa **camelCase** (`accountId`, `endToEndId`, `payerDocument`) e
sempre carrega **`eventType`**. O tipo do evento tambem viaja no header
`X-Monetarie-Event-Type` — use o que preferir.

Atencao a uma diferenca deliberada: a **API HTTP de gestao de webhooks**
(`POST /api/external/webhooks`, `GET /webhooks/:id`) responde em **snake_case**
(`is_active`, `created_at`). Só o **corpo entregue no seu endpoint** e camelCase.

### Forma estavel: campo documentado nunca vem ausente

Todo campo listado nas tabelas deste catalogo **sempre existe no corpo**. Quando
nao temos o dado, ele chega **`null`** — nunca ausente. A diferenca importa: com
`null` voce faz destructuring sem quebrar e distingue "nao temos" de "campo que
nao existe".

Isso vale mesmo quando o mesmo evento nasce por caminhos internos diferentes.
Um `pix.charge.paid` originado pela liquidacao instantanea e outro originado
pela reconciliacao chegam com **a mesma forma**; o que muda e quanto do
conteudo esta preenchido.

### Apelidos de campo

Alguns campos viajam com dois nomes, para compatibilidade. Os dois carregam o
**mesmo valor** — use o que preferir:

| evento | campo | apelido |
|---|---|---|
| `pix.payout.confirmed` / `.processing` / `.failed` | `payer` | `sender` |
| `pix.infraction.*` | `endToEndId` | `e2eId` |
| `pix.refund.requested` / `.completed` | `endToEndId` | `e2eId` |

### Eventos que ainda NAO sao emitidos

Os eventos abaixo estao previstos no roadmap e **nao sao disparados hoje**. Nao
construa fluxo que dependa deles ate que este aviso saia daqui:

| evento | situacao |
|---|---|
| `pix.charge.cancelled` | nao emitido |
| `pix.charge.expired` | nao emitido |
| `pix.payout.held` | nao emitido |
| `tef.transfer.sent` | nao emitido (use `transfer.received`/`transfer.confirmed`) |
| `tef.transfer.received` | nao emitido (use `transfer.received`) |
| `tef.transfer.failed` | nao emitido (use `transfer.failed`) |

### Eventos emitidos que faltavam neste catalogo

| evento | quando dispara |
|---|---|
| `pix.received` | PIX recebido em conta (entrada organica, sem QR emitido por voce) |
| `pix.key.registered` | chave PIX registrada no DICT |
| `transfer.received` | transferencia interna recebida |
| `transfer.confirmed` | transferencia interna confirmada |
| `transfer.failed` | transferencia interna falhou |
| `ted.received` | TED recebida |
| `ted.failed` | TED falhou |
| `ted.refund.requested` | devolucao de TED solicitada |
| `account.created` | conta criada |
| `fee.charged` | tarifa cobrada |

O catalogo autoritativo em tempo real e `GET /webhooks/events`.

## Campos comuns

Todos os payloads de webhook incluem estes campos:

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Tipo do evento que disparou o webhook (ex: `pix.charge.paid`) |
| `status` | string | Status da operação - consulte a [Referência de Status](#referencia-de-status) |
| `accountId` | integer | Número da sua conta na Monetarie |
| `entityId` | string (UUID) | Identificador da entidade Monetarie |

**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
{
  "eventType": "pix.charge.paid",
  "status": "paid",
  "accountId": 10014,
  "amount": 300000,
  "feeAmount": 400,
  "endToEndId": "E9040088820260402095758709999671",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "txId": "u5f26sfyrq4plkw7tjwa",
  "qrCodeId": "f401d5e3-a2b1-4c8e-9f3d-1234567890ab",
  "counterpartyName": "MARIA SANTOS",
  "payerDocument": "12345678901",
  "payerIspb": "60701190",
  "payerBankName": "Itau Unibanco S.A.",
  "externalId": "order-9876",
  "paidAt": "2026-04-02T09:58:05Z",
  "recipientKey": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "recipientKeyType": "evp",
  "receiver": {
    "name": "PENHOTA GESTAO E INTERMEDIACAO LTDA",
    "document": "62188010000150",
    "account": "0000000019",
    "ispb": "46026562",
    "institutionName": "MONETARIE IP"
  }
}
```

### Exemplo - transferência direta (sem QR)

```json
{
  "eventType": "pix.charge.paid",
  "status": "paid",
  "accountId": 10014,
  "amount": 300000,
  "feeAmount": 400,
  "endToEndId": "E9040088820260402095758709999671",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "txId": null,
  "qrCodeId": null,
  "counterpartyName": "JOAO SILVA",
  "payerDocument": "98765432100",
  "payerIspb": "00000000",
  "payerBankName": "Banco do Brasil S.A.",
  "externalId": null,
  "paidAt": "2026-04-02T10:15:22Z",
  "recipientKey": "12345678901",
  "recipientKeyType": "cpf",
  "receiver": {
    "name": "PENHOTA GESTAO E INTERMEDIACAO LTDA",
    "document": "62188010000150",
    "account": "0000000019",
    "ispb": "46026562",
    "institutionName": "MONETARIE IP"
  }
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.charge.paid` |
| `status` | string | Sempre `paid` |
| `accountId` | integer | Número da conta que recebeu o PIX |
| `amount` | integer | Valor recebido em subcentavos. `300000` = R$ 30,00 |
| `feeAmount` | integer | Tarifa cobrada em subcentavos. `400` = R$ 0,04 |
| `endToEndId` | string | Identificador E2E do BACEN (único por transação PIX) |
| `entityId` | string (UUID) | Identificador da entidade Monetarie |
| `txId` | string ou null | ID da transação. Presente quando vinculado a um QR code. `null` para transferências diretas |
| `qrCodeId` | string ou null | UUID do QR code vinculado. `null` para transferências diretas |
| `counterpartyName` | string ou null | Nome do pagador (remetente) |
| `payerDocument` | string ou null | CPF/CNPJ do pagador (somente dígitos) |
| `payerIspb` | string ou null | ISPB (8 dígitos) da instituição do pagador |
| `payerBankName` | string ou null | Nome da instituição do pagador, resolvido via cache BCB (896 bancos) |
| `externalId` | string ou null | Seu identificador externo. Presente quando o QR code foi criado via API com external_id. `null` para transferências diretas ou QR sem external_id |
| `paidAt` | string (ISO 8601) | Data/hora da liquidação (UTC) |
| `recipientKey` | string ou null | Chave PIX que recebeu o pagamento (EVP, CPF, CNPJ, email ou telefone) |
| `recipientKeyType` | string ou null | Tipo da chave PIX recebedora: `evp`, `phone`, `email`, `cpf`, `cnpj` |
| `receiver` | object | Dados completos do recebedor (você). Inclui `name`, `document`, `account`, `ispb`, `institution_name` |

::: warning Variação de payload: reconciliação operacional
Em cenários raros de reconciliação operacional ou replay retroativo após incidente, `pix.charge.paid` pode chegar 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`.
:::

::: tip `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. A verificação de expiração roda periodicamente e pode registrar o evento alguns minutos após o `expires_at` real.

```json
{
  "eventType": "pix.charge.expired",
  "status": "expired",
  "accountId": 10014,
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "txId": "abc123def456ghi789",
  "amount": 500000,
  "externalId": "order-9876",
  "expiredAt": "2026-04-02T14:30:00Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.charge.expired` |
| `status` | string | Sempre `expired` |
| `accountId` | integer | Conta que emitiu o QR code |
| `entityId` | string (UUID) | Identificador da entidade Monetarie |
| `txId` | string | ID da cobrança/QR code |
| `amount` | integer | Valor esperado em subcentavos (não cobrado) |
| `externalId` | string ou null | Seu identificador externo, se enviado na criação |
| `expiredAt` | string (ISO 8601) | Momento em que a API registrou a expiração (UTC) - pode ser posterior ao `expires_at` real do QR em alguns minutos |

---

## pix.charge.cancelled

Enviado quando um QR code é cancelado explicitamente pelo merchant antes de ser pago, via ação no portal. Não é disparado em expiração automática (use `pix.charge.expired`) nem em pagamento (`pix.charge.paid`).

```json
{
  "eventType": "pix.charge.cancelled",
  "status": "cancelled",
  "txId": "abc123def456ghi789",
  "amount": 500000,
  "accountId": 10014,
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "externalId": "order-9876",
  "cancelledAt": "2026-04-23T12:30:00Z"
}
```

| Campo | Tipo | Descrição |
|---|---|---|
| `txId` | string | ID da cobrança/QR code |
| `amount` | integer | Valor esperado em subcentavos (não cobrado) |
| `externalId` | string ou null | Seu identificador externo, se enviado na criação |
| `cancelledAt` | string (ISO 8601) | Momento em que o cancelamento foi efetivado (UTC) |

::: info 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
- `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
{
  "eventType": "pix.charge.created",
  "status": "created",
  "accountId": 10014,
  "amount": 500000,
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "txId": "abc123def456ghi789",
  "externalId": "order-9876"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.charge.created` |
| `status` | string | Sempre `created` |
| `amount` | integer | Valor esperado em subcentavos |
| `txId` | string | ID da cobrança/QR code |
| `externalId` | string ou null | Seu identificador externo, retornado tal como enviado. `null` se não informado ou QR gerado pelo portal |

---

## pix.payout.held

Enviado quando um PIX enviado fica **retido para análise no agente de liquidação** (fila de autorização/anti-fraude, status SPI `AGUARDANDO_AUTORIZACAO`). A operação NÃO falhou: ela liquida (`pix.payout.confirmed`) ou é rejeitada (`pix.payout.failed`) quando o agente decide - tipicamente em minutos. **Não reenvie o pagamento**: o valor segue reservado e um reenvio criaria um pagamento duplicado. O evento é emitido no máximo uma vez por operação, após ~2 minutos sem confirmação.

```json
{
  "eventType": "pix.payout.held",
  "status": "processing",
  "accountId": 10014,
  "amount": 500000,
  "endToEndId": "E4602656220260402101500000001",
  "transactionId": "PIXOUT1027803798e62a0f502761008061",
  "externalId": "payment-456",
  "reason": "held_at_settlement_agent",
  "spiStatus": "AGUARDANDO_AUTORIZACAO",
  "heldSince": "2026-06-10T16:45:36Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.payout.held` |
| `status` | string | Sempre `processing` - estado não-terminal |
| `reason` | string | Sempre `held_at_settlement_agent` |
| `spiStatus` | string | Status SPI consultado no momento da emissão (ex.: `AGUARDANDO_AUTORIZACAO`) |
| `heldSince` | string (ISO 8601) | Momento do envio da PACS.008 (início da retenção) |
| `amount` | integer | Valor em subcentavos |
| `externalId` | string ou null | Seu identificador externo |

---

## pix.payout.confirmed

Enviado quando um PIX enviado é **confirmado** pela instituição destino. Débito definitivo.

```json
{
  "eventType": "pix.payout.confirmed",
  "status": "settled",
  "accountId": 10014,
  "amount": 500000,
  "feeAmount": 200,
  "endToEndId": "E4602656220260402101500000001",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "externalId": "payment-456",
  "pixKey": "destinatario@email.com",
  "pixKeyType": "EMAIL",
  "description": "Pagamento fornecedor",
  "initiatedAt": "2026-04-02T10:14:59Z",
  "recipient": {
    "name": "EMPRESA DESTINO LTDA",
    "document": "12345678000199",
    "ispb": "60701190",
    "account": "12345678",
    "agency": "0001",
    "institutionName": "Itau Unibanco S.A."
  },
  "sender": {
    "name": "MINHA EMPRESA LTDA",
    "document": "98765432000100",
    "ispb": "46026562",
    "account": "00001234",
    "agency": "0001"
  }
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.payout.confirmed` |
| `status` | string | Sempre `settled` - débito definitivo |
| `amount` | integer | Valor enviado em subcentavos |
| `feeAmount` | integer | Tarifa cobrada em subcentavos |
| `endToEndId` | string | Identificador E2E do BACEN |
| `transactionId` | string (UUID) | Identificador único da transação |
| `externalId` | string ou null | Seu identificador externo |
| `pixKey` | string | Chave PIX do destinatário |
| `pixKeyType` | string | Tipo da chave: `CPF`, `CNPJ`, `EMAIL`, `PHONE`, `EVP` |
| `description` | string ou null | Descrição informada pelo remetente |
| `initiatedAt` | string (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-Monetarie-Timestamp` |
| `recipient` | object | Dados bancários do destinatário (resolvidos via DICT) |
| `recipient.name` | string ou null | Nome do titular da conta destino |
| `recipient.document` | string ou null | CPF/CNPJ do destinatário (somente dígitos) |
| `recipient.ispb` | string ou null | ISPB da instituição destino |
| `recipient.account` | string ou null | Número da conta destino |
| `recipient.agency` | string ou null | Agência da conta destino |
| `recipient.institution_name` | string ou null | Nome da instituição destino (resolvido via cache BCB) |
| `sender` | object | Dados bancários da conta remetente (sua conta Monetarie) |
| `sender.name` | string ou null | Nome do titular da conta remetente |
| `sender.document` | string ou null | CPF/CNPJ do remetente (somente dígitos) |
| `sender.ispb` | string ou null | ISPB da Monetarie (`46026562`) |
| `sender.account` | string ou null | Número da conta remetente |
| `sender.agency` | string ou null | Agê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
{
  "eventType": "pix.payout.processing",
  "status": "processing",
  "accountId": 10014,
  "amount": 500000,
  "feeAmount": 200,
  "endToEndId": "E4602656220260402101500000001",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "externalId": "payment-456",
  "pixKey": "destinatario@email.com",
  "pixKeyType": "EMAIL",
  "description": "Pagamento fornecedor",
  "initiatedAt": "2026-04-02T10:14:59Z",
  "recipient": {
    "name": "EMPRESA DESTINO LTDA",
    "document": "12345678000199",
    "ispb": "60701190",
    "account": "12345678",
    "agency": "0001",
    "institutionName": "Itau Unibanco S.A."
  },
  "sender": {
    "name": "MINHA EMPRESA LTDA",
    "document": "98765432000100",
    "ispb": "46026562",
    "account": "00001234",
    "agency": "0001"
  }
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.payout.processing` |
| `status` | string | Sempre `processing` - saldo reservado, pode reverter |
| `amount` | integer | Valor em subcentavos |
| `feeAmount` | integer | Tarifa em subcentavos (mesma tarifa que aparece em `confirmed`/`failed` posteriormente - é calculada na criação do cash-out, não após) |
| `endToEndId` | string | Identificador E2E do BACEN |
| `transactionId` | string (UUID) | Identificador único da transação |
| `externalId` | string ou null | Seu identificador externo |
| `pixKey` | string | Chave PIX do destinatário |
| `pixKeyType` | string | Tipo da chave: `CPF`, `CNPJ`, `EMAIL`, `PHONE`, `EVP` |
| `description` | string ou null | Descrição informada pelo remetente |
| `initiatedAt` | string (ISO 8601) | Momento do dispatch deste webhook (UTC) - ver nota em `pix.payout.confirmed` |
| `recipient` | object | Dados bancários do destinatário (resolvidos via DICT) |
| `recipient.name` | string ou null | Nome do titular da conta destino |
| `recipient.document` | string ou null | CPF/CNPJ do destinatário (somente dígitos) |
| `recipient.ispb` | string ou null | ISPB da instituição destino |
| `recipient.account` | string ou null | Número da conta destino |
| `recipient.agency` | string ou null | Agência da conta destino |
| `recipient.institution_name` | string ou null | Nome da instituição destino |
| `sender` | object | Dados bancários da conta remetente (sua conta Monetarie) |
| `sender.name` | string ou null | Nome do titular da conta remetente |
| `sender.document` | string ou null | CPF/CNPJ do remetente (somente dígitos) |
| `sender.ispb` | string ou null | ISPB da Monetarie (`46026562`) |
| `sender.account` | string ou null | Número da conta remetente |
| `sender.agency` | string ou null | Agência da conta remetente |

::: tip 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.

::: tip 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 a API identifica um código BACEN na 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
{
  "eventType": "pix.payout.failed",
  "status": "rejected",
  "accountId": 10014,
  "amount": 500000,
  "feeAmount": 200,
  "endToEndId": "E4602656220260402101500000001",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "externalId": "payment-456",
  "pixKey": "destinatario@email.com",
  "pixKeyType": "EMAIL",
  "description": "Pagamento fornecedor",
  "initiatedAt": "2026-04-02T10:14:59Z",
  "reasonCode": "AC03",
  "reasonDescription": "Invalid creditor account number",
  "reason": "Conta destinatario nao encontrada",
  "recipient": {
    "name": "EMPRESA DESTINO LTDA",
    "document": "12345678000199",
    "ispb": "60701190",
    "account": "12345678",
    "agency": "0001",
    "institutionName": "Itau Unibanco S.A."
  },
  "sender": {
    "name": "MINHA EMPRESA LTDA",
    "document": "98765432000100",
    "ispb": "46026562",
    "account": "00001234",
    "agency": "0001"
  }
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.payout.failed` |
| `status` | string | Sempre `rejected` - hold liberado, saldo restaurado |
| `amount` | integer | Valor em subcentavos |
| `feeAmount` | integer | Tarifa 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 |
| `endToEndId` | string | Identificador E2E do BACEN |
| `transactionId` | string (UUID) | Identificador único da transação |
| `externalId` | string ou null | Seu identificador externo |
| `pixKey` | string | Chave PIX do destinatário |
| `pixKeyType` | string | Tipo da chave: `CPF`, `CNPJ`, `EMAIL`, `PHONE`, `EVP` |
| `description` | string ou null | Descrição informada pelo remetente |
| `initiatedAt` | string (ISO 8601) | Momento do dispatch deste webhook (UTC) |
| `reasonCode` | string ou ausente | **Código BACEN SPI estruturado** (2-6 caracteres). Exemplos: `AC03`, `ED05`, `AM02`, `BE01`, `MD06`, `FOCR`. Presente quando a API identificou código BACEN na rejeição. Use este campo para roteamento programático |
| `reasonDescription` | string ou ausente | Descrição em inglês do `reason_code`. Presente junto com `reason_code`. Exemplo: `"Invalid creditor account number"` |
| `reason` | string 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` |
| `recipient` | object | Dados bancários do destinatário (resolvidos via DICT) |
| `recipient.name` | string ou null | Nome do titular da conta destino |
| `recipient.document` | string ou null | CPF/CNPJ do destinatário (somente dígitos) |
| `recipient.ispb` | string ou null | ISPB da instituição destino |
| `recipient.account` | string ou null | Número da conta destino |
| `recipient.agency` | string ou null | Agência da conta destino |
| `recipient.institution_name` | string ou null | Nome da instituição destino |
| `sender` | object | Dados bancários da conta remetente (sua conta Monetarie) |
| `sender.name` | string ou null | Nome do titular da conta remetente |
| `sender.document` | string ou null | CPF/CNPJ do remetente (somente dígitos) |
| `sender.ispb` | string ou null | ISPB da Monetarie (`46026562`) |
| `sender.account` | string ou null | Número da conta remetente |
| `sender.agency` | string ou null | Agência da conta remetente |

::: warning Variações de payload
`pix.payout.failed` pode ser emitido por mais de um fluxo operacional. Em alguns cenários, o payload pode enviar **tanto `reason` quanto `reason_code`**, 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ódigo | Significado em inglês | Ação recomendada |
|--------|------------------------|------------------|
| `AC03` | Invalid creditor account number | Confirmar dados bancários do destinatário com o cliente final |
| `AC06` | Creditor account blocked | Conta destino bloqueada - não retentar |
| `AM02` | Not allowed amount (limit exceeded) | Valor excede limite de PIX do destino ou origem |
| `AM04` | Insufficient funds | Saldo insuficiente na origem |
| `BE01` | End customer not in whitelist | Identificador do destinatário não reconhecido |
| `ED05` | Settlement failed | Falha no settlement - pode retentar após investigação |
| `MD06` | Refund requested by end customer | Devolução solicitada pelo cliente final |
| `FOCR` | Forbidden credit return | Devoluçã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).

::: danger 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.
:::

::: warning Mesmo payload, dois eventos, dois status diferentes
A API pode disparar `pix.return.received` e `pix.payout.returned` para a mesma devolução usando o **mesmo payload base** com o campo `status` ajustado para cada evento:

- `pix.return.received` → `status: "settled"` (PIX que **você recebeu** está sendo devolvido → saldo diminui)
- `pix.payout.returned` → `status: "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
{
  "eventType": "pix.payout.returned",
  "status": "returned",
  "accountId": 10014,
  "amount": 500000,
  "originalAmount": 500000,
  "refundedAmount": 500000,
  "feeAmount": 0,
  "netAmount": 500000,
  "isPartial": false,
  "totalRefunded": 500000,
  "remainingRefundable": 0,
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "returnE2eId": "D4602656220260410111500000001",
  "endToEndId": "E4602656220260402101500000001",
  "originalTransactionId": "PIXOUTa1b2c3d4e5f67890abcdef1234567890",
  "externalId": "payment-456",
  "returnReason": "MD06",
  "returnReasonDescription": "Refund requested by end customer",
  "counterpartyIspb": "60701190",
  "counterpartyName": "EMPRESA DESTINO LTDA",
  "counterpartyDocument": "12345678000199",
  "counterpartyInstitutionName": "Itau Unibanco S.A.",
  "returnedAt": "2026-04-10T11:15:00Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.payout.returned` |
| `status` | string | Sempre `returned` - devolução liquidada e creditada em sua conta |
| `amount` | integer | Mesmo valor que `refunded_amount` (mantido para compatibilidade) |
| `originalAmount` | integer | Valor do PIX OUT original em subcentavos |
| `refundedAmount` | integer | Valor efetivamente devolvido nesta devolução (pode ser parcial) |
| `feeAmount` | integer | Tarifa cobrada nesta devolução (geralmente `0`) |
| `netAmount` | integer | `refunded_amount - fee_amount` |
| `isPartial` | boolean | `true` quando `refunded_amount < original_amount` ou ainda restar saldo a devolver |
| `totalRefunded` | integer | Soma de **todas** as devoluções já recebidas para esta transação original (inclui esta) |
| `remainingRefundable` | integer | `max(original_amount - total_refunded, 0)` - saldo ainda passível de devolução |
| `returnE2eId` | string | E2E da devolução (prefixo `D`) |
| `endToEndId` | string | E2E da transação PIX OUT original (prefixo `E`) |
| `originalTransactionId` | string | `transaction_id` do PIX OUT original. Use para correlação com seu sistema |
| `externalId` | string ou null | Seu identificador externo da transação original (se aplicável) |
| `returnReason` | string | Código BACEN da devolução: `MD06`, `BE08`, `FR01`, `SL02` |
| `returnReasonDescription` | string | Descrição em inglês do `return_reason` |
| `counterpartyIspb` | string | ISPB da instituição que iniciou a devolução |
| `counterpartyName` | string | Nome da contraparte (instituição destino do PIX original) |
| `counterpartyDocument` | string ou null | CPF/CNPJ da contraparte |
| `counterpartyInstitutionName` | string ou null | Nome da instituição contraparte (cache BCB) |
| `returnedAt` | string (ISO 8601) | Momento do dispatch deste webhook (UTC) |

::: warning 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.

::: warning 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
{
  "eventType": "pix.refund.requested",
  "status": "requested",
  "accountId": 10014,
  "requestedAmount": 300000,
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "blockId": "b1c2d3e4-f5g6-7890-hijk-lm1234567890",
  "infractionReportId": "INF20260402001",
  "e2eId": "E9040088820260402095758709999671",
  "externalId": null,
  "blockedAmount": 300000,
  "feeAmount": 0,
  "fraudCategory": "OTHER",
  "deadline": "2026-04-09T14:30:00Z",
  "scenario": "cautelar",
  "createdAt": "2026-04-02T14:30:00Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.refund.requested` |
| `status` | string | Sempre `requested` - bloqueio cautelar ativo |
| `requestedAmount` | integer | Valor solicitado para devolução em subcentavos |
| `blockId` | string (UUID) | Identificador do bloqueio cautelar |
| `infractionReportId` | string | Identificador da infração no provedor PIX |
| `e2eId` | string | E2E da transação PIX original que está sendo contestada |
| `externalId` | string ou null | Seu identificador externo (se aplicável) |
| `blockedAmount` | integer | Valor efetivamente bloqueado em subcentavos |
| `feeAmount` | integer | Tarifa MED em subcentavos |
| `fraudCategory` | string | Categoria 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`). |
| `deadline` | string (ISO 8601) | Prazo para análise/defesa (UTC) |
| `scenario` | string | Cenário MED: `cautelar` ou `fraude` |
| `createdAt` | string (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
{
  "eventType": "pix.refund.completed",
  "status": "settled",
  "accountId": 10014,
  "amount": 300000,
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "blockId": "b1c2d3e4-f5g6-7890-hijk-lm1234567890",
  "infractionReportId": "INF20260402001",
  "e2eId": "E9040088820260402095758709999671",
  "externalId": null,
  "reason": "analysis_unfounded",
  "completedAt": "2026-04-02T14:30:00Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.refund.completed` |
| `status` | string | Sempre `completed` - devolução MED finalizada |
| `amount` | integer | Valor devolvido em subcentavos |
| `blockId` | string (UUID) | Identificador do bloqueio cautelar |
| `infractionReportId` | string | Identificador da infração no provedor PIX |
| `e2eId` | string | E2E da transação PIX original |
| `externalId` | string ou null | Seu identificador externo (se aplicável) |
| `reason` | string | Motivo da liberação (ex: `analysis_unfounded`, `manual_release`) |
| `completedAt` | string (ISO 8601) | Data/hora da conclusão (UTC) |

---

## pix.refund.failed

Disparado quando uma **devolução PIX que você iniciou** (POST de devolução) é **rejeitada** pelo SPI ou pelo participante liquidante. Estado **terminal**: o valor reservado é liberado e o saldo do cliente é restaurado. Traz o motivo estruturado em `reason_code` (código BACEN SPI, ex: `AB03`) e `reason_description`.

```json
{
  "eventType": "pix.refund.failed",
  "status": "failed",
  "transactionId": "PIXRET1400c0054e09f10f5027e1003c52",
  "endToEndId": "D4602656220260705080847fc4253817",
  "originalEndToEndId": "E2289643120260705080712345678901",
  "originalTransactionId": "PIXIN123456789",
  "originalAmount": 2000,
  "amount": 2000,
  "accountId": 10202,
  "merchantId": "ef8c0fc6-3ce4-4aff-a559-cc7b6c079b00",
  "returnCode": "MD06",
  "reason": "Devolucao PIX",
  "reasonCode": "AB03",
  "reasonDescription": "Liquidacao da transacao interrompida devido a timeout no SPI.",
  "type": "pix_return",
  "direction": "outbound",
  "occurredAt": "2026-07-05T08:08:48Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.refund.failed` |
| `status` | string | Sempre `failed` - devolução rejeitada, saldo restaurado |
| `endToEndId` | string | E2E da devolução (prefixo `D`) que foi rejeitada |
| `originalEndToEndId` | string | E2E da transação PIX original que você tentou devolver |
| `amount` | integer | Valor da devolução em subcentavos |
| `reasonCode` | string ou null | Código BACEN SPI do motivo (ex: `AB03`). `null` em rejeição síncrona sem código |
| `reasonDescription` | string ou null | Descrição do motivo retornada pelo SPI |
| `occurredAt` | string (ISO 8601) | Data/hora da rejeição (UTC) |

Uma devolução rejeitada **pode ser reenviada** (nova chamada ao POST de devolução) enquanto a transação original estiver dentro da janela de 90 dias.

---

## 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**.

::: danger 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
{
  "eventType": "pix.return.received",
  "status": "settled",
  "accountId": 10014,
  "amount": 300000,
  "originalAmount": 300000,
  "refundedAmount": 300000,
  "feeAmount": 0,
  "netAmount": 300000,
  "isPartial": false,
  "totalRefunded": 300000,
  "remainingRefundable": 0,
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "returnE2eId": "D9040088820260402111500000001",
  "endToEndId": "E9040088820260402095758709999671",
  "originalTransactionId": "PIXINE9040088820260402095758709999671",
  "externalId": null,
  "returnReason": "MD06",
  "returnReasonDescription": "Refund requested by end customer",
  "counterpartyIspb": "60701190",
  "counterpartyName": "EMPRESA X LTDA",
  "counterpartyDocument": "98765432100",
  "counterpartyInstitutionName": "Itau Unibanco S.A.",
  "returnedAt": "2026-04-02T11:15:00Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.return.received` |
| `status` | string | Sempre `settled` - devolução liquidada |
| `amount` | integer | Mesmo valor que `refunded_amount` (mantido para compatibilidade) |
| `originalAmount` | integer | Valor do PIX IN original em subcentavos |
| `refundedAmount` | integer | Valor efetivamente devolvido nesta devolução (pode ser parcial) |
| `feeAmount` | integer | Tarifa cobrada nesta devolução |
| `netAmount` | integer | `refunded_amount - fee_amount` |
| `isPartial` | boolean | `true` quando a devolução não cobre o valor total do PIX IN original |
| `totalRefunded` | integer | Soma de **todas** as devoluções já enviadas para esta transação (inclui esta) |
| `remainingRefundable` | integer | Saldo ainda passível de devolução |
| `returnE2eId` | string | E2E da devolução (prefixo `D`) |
| `endToEndId` | string | E2E da transação PIX IN original (prefixo `E`) |
| `originalTransactionId` | string | `transaction_id` do PIX IN original. Use para correlação com seu sistema |
| `externalId` | string ou null | Seu identificador externo da transação original (se aplicável) |
| `returnReason` | string | Código BACEN da devolução: `MD06`, `BE08`, `FR01`, `SL02` |
| `returnReasonDescription` | string | Descrição em inglês do `return_reason` |
| `counterpartyIspb` | string | ISPB da instituição que está recebendo a devolução |
| `counterpartyName` | string | Nome da contraparte (pagador original do PIX IN) |
| `counterpartyDocument` | string ou null | CPF/CNPJ da contraparte |
| `counterpartyInstitutionName` | string ou null | Nome da instituição contraparte (cache BCB) |
| `returnedAt` | string (ISO 8601) | Momento do dispatch deste webhook (UTC) |

::: tip Deduplicação
Para deduplicar retries de webhook, use o header `X-Monetarie-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
{
  "eventType": "webhook.test",
  "status": "test",
  "accountId": 10014,
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "message": "Webhook test event"
}
```

---

## pix.infraction.created

Disparado quando uma infração PIX é reportada pela contraparte (via BACEN DICT). Use o `defense_deadline` para acompanhar o prazo de resposta.

```json
{
  "eventType": "pix.infraction.created",
  "infractionId": "e7f4d23a-6f2a-4d1e-a3e6-fe8b32bba95d",
  "e2eId": "E0416201020260404113012abcdef1234",
  "status": "ACKNOWLEDGED",
  "infractionType": "REFUND_REQUEST",
  "situation": "SCAM",
  "amount": 1500000,
  "analysisResult": null,
  "analysisDetails": null,
  "creationTime": "2026-04-14T18:00:00Z",
  "defenseDeadline": "2026-04-21T23:59:59Z",
  "counterpartIspb": "60701190",
  "accountId": 10011,
  "merchantId": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7"
}
```

::: tip Disparado apenas na criação
Este evento é emitido **somente** quando uma infração nova é inserida - atualizações e re-syncs da mesma infração **não** re-emitem `pix.infraction.created`. Para a resolução, assine [`pix.infraction.resolved`](#pix-infraction-resolved).
:::

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.infraction.created` |
| `infractionId` | string (UUID) | ID interno da infração |
| `e2eId` | string | E2E da transação contestada |
| `status` | string | Status BACEN: `ACKNOWLEDGED`, `CLOSED`, `CANCELLED` |
| `infractionType` | string | Tipo BACEN: `REFUND_REQUEST`, `REFUND_CANCELLED`, `FRAUD` |
| `situation` | string \| null | Situação/tipo de fraude: `SCAM`, `ACCOUNT_TAKEOVER`, `COERCION`, `FRAUDULENT_ACCESS`, `OTHER` |
| `amount` | integer | Valor em subcentavos |
| `creationTime` | string (ISO 8601) \| null | Data de abertura da infração |
| `defenseDeadline` | string (ISO 8601) | Prazo para submissão de defesa |
| `counterpartIspb` | string (8 dígitos) | ISPB da instituição contraparte |
| `accountId` | integer | Sua conta afetada |
| `merchantId` | string (UUID) | Seu merchant_id |
| `entityId` | string (UUID) | Sua entidade |

::: warning Ação necessária
Infrações com status `ACKNOWLEDGED` podem exigir análise MED. Responda pelo portal ou pela API externa (`POST /api/external/med/:id/defense`) antes do `defense_deadline` quando houver defesa e evidências.
:::

---

## pix.infraction.resolved

Disparado quando uma infração é resolvida. Informa o resultado final e libera o fluxo financeiro aplicável.

```json
{
  "eventType": "pix.infraction.resolved",
  "infractionId": "e7f4d23a-6f2a-4d1e-a3e6-fe8b32bba95d",
  "e2eId": "E0416201020260404113012abcdef1234",
  "status": "CLOSED",
  "infractionType": "REFUND_REQUEST",
  "amount": 1500000,
  "analysisResult": "DISAGREED",
  "analysisDetails": "Verificado pelo time de compliance e sem evidencias concretas nao temos como fazer devolucao",
  "defenseDeadline": "2026-04-21T23:59:59Z",
  "counterpartIspb": "60701190",
  "accountId": 10011,
  "merchantId": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `analysisResult` | string | `AGREED` (devolve), `DISAGREED` (nega) |
| `analysisDetails` | string | Justificativa da decisão |
| Demais campos | | Idênticos a `pix.infraction.created` |

---

## pix.infraction.defense_submitted

Disparado quando uma defesa é registrada contra infração/MED via portais Monetarie ou API externa.

```json
{
  "eventType": "pix.infraction.defense_submitted",
  "infractionId": "e7f4d23a-6f2a-4d1e-a3e6-fe8b32bba95d",
  "blockId": "3f1e2c41-c269-4fa8-a151-49e739f8d37d",
  "e2eId": "E0416201020260404113012abcdef1234",
  "endToEndId": "E0416201020260404113012abcdef1234",
  "status": "defense_submitted",
  "accountId": 10011,
  "merchantId": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.infraction.defense_submitted` |
| `status` | string | Sempre `defense_submitted` |
| `infractionId` | string (UUID) | ID da infração sendo defendida |
| `blockId` | string (UUID) | ID do bloqueio MED cautelar, quando aplicável |
| `e2e_id` / `end_to_end_id` | string | E2E da transação contestada |

::: tip Evidências armazenadas
Os anexos da defesa ficam armazenados na Monetarie para análise e auditoria. O fechamento enviado ao provider usa `AnalysisResult` e `AnalysisDetails`; o resultado final chega via `pix.infraction.resolved`.
:::

---

## pix.payout.queued

Disparado quando PIX OUT é automaticamente colocado em fila de nova tentativa. Motivos comuns: limite operacional por merchant ou indisponibilidade temporária de capacidade DICT BACEN.


```json
{
  "eventType": "pix.payout.queued",
  "status": "queued",
  "accountId": 10011,
  "merchantId": "1b2db911-972f-4466-9be9-60a7c5450064",
  "transactionId": "PIXOUT0200806193e0984f830569",
  "endToEndId": "E4602656220260421133012abcdef1234",
  "amount": 200,
  "externalId": "payment-456",
  "reason": "dict_client_rate_limited",
  "reasonCode": "DICT_CLIENT_RATE_LIMITED",
  "reasonDescription": "Merchant exceeded per-minute DICT lookup quota",
  "queuedAt": "2026-04-21T13:30:12Z",
  "estimatedRetrySeconds": 3,
  "queueTtlSeconds": 7200
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `pix.payout.queued` |
| `status` | string | Sempre `queued` |
| `accountId` | integer | Conta que originou o PIX OUT |
| `merchantId` | string (UUID) | Seu merchant_id |
| `transactionId` | string | Identificador da transação Monetarie |
| `endToEndId` | string | E2E BACEN gerado para o PIX OUT |
| `amount` | integer | Valor em subcentavos |
| `externalId` | string ou null | Seu identificador externo (se enviado no request original) |
| `reason` | string | Motivo 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) |
| `reasonCode` | string | **Có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 Monetarie |
| `reasonDescription` | string | Descrição em inglês do motivo |
| `queuedAt` | string (ISO 8601) | Momento em que entrou na fila (UTC) |
| `estimatedRetrySeconds` | integer | Intervalo estimado de nova tentativa; a fila não garante esse tempo e pode demorar se a capacidade externa demorar para liberar |
| `queueTtlSeconds` | integer | TTL máximo na fila em segundos (7200 = 2 h). Após expirar, request vai para `failed` com motivo `queue_ttl_expired` |

::: warning `reason_code` aqui não é BACEN SPI
Note que em `pix.payout.queued` o `reason_code` é um código **interno Monetarie** 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.
:::

::: tip Retry automático
Requests enfileiradas são retentadas automaticamente 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"`.
:::

---

## tef.transfer.sent

Disparado quando uma TEF entre contas Monetarie é liquidada para a conta de origem.

Disparado quando a TED/TEF de saída é efetivamente registrada para processamento.

```json
{
  "eventType": "tef.transfer.sent",
  "transactionId": "TEF202605300001",
  "accountId": 10011,
  "senderAccountId": 10011,
  "receiverAccountId": 10012,
  "merchantId": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "amount": 20000,
  "description": "Repasse interno",
  "settledAt": "2026-05-30T13:30:12Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `tef.transfer.sent` |
| `accountId` | integer | Conta de origem assinante do webhook |
| `senderAccountId` | integer | Conta que enviou a TEF |
| `receiverAccountId` | integer | Conta que recebeu a TEF |
| `transactionId` | string | Identificador da transação Monetarie |
| `amount` | integer | Valor em subcentavos |
| `settledAt` | string (ISO 8601) | Momento de liquidação em UTC |

---

## tef.transfer.received

Disparado quando uma TEF entre contas Monetarie é liquidada para a conta de destino.

```json
{
  "eventType": "tef.transfer.received",
  "transactionId": "TEF202605300001_RCV",
  "accountId": 10012,
  "senderAccountId": 10011,
  "receiverAccountId": 10012,
  "merchantId": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "amount": 20000,
  "description": "Repasse interno",
  "settledAt": "2026-05-30T13:30:12Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `tef.transfer.received` |
| `accountId` | integer | Conta de destino assinante do webhook |
| `transactionId` | string | Identificador da transação Monetarie com sufixo `_RCV` |
| Demais campos | | Iguais a `tef.transfer.sent` |

---

## tef.transfer.failed

Disparado quando uma TEF entre contas Monetarie é rejeitada ou não liquidada.

```json
{
  "eventType": "tef.transfer.failed",
  "transactionId": "TEF202605300001",
  "accountId": 10011,
  "receiverAccountId": 10012,
  "merchantId": "1b2db911-972f-4466-9be9-60a7c5450064",
  "entityId": "26a48541-edce-4581-8c6e-564e7f2e6cd7",
  "amount": 20000,
  "failureReason": "insufficient_funds",
  "failedAt": "2026-05-30T13:30:12Z"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `eventType` | string | Sempre `tef.transfer.failed` |
| `accountId` | integer | Conta de origem da tentativa |
| `failureReason` | string | Motivo técnico registrado pela API |
| `failedAt` | string (ISO 8601) | Momento da falha em UTC |

---

## 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.

**Para TEF entre contas Monetarie**: `tef.transfer.sent` confirma a saída liquidada na origem e `tef.transfer.received` confirma a entrada liquidada no destino.

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