# Statement

Lists account transactions with pagination and filters.

## Endpoint

```
GET /api/external/statement
```

## Headers

| Header | Type | Required | Description |
|--------|------|----------|-------------|
| `Authorization` | String | Yes | `ApiKey {client_id}:{client_secret}` |
| `X-Key-Case` | String | No | Set to `camelCase` to receive response fields in camelCase (default is snake_case) |

## Query Parameters

| Parameter | Type | Required | Description | Default |
|-----------|------|----------|-------------|---------|
| `page` | Integer | No | Page number | `1` |
| `per_page` | Integer | No | Items per page (max 100) | `20` |
| `status` | String | No | Filter by `payment_status` column. Values: `settled`, `rejected`, `failed`, `processing` | -- |
| `type` | String | No | Filter by type (`pix`, `ted`, `internal`) | -- |
| `date_from` | String | No | Start date (format `YYYY-MM-DD`) | -- |
| `date_to` | String | No | End date (format `YYYY-MM-DD`) | -- |

**Accepted `status` values**:
- `settled`: Settled transactions (default success)
- `rejected`: Rejected by BACEN
- `failed`: Internal failures or post-rejection
- `processing`: Being processed

::: warning Display vs Filter
The value displayed in the response `status` field may differ from the value accepted by the filter:

- Row with `status=2` displays `"pending"` but is filtered by `status=processing`
- Row with `payment_status=nil` and `status=1` displays `"completed"` but is filtered by `status=settled`

Use the filter values above; the display is normalized for client consumption.
:::

## Example

```bash
curl -X GET "https://api.monetarie.com/api/external/statement?page=1&per_page=20&status=settled&date_from=2026-03-01&date_to=2026-03-07" \
  -H "Authorization: ApiKey $CLIENT_ID:$CLIENT_SECRET"
```

## Success Response (200)

```json
{
  "worked": true,
  "data": [
    {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
      "transaction_id": "7popu57v6us7p6pcicgq12345",
      "end_to_end_id": "E46026562202603071530000001",
      "external_id": "order-9876",
      "type": "pix",
      "status": "settled",
      "amount": 300000,
      "fee_amount": 0,
      "net_amount": 300000,
      "description": "Pedido #1234",
      "direction": "inbound",
      "counterparty_name": "Maria Santos",
      "created_at": "2026-03-07T15:30:00Z",
      "completed_at": "2026-03-07T15:30:02Z"
    },
    {
      "id": "f7e8d9c0-b1a2-4c3d-9e8f-7a6b5c4d3e2f",
      "transaction_id": "PIXOUT20260306x9y8z7w6v5u4",
      "end_to_end_id": "E46026562202603061200000005",
      "external_id": "invoice-4521",
      "type": "pix",
      "status": "settled",
      "amount": 500000,
      "fee_amount": 350,
      "net_amount": 500350,
      "description": "Pagamento fornecedor",
      "direction": "outbound",
      "counterparty_name": "Joao Silva",
      "recipient_key": "12345678901",
      "created_at": "2026-03-06T12:00:00Z",
      "completed_at": "2026-03-06T12:00:03Z"
    }
  ],
  "page": 1,
  "per_page": 20
}
```

| Field | Type | Description |
|-------|------|-------------|
| `worked` | Boolean | `true` indicates operation success |
| `data` | Array | List of transactions |
| `page` | Integer | Current page |
| `per_page` | Integer | Items per page |

### Fields of each transaction

| Field | Type | Description |
|-------|------|-------------|
| `id` | String | Internal transaction UUID |
| `transaction_id` | String | Public transaction identifier |
| `end_to_end_id` | String | BACEN E2E ID |
| `external_id` | String | Your system identifier. `null` if not provided |
| `type` | String | Type (`pix`, `ted`, `internal`) |
| `status` | String | Transaction status (normalized for display). See the "Display vs Filter" block in [Query Parameters](#query-parameters). |
| `amount` | Integer | Value in **base units** (÷ 10,000 for BRL). `300000` = R$ 30.00 |
| `fee_amount` | Integer | Fee charged in base units |
| `net_amount` | Integer | Net value in base units |
| `description` | String | Transaction description |
| `direction` | String | `inbound` (incoming) or `outbound` (outgoing) |
| `counterparty_name` | String | Counterparty name |
| `recipient_key` | String | Recipient PIX key (outbound only) |
| `payer_document` | String | Payer's CPF/CNPJ (inbound only). `null` for outbound. |
| `recipient_document` | String | Recipient's CPF/CNPJ (outbound only). `null` for inbound. |
| `payer_ispb` | String | Payer institution's ISPB (inbound only). `null` for outbound. |
| `payer_bank_name` | String | Payer's bank name resolved from ISPB (inbound only). `null` for outbound. |
| `created_at` | String | Creation date (ISO 8601 UTC) |
| `completed_at` | String | Completion date (ISO 8601 UTC). `null` if not yet settled. |

::: info Date in UTC
All date/time fields are returned in **ISO 8601 UTC** (`Z` suffix). To convert to Brasília time (BRT), subtract 3 hours. The `date_from`/`date_to` filter is also interpreted as UTC - a single filtered day (`date_from=2026-03-07`) covers from `2026-03-07T00:00:00Z` to `2026-03-07T23:59:59Z`.
:::

::: tip In-flight transactions
Page 1 of the listing includes PIX OUT still in flight (table `outbound_requests`, stage < 3) when there is no `status` filter applied or `status=processing`. This allows real-time reconciliation - you see the transaction while it is being processed by BACEN, with `status="pending"`, `payment_status="processing"`, and `completed_at=null`.

When you apply `status=settled` or `status=rejected`, the merge with `outbound_requests` is **not** done - only the `transactions`/`failed_transactions` table is consulted. This avoids duplication when you only want terminal transactions.
:::

::: warning net_amount on outbound is the sum (not subtraction)
In **outbound** transactions (`direction="outbound"`), `net_amount` is computed as `amount + fee_amount` (total debit on the account, including the fee). In **inbound** transactions, `net_amount = amount - fee_amount` (net credit with the fee already deducted).

Outbound example: `amount=500000`, `fee_amount=350`, `net_amount=500350` - R$ 50.035 debited from your account. **Not** R$ 49.965.
:::

::: info Rate limit and polling
`GET /statement` goes through the global `/api/external/*` rate limiter (90,000 req/min per authenticated IP). Only `GET /balance` is exempt from that limiter. Even so, avoid high polling on this endpoint - prefer subscribing to webhooks (`pix.charge.paid`, `pix.payout.confirmed`, `pix.payout.failed`) for real-time notification and use `/statement` for periodic reconciliation (e.g., 5-15 min intervals or end-of-day batch).
:::

::: tip Permission
This endpoint requires `statement:read` on the API Key. The sibling endpoint `GET /api/external/transactions` (same base query, nearly identical shape) requires `transfer:read` - if your integration uses only a subset of permissions, confirm which endpoint accepts your scopes.
:::

## Error Response (401)

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

::: tip Pagination
The maximum `per_page` limit is 100. To extract large volumes, iterate through pages by incrementing the `page` parameter until the response returns an empty `data` array or with fewer items than `per_page`.
:::
