> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firebanking.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# RECEIVE

> Webhook enviado quando um PIX é recebido (Cash-In)

## Visão Geral

O webhook `RECEIVE` é enviado quando um PIX é recebido na sua conta. Este evento indica que alguém pagou um QR Code gerado pela sua aplicação ou fez uma transferência direta para sua chave PIX.

## Quando é enviado

* Pagamento de QR Code (cobrança) confirmado
* Transferência direta para chave PIX da conta

## Estrutura do Payload

```json theme={null}
{
  "type": "RECEIVE",
  "data": {
    "id": 123,
    "txId": "7978c0c97ea847e78e8849634473c1f1",
    "pixKey": "7d9f0335-8dcc-4054-9bf9-0dbd61d36906",
    "status": "LIQUIDATED",
    "payment": {
      "amount": "100.00",
      "currency": "BRL"
    },
    "refunds": [],
    "createdAt": "2024-01-15T10:30:00.000Z",
    "errorCode": null,
    "endToEndId": "E12345678901234567890123456789012",
    "ticketData": {},
    "webhookType": "RECEIVE",
    "debtorAccount": {
      "ispb": "18236120",
      "name": "NU PAGAMENTOS S.A.",
      "issuer": "260",
      "number": "12345-6",
      "document": "123.xxx.xxx-xx",
      "accountType": null
    },
    "idempotencyKey": null,
    "creditDebitType": "CREDIT",
    "creditorAccount": {
      "ispb": null,
      "name": null,
      "issuer": null,
      "number": null,
      "document": null,
      "accountType": null
    },
    "localInstrument": "DICT",
    "transactionType": "PIX",
    "remittanceInformation": "Pagamento pedido #12345"
  }
}
```

## Campos Importantes

<ResponseField name="type" type="string">
  Sempre `"RECEIVE"` para PIX recebido.
</ResponseField>

<ResponseField name="data.id" type="number">
  ID da transação. Use para idempotência.
</ResponseField>

<ResponseField name="data.txId" type="string">
  Identificador da cobrança (txid do endpoint `/cob`). Pode ser `null` para transferências diretas.
</ResponseField>

<ResponseField name="data.endToEndId" type="string">
  End to End ID - identificador único da transação PIX no Banco Central.
</ResponseField>

<ResponseField name="data.status" type="string">
  Status da transação:

  * `LIQUIDATED`: Pagamento confirmado (sucesso)
  * `ERROR`: Falha no processamento
</ResponseField>

<ResponseField name="data.payment" type="object">
  <Expandable title="Propriedades">
    <ResponseField name="amount" type="string">
      Valor recebido. **String** com 2 casas decimais.
    </ResponseField>

    <ResponseField name="currency" type="string">
      Moeda. Sempre `"BRL"`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="data.debtorAccount" type="object">
  Dados de quem pagou (o pagador/remetente).

  <Expandable title="Propriedades">
    <ResponseField name="ispb" type="string">
      Código ISPB do banco do pagador.
    </ResponseField>

    <ResponseField name="name" type="string">
      Nome do banco do pagador.
    </ResponseField>

    <ResponseField name="issuer" type="string">
      Código do banco (ex: "260" para Nubank).
    </ResponseField>

    <ResponseField name="number" type="string">
      Número da conta do pagador.
    </ResponseField>

    <ResponseField name="document" type="string">
      CPF/CNPJ do pagador (mascarado).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="data.creditDebitType" type="string">
  Sempre `"CREDIT"` para recebimentos.
</ResponseField>

<ResponseField name="data.refunds" type="array">
  Lista de devoluções. Vazio para transações sem devolução.
</ResponseField>

<ResponseField name="data.remittanceInformation" type="string">
  Descrição da transferência (se informada pelo pagador).
</ResponseField>

## Processando o Webhook

### Exemplo Node.js

```typescript theme={null}
interface ReceiveWebhook {
  type: 'RECEIVE';
  data: {
    id: number;
    txId: string | null;
    status: 'LIQUIDATED' | 'ERROR';
    payment: {
      amount: string;
      currency: string;
    };
    endToEndId: string;
    debtorAccount: {
      name: string | null;
      document: string | null;
    };
    remittanceInformation: string | null;
  };
}

async function handleReceive(webhook: ReceiveWebhook) {
  const { data } = webhook;

  if (data.status !== 'LIQUIDATED') {
    console.log(`PIX não confirmado: ${data.status}`);
    return;
  }

  // Converter valor de string para number
  const amount = parseFloat(data.payment.amount);

  // Encontrar pedido pelo txId (se for cobrança)
  if (data.txId) {
    const order = await findOrderByTxId(data.txId);
    if (order) {
      await markOrderAsPaid(order.id, {
        amount,
        endToEndId: data.endToEndId,
        payer: data.debtorAccount.name,
      });
      return;
    }
  }

  // Recebimento sem cobrança associada
  await createGenericCredit({
    amount,
    endToEndId: data.endToEndId,
    payer: data.debtorAccount.name,
    description: data.remittanceInformation,
  });
}
```

