# Guia de Integração: PIX Cash-Out

Este guia descreve o fluxo completo para integrar pagamentos PIX (cash-out) via API Monetarie.

---

## Fluxo de Vida de um Pagamento

```
POST /api/external/pix/cash-out
         │
         ▼
   ┌─────────────┐
   │  accepted    │ ← HTTP 200, worked: true, final: false
   │  (pendente)  │
   └──────┬──────┘
          │
    ┌─────┴─────┐
    ▼           ▼
┌────────┐  ┌────────┐
│settled │  │rejected│
│(final) │  │(final) │
└────────┘  └────────┘
```

### Importante

- **`worked: true`** significa que o pagamento foi **aceito para processamento**, NÃO que foi liquidado.
- **`final: true`** significa que o pagamento atingiu estado terminal (settled ou rejected).
- **`final: false`** significa que ainda está em processamento.

---

## Enviando um Pagamento

```bash
curl -X POST https://api.monetarie.com/api/external/pix/cash-out \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "hmac: $HMAC_SHA512" \
  -H "Idempotency-Key: order-12345" \
  -d '{
    "amount": 3000,
    "pix_key": "12345678901",
    "pix_key_type": "cpf",
    "description": "Pagamento fornecedor",
    "external_id": "order-12345"
  }'
```

### Campos do Request

| Campo | Tipo | Obrigatório | Descrição |
|-------|------|-------------|-----------|
| `amount` | Integer | Sim | Valor em **centavos** (R$ 30,00 = 3000) |
| `pix_key` | String | Condicional | Chave PIX (CPF, CNPJ, email, telefone, EVP) |
| `pix_key_type` | String | Recomendado | `cpf`, `cnpj`, `email`, `phone`, `evp` |
| `emv` | String | Condicional | Copia e Cola (alternativa a pix_key) |
| `description` | String | Não | Descrição (max 140 caracteres) |
| `external_id` | String | Não | ID no seu sistema (max 128 chars, `a-zA-Z0-9._:-`) |
| `Idempotency-Key` | Header | Recomendado | Previne duplicatas em retry |

::: warning Chaves de 11 dígitos
Se a chave tem exatamente 11 dígitos, pode ser CPF ou telefone. Envie `pix_key_type` para evitar erro `pix_key_ambiguous`.
:::

### Resposta de Sucesso (HTTP 200)

```json
{
  "worked": true,
  "final": false,
  "transaction_id": "PIXOUT20260405abc123",
  "end_to_end_id": "E46026562202604051530abcdef01",
  "external_id": "order-12345",
  "amount": 30000000,
  "fee_amount": 3500,
  "net_amount": 30003500,
  "status": "accepted",
  "detail": "PIX enviado para processamento"
}
```

::: danger Unidades de valor na resposta
O `amount` na resposta está em **unidades base** (subcentavos). Para converter para reais: `amount / 10000`. Exemplo: `30000000 / 10000 = R$ 3.000,00`.
:::

---

## Acompanhando o Status

### Opção 1: Webhooks (recomendado)

Configure um webhook para receber notificações automáticas:

| Evento | Quando | Significado |
|--------|--------|-------------|
| `pix.payout.confirmed` | Liquidação BACEN | Pagamento confirmado (terminal) |
| `pix.payout.failed` | Rejeição BACEN | Pagamento rejeitado (terminal) |

### Opção 2: Polling (GET)

```bash
# Por transaction_id
GET /api/external/transactions/{transaction_id}

# Por E2E ID
GET /api/external/transactions/e2e/{end_to_end_id}

# Por external_id
GET /api/external/transactions/ref/{external_id}
```

::: tip Frequência de polling
O BACEN liquida em ~1.6 segundos. Recomendamos polling a cada 2 segundos, máximo 5 tentativas. Após isso, confie nos webhooks.
:::

---

## Requests Sequenciais

::: warning Requests simultâneos para a mesma conta
O sistema usa lock exclusivo por conta com backoff progressivo para garantir consistência de saldo. Requests concorrentes são enfileirados internamente e processados em sequência. Se o saldo é insuficiente, o request retorna `insufficient_balance`.

**Recomendação:** para melhor desempenho, envie requests sequencialmente quando possível.
:::

---

## Códigos de Erro

### Validação (HTTP 422)

| Código | Descrição | Ação |
|--------|-----------|------|
| `invalid_amount` | Valor inválido (<=0 ou não inteiro) | Corrigir valor |
| `pix_key_ambiguous` | 11 dígitos pode ser CPF ou telefone | Enviar `pix_key_type` |
| `destination_not_found` | Chave PIX não registrada no DICT | Verificar chave |
| `self_transfer` | Transferência para própria chave | Usar TEF |
| `same_institution_transfer` | Destinatário na mesma instituição | Usar TEF |
| `nighttime_limit_exceeded` | Fora do horário permitido | Aguardar horário |

### Integração (HTTP 400)

| Código | Descrição | Ação |
|--------|-----------|------|
| `insufficient_balance` | Saldo insuficiente (valor + taxa) | Verificar saldo |
| `lock_unavailable` | Outra transação em andamento | Eliminado -- requests concorrentes agora retornam `insufficient_balance` se o saldo é insuficiente, ou sucedem se o saldo está disponível |
| `provider_timeout` | Timeout na comunicação BACEN | Reenviar após 5s |

---

## Idempotência

Envie o header `Idempotency-Key` com um ID único do seu sistema. Se o mesmo key for enviado novamente, a API retorna o resultado da primeira execução sem processar novamente.

```bash
# Primeira chamada - processa normalmente
curl -H "Idempotency-Key: pay-001" ...

# Segunda chamada com mesmo key - retorna resultado anterior
curl -H "Idempotency-Key: pay-001" ...
```

---

## Circuit Breaker (recomendação)

Implemente circuit breaker no seu cliente:

1. **Contagem:** Após 3 erros consecutivos (timeout ou 5xx), pare de enviar por 30 segundos
2. **Half-open:** Após 30s, envie 1 request de teste
3. **Reset:** Se o teste funcionar, retome operação normal

---

## Comprovante

Após liquidação (`final: true`), o comprovante está disponível:

```bash
GET /api/external/transactions/{transaction_id}/receipt
```

Retorna dados estruturados do comprovante (pagador, recebedor, valor, data, E2E).
