# Subcontas — eventos

Eventos emitidos durante o onboarding de uma subconta e pelo MED (Mecanismo Especial de Devolução do Pix).

Os dois grupos usam **`accountId`** no envelope — é a conta master que recebe o webhook, não a subconta criada. Eventos de assinatura usam `accountNumber`; aqui é `accountId`.

## Onboarding

| Evento | Quando |
|---|---|
| `onboarding.create` | Conta criada; traz os dados bancários em `data.account` |
| `onboarding.backgroundcheck` | Análise de background concluída |
| `onboarding.documentscopy` | Etapa de documentoscopia atualizada; pode trazer `data.url` para o seller enviar documentos |
| `onboarding.proposal` | Status final da proposta |

Todos seguem a mesma forma: envelope (`event`, `timestamp`, `accountId`) mais um objeto **`data`**.

| Campo de `data` | Presente em | Descrição |
|---|---|---|
| `formId` | todos | ID do formulário de proposta na ValidaPay |
| `proposalId` | todos | ID da proposta |
| `documentNumber` | todos | CPF ou CNPJ do proponente |
| `status` | todos | `PENDING`, `APPROVED`, `REPROVED`; `CONFIRMED` no `onboarding.create` |
| `proposalType` | backgroundcheck, documentscopy, proposal | `PF` ou `PJ` |
| `url` | documentscopy | Link de envio de documentos; `null` quando a etapa se encerra |
| `account` | create | `{ number, branch, name }` da conta aberta |

### Exemplo — sequência de aprovação

```json
{
  "event": "onboarding.backgroundcheck",
  "timestamp": "2026-07-24T13:50:02.451Z",
  "accountId": "4231833",
  "data": {
    "formId": "1fc0f2e7-5fe0-4716-a1a2-e3cb31b94035",
    "proposalId": "8ff8f785-a81d-48a5-a7de-6717c4beb099",
    "documentNumber": "67624185000186",
    "proposalType": "PJ",
    "status": "APPROVED"
  }
}
```

A ordem típica é `onboarding.backgroundcheck` (`PENDING`, depois `APPROVED`), `onboarding.documentscopy` (`PENDING` com `url`, depois `APPROVED` com `url: null`), `onboarding.proposal` com o status final e, quando a conta é efetivamente aberta, `onboarding.create`.

Uma reprovação chega como o mesmo evento com `status: "REPROVED"` — foi o que aconteceu no exemplo abaixo, em que a documentoscopia e a proposta foram recusadas na mesma leva.

### Exemplo — onboarding.create

```json
{
  "event": "onboarding.create",
  "timestamp": "2026-04-07T11:24:41.416Z",
  "accountId": "4231833",
  "data": {
    "formId": "03712fd1-bf57-403e-a278-76ca70b2ed1a",
    "proposalId": "c8d1f2a5-871f-46f2-8f98-dd55641ac225",
    "documentNumber": "12354372990",
    "status": "CONFIRMED",
    "account": {
      "number": "483918595",
      "branch": "0001",
      "name": "Guilherme Ferreira Valente"
    }
  }
}
```

Guarde `data.account.number` — é ele que vai no header `X-Sub-Account` e no `accountNumber` dos splits. Note que `onboarding.create` não traz `proposalType`, e que o status desse evento é `CONFIRMED`, não `APPROVED`.

## MED

O MED é o processo do Banco Central para contestação de Pix. Estes eventos avisam sobre bloqueios e devoluções determinadas por ele.

| Evento | Quando |
|---|---|
| `med.infraction.updated` | Infração atualizada |
| `med.balance.blocked` | Saldo bloqueado por ordem do MED |
| `med.balance.unblocked` | Saldo desbloqueado |
| `med.refund.opened` | Processo de devolução aberto |
| `med.refund.closed` | Processo de devolução encerrado |

Todos trazem `event`, `timestamp`, `accountId`, `caseId` (o caso MED na ValidaPay) e `originalEndToEndId` (o Pix contestado), mais os campos específicos de cada etapa:

| Evento | Campos adicionais |
|---|---|
| `med.infraction.updated` | `infractionId`, `status`, `analysisResult`, `chargeId` |
| `med.balance.blocked` | `blockId`, `infractionId`, `blockedAmount`, `blockStatus`, `balanceAfter`, `blockedBalanceAfter` |
| `med.balance.unblocked` | `blockId`, `infractionId`, `unblockedAmount`, `balanceAfter`, `blockedBalanceAfter` |
| `med.refund.opened` | `medRefundId`, `refundAmount` |
| `med.refund.closed` | `medRefundId`, `refundAmount`, `analysisResult`, `returnIdentification`, `chargeId`, `balanceResult` |

```json
{
  "event": "med.balance.blocked",
  "timestamp": "2026-07-03T18:25:09.025Z",
  "accountId": "4231833",
  "caseId": "med_1786746837248_gsoosg37y",
  "blockId": "b4b0c9de-2f18-4a55-9f31-7c0d9a1e2b34",
  "infractionId": "3f8c1d92-5b21-4e77-9a0c-1f2b3c4d5e6f",
  "originalEndToEndId": "E18236120202608142232s0290d93572",
  "blockedAmount": 150.00,
  "blockStatus": "BLOCKED",
  "balanceAfter": 320.55,
  "blockedBalanceAfter": 150.00
}
```

`balanceAfter` é o saldo livre depois da operação e `blockedBalanceAfter`, o total retido. Um bloqueio de saldo pode fazer um saque falhar mesmo com saldo aparente — trate `med.balance.blocked` na sua conciliação.

Os eventos `med.*` só podem ser assinados via `POST /v1/users/webhooks`; a tela de webhooks do painel ainda não os lista.
