# Saldo

Consulta o saldo da conta bancária associada à API Key.

## Endpoint

```
GET /api/external/balance
```

## Headers

| Header | Tipo | Obrigatório | Descrição |
|--------|------|-------------|-----------|
| `Authorization` | String | Sim | `ApiKey {client_id}:{client_secret}` |
| `X-Key-Case` | String | Não | Defina como `camelCase` para receber os campos da resposta em camelCase (padrão é snake_case) |

## Exemplo

```bash
curl -X GET https://api.monetarie.com/api/external/balance \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"
```

## Resposta de Sucesso (200)

```json
{
  "worked": true,
  "balance": 3000000,
  "available": 2700000,
  "pending": 300000,
  "currency": "BRL"
}
```

| Campo | Tipo | Descrição |
|-------|------|-----------|
| `worked` | Boolean | `true` indica sucesso na operação |
| `balance` | Integer | Saldo seguro em **unidades base** (÷ 10.000 para reais). `3000000` = R$ 300,00 |
| `available` | Integer | Saldo disponível para operações em unidades base. `2700000` = R$ 270,00 |
| `pending` | Integer | Valor retido em transações pendentes em unidades base. `300000` = R$ 30,00 |
| `currency` | String | Código da moeda (sempre `BRL`) |

::: danger Valores de resposta em unidades base
Todos os valores de resposta são inteiros em **unidades base**. Para converter para reais, divida por 10.000.
Exemplo: `3000000` ÷ 10.000 = **R$ 300,00**. Nunca use ponto flutuante.
:::

## Cálculo do saldo

| Campo | Definição |
|---|---|
| `balance` | **Saldo seguro** = `min(saldo_tigerbeetle, saldo_postgres)`. Se houver divergência TB↔PG, o menor valor é usado |
| `available` | `balance - pending` - saldo efetivamente disponível para novas operações |
| `pending` | Soma dos **débitos pendentes** no TigerBeetle (`account.debits_pending`) |

O campo `balance` protege contra saldo inflado em cenários de divergência temporária entre TigerBeetle e PostgreSQL (ex.: bloqueio MED, reconciliação pós-deploy). Você **nunca** verá aqui um valor maior do que o realmente disponível no sistema de ledger - sempre o menor dos dois sistemas.

### O que compõe `pending` (débitos pendentes no TigerBeetle)

Cada item abaixo é uma **pending transfer** no TigerBeetle que reduz o `available` até ser posted ou voided:

| Origem | Quando aparece | Quando é liberado |
|---|---|---|
| **PIX OUT em voo** (pending TB da wallet → COSIF in-transit) | Durante o envio, enquanto aguarda confirmação BACEN (~1,6s típico) | Posted ao receber `pix.payout.confirmed` (settled); voided ao receber `pix.payout.failed` |
| **Valor em disputa MED** | Quando um caso MED exige reserva temporária do valor contestado | Liberado ou liquidado conforme decisão final. Acompanhe por `pix.infraction.resolved` e veja [Infrações](/infractions). |
| **Quarentena (stage=5)** | PIX OUT sem resposta BACEN >30min - saldo fica em limbo | Posted/voided só após decisão manual da reserva Monetarie (pode levar horas ou D+1). Ver [pix-lifecycle](/pix-lifecycle#quarentena-operacoes-sem-resposta-bacen). |
| **Outros holds internos** | Raros - normalmente ligados a fees ou ajustes específicos | Depende do tipo |

::: info Situações onde `balance < saldo bruto TB`
- **Divergência TB↔PG**: em casos raros (ex.: janela de remediação pós-deploy, incidente session 142 TB-PG equalization), `balance` reflete o **menor** entre os dois sistemas até a convergência. Nunca vemos saldo inflado; no máximo, subdimensionado por alguns minutos.
:::

::: warning `available` pode ficar "parado" mesmo com PIX IN crescente
Se você vê `balance` subindo (recebimentos) mas `available` não cresce na mesma proporção, **muito provavelmente há bloqueio MED ativo**. Consulte [`GET /api/external/med`](/med-list) para listar os bloqueios cautelares. Todo bloqueio tem origem em uma infração - veja [Infrações](/infractions) para o fluxo completo.
:::

::: warning Cache e consistência
O saldo é calculado em tempo real (latência típica <10ms) - não há cache. Entretanto, em janelas pós-liquidação (<200ms após o webhook `pix.charge.paid`), o PostgreSQL pode ainda não ter sido atualizado. Para conciliação crítica, aguarde o webhook antes de consultar o saldo.
:::

## Resposta de Erro (401)

```json
{
  "worked": false,
  "errors": {
    "unauthorized": "Missing API key credentials. Use Authorization: ApiKey <client_id>:<client_secret>"
  }
}
```