### Exemplo Python

```python theme={null}
from decimal import Decimal

def handle_receive(webhook: dict):
    data = webhook['data']

    if data['status'] != 'LIQUIDATED':
        print(f"PIX não confirmado: {data['status']}")
        return

    # Converter valor
    amount = Decimal(data['payment']['amount'])

    # Processar por txId se existir
    if data.get('txId'):
        order = find_order_by_txid(data['txId'])
        if order:
            mark_order_as_paid(
                order_id=order.id,
                amount=amount,
                e2e_id=data['endToEndId'],
                payer=data['debtorAccount'].get('name')
            )
            return

    # Crédito genérico
    create_generic_credit(
        amount=amount,
        e2e_id=data['endToEndId'],
        payer=data['debtorAccount'].get('name'),
        description=data.get('remittanceInformation')
    )
```

## Correlação com Cobrança

Se o PIX foi pago via QR Code gerado pelo endpoint `/cob/:txid`, o campo `txId` conterá o identificador:

```json theme={null}
{
  "type": "RECEIVE",
  "data": {
    "txId": "7978c0c97ea847e78e8849634473c1f1",  // Mesmo txid do PUT /cob
    // ...
  }
}
```

Use este campo para correlacionar com seus registros internos:

```typescript theme={null}
// Criar cobrança
const cobranca = await createCob('meu-txid-123', { valor: '100.00' });

// Salvar associação
await saveOrder({
  orderId: 'pedido-456',
  txId: 'meu-txid-123',
  status: 'PENDING'
});

// No webhook RECEIVE
if (webhook.data.txId === 'meu-txid-123') {
  await updateOrder('pedido-456', { status: 'PAID' });
}
```

## Tratamento de Erros

Se `status === 'ERROR'`, verifique o campo `errorCode`:

```typescript theme={null}
if (data.status === 'ERROR') {
  console.error(`Erro no PIX: ${data.errorCode}`);

  // Notificar sobre falha
  await notifyPaymentError({
    txId: data.txId,
    errorCode: data.errorCode,
  });
}
```

## Idempotência

Use `data.id` para evitar processamento duplicado:

```typescript theme={null}
const PROCESSED_KEY = 'processed_webhooks';

async function handleWebhook(webhook: ReceiveWebhook) {
  const webhookId = `receive:${webhook.data.id}`;

  // Verificar se já processou
  const isProcessed = await redis.sismember(PROCESSED_KEY, webhookId);
  if (isProcessed) {
    console.log(`Webhook ${webhookId} já processado`);
    return;
  }

  // Marcar como processado ANTES de processar
  await redis.sadd(PROCESSED_KEY, webhookId);

  // Processar
  await handleReceive(webhook);
}
```

## Boas Práticas

<AccordionGroup>
  <Accordion title="Responda rapidamente">
    Retorne HTTP 200 imediatamente e processe de forma assíncrona.

    ```typescript theme={null}
    app.post('/webhook', (req, res) => {
      res.status(200).send();  // Responder primeiro

      handleWebhook(req.body)  // Processar depois
        .catch(console.error);
    });
    ```
  </Accordion>

  <Accordion title="Valide o status">
    Sempre verifique se `status === 'LIQUIDATED'` antes de creditar.
  </Accordion>

  <Accordion title="Use txId para correlação">
    Se você criou a cobrança via `/cob`, use o `txId` para encontrar o pedido correspondente.
  </Accordion>

  <Accordion title="Logue informações importantes">
    ```typescript theme={null}
    console.log({
      event: 'PIX_RECEIVED',
      id: data.id,
      txId: data.txId,
      amount: data.payment.amount,
      e2eId: data.endToEndId,
      payer: data.debtorAccount.name,
    });
    ```
  </Accordion>
</AccordionGroup>

## Próximos Passos

<CardGroup cols={2}>
  <Card title="TRANSFER" icon="arrow-up" href="/pix-bacen/webhooks/transfer">
    PIX enviado
  </Card>

  <Card title="REFUND" icon="rotate-left" href="/pix-bacen/webhooks/refund">
    Devolução
  </Card>
</CardGroup>
