# Query Transaction by External ID

Queries a transaction by `external_id`, the identifier defined by your system at creation time (cash-in or cash-out).

## Endpoint

```
GET /api/external/transactions/ref/:external_id
```

## 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) |

## Path Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `external_id` | String | Yes | External identifier defined at transaction creation |

::: tip When to use
This endpoint is useful for reconciliation between your system and Monetarie. Instead of storing Monetarie's `transaction_id`, query directly by your order ID, invoice, or internal reference.
:::

## Example

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

## Response Shapes

The response varies by transaction state. Below are the 4 possible shapes.

### Shape 1 -- Settled transaction (`status: "settled"`)

Returned when the transaction has settled and is persisted in the `transactions` table.

```json
{
  "worked": true,
  "data": {
    "id": "c7f3a8b1-2d4e-4f6a-9c1b-3e5f7a9b1d3e",
    "transaction_id": "PIXOUT20260309a1b2c3d4e5f6",
    "end_to_end_id": "E46026562202603091530abcdef01",
    "external_id": "order-9876",
    "type": "pix",
    "direction": "outbound",
    "status": "settled",
    "amount": 300000,
    "fee_amount": 350,
    "net_amount": 300350,
    "description": "Pagamento fornecedor",
    "counterparty_name": "Joao Silva",
    "recipient_key": "12345678901",
    "payer_document": null,
    "recipient_document": "12345678901",
    "payer_ispb": null,
    "payer_bank_name": null,
    "created_at": "2026-03-09T15:30:00Z",
    "completed_at": "2026-03-09T15:30:02Z"
  }
}
```

| Field (top-level) | 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 |
| `type` | String | `pix`, `ted`, `internal` |
| `direction` | String | `inbound` or `outbound` |
| `status` | String | Transaction status (see [pix-lifecycle](/en/pix-lifecycle)) |
| `amount` | Integer | Value in base units (÷ 10,000 for BRL) |
| `fee_amount` | Integer | Fee charged in base units |
| `net_amount` | Integer | Net value in base units |
| `description` | String | Transaction description |
| `counterparty_name` | String | Counterparty name |
| `recipient_key` | String | Recipient PIX key (outbound only) |
| `payer_document` | String | Payer's CPF/CNPJ (inbound). `null` for outbound |
| `recipient_document` | String | Recipient's CPF/CNPJ (outbound). `null` for inbound |
| `payer_ispb` | String | Payer institution ISPB (inbound). `null` for outbound |
| `payer_bank_name` | String | Payer's bank name (inbound). `null` for outbound |
| `created_at` | String | Creation date (ISO 8601) |
| `completed_at` | String | Completion date (ISO 8601) |

### Shape 2 -- Transaction in processing (`status: "processing"`)

Returned when the transaction is in `outbound_requests` awaiting BACEN response (not settled or failed yet).

```json
{
  "worked": true,
  "data": {
    "transaction_id": "PIXOUT20260309a1b2c3d4e5f6",
    "end_to_end_id": "E46026562202603091530abcdef01",
    "external_id": "order-9876",
    "amount": 300000,
    "fee_amount": 350,
    "net_amount": 300350,
    "status": "processing",
    "payment_status": "processing",
    "type": "pix",
    "direction": "outbound",
    "pix_key": "12345678901",
    "description": "Pagamento fornecedor",
    "started_at": "2026-03-09T15:30:00Z"
  }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `transaction_id` | String | Public identifier (prefix `PIXOUT`) |
| `end_to_end_id` | String | BACEN E2E ID |
| `external_id` | String | Your system identifier |
| `amount` | Integer | Value in base units (÷ 10,000 for BRL) |
| `fee_amount` | Integer | Fee in base units |
| `net_amount` | Integer | `amount + fee_amount` in base units |
| `status` | String | Always `"processing"` in this shape |
| `payment_status` | String | Mirror of `status` for compatibility |
| `type` | String | `pix`, `ted`, `internal` |
| `direction` | String | `outbound` (shape exclusive to PIX OUT in flight) |
| `pix_key` | String | Recipient PIX key |
| `description` | String | Description sent in the request |
| `started_at` | String | Moment when the request was queued (ISO 8601) |

::: warning Intermediate shape
Transactions in `processing` are in flight at BACEN. **Do not trust this state as final** - wait for the `pix.payout.confirmed` or `pix.payout.failed` webhook. Quarantine operations (stage=5, no BACEN response >30min) also return `"processing"` - see [pix-lifecycle](/en/pix-lifecycle).
:::

### Shape 3 -- Failed transaction

Returned when the transaction is in `failed_transactions` (rejected by BACEN or internal failure).

```json
{
  "worked": true,
  "data": {
    "transaction_id": "PIXOUT20260309a1b2c3d4e5f6",
    "end_to_end_id": "E46026562202603091530abcdef01",
    "external_id": "order-9876",
    "amount": 300000,
    "status": "failed",
    "type": "pix",
    "direction": "outbound",
    "reason_code": "AC03",
    "reason_description": "Invalid creditor account number",
    "recipient": {
      "name": "Joao Silva",
      "key": "12345678901"
    },
    "failed_at": "2026-03-09T15:30:02Z"
  }
}
```

| Extra field | Type | Description |
|-------|------|-------------|
| `reason_code` | String | BACEN/provider code (e.g., `AC03`, `ED05`, `AM02`) |
| `reason_description` | String | English description |
| `recipient` | Object | `{name, key}` of the recipient |
| `failed_at` | String | Failure date (ISO 8601) |

### Shape 4 -- QR code (cash-in)

Returned when the `external_id` was registered on a charge QR code (paid or unpaid). Used as a fallback when there is no row in `transactions` or in `outbound_requests`.

```json
{
  "worked": true,
  "data": {
    "id": "e9f3df72-031f-49bf-abc3-a9ce1d540726",
    "tx_id": "smyoka2zd5xowvqq2hea",
    "pix_key": "evp-xxxx-xxxx-xxxx",
    "amount": 100000,
    "fee_amount": 0,
    "status": "paid",
    "external_id": "order-9876",
    "description": "Pedido #1234",
    "end_to_end_id": "E46026562202604101607b2fc9d8b4c6b",
    "direction": "inbound",
    "type": "pix_qrcode",
    "created_at": "2026-04-10T16:00:00Z",
    "paid_at": "2026-04-10T16:07:08Z"
  }
}
```

| Field | Type | Description |
|-------|------|-------------|
| `id` | String | QR code UUID |
| `tx_id` | String | BACEN `txId` (QR identifier in SPI) |
| `pix_key` | String | PIX key of the QR receiver |
| `amount` | Integer | QR amount in base units (`0` if QR has no defined value) |
| `fee_amount` | Integer | Always `0` on the QR code (fee is charged on settlement) |
| `status` | String | `paid`, `pending`, `expired`, `cancelled` |
| `external_id` | String | Your system identifier |
| `description` | String | Description provided at QR creation |
| `end_to_end_id` | String | E2E of the PIX that paid the QR (only if `status=paid`). `null` otherwise. |
| `direction` | String | Always `"inbound"` for QR code |
| `type` | String | Always `"pix_qrcode"` |
| `created_at` | String | QR creation moment (ISO 8601) |
| `paid_at` | String | Payment moment (ISO 8601). `null` if not yet paid. |

All monetary values are in **base units** (÷ 10,000 for BRL).

::: tip Search priority
The backend looks up `external_id` in this order: (1) `transactions` → shape 1, (2) in-flight `outbound_requests` → shape 2, (3) `failed_transactions` → shape 3, (4) `qrcodes` → shape 4. The first table containing the ID wins.
:::

::: warning Differences between shapes (important for client parser)
The 4 shapes share some fields (e.g., `transaction_id`, `end_to_end_id`, `external_id`, `amount`, `status`, `type`, `direction`) but **do not have the same set of fields**:

- **Shape 1 (`settled`)**: 18 fields including `fee_amount`, `net_amount`, `payer_document`, `payer_ispb`, `payer_bank_name`, `recipient_document`, `recipient_key`, `counterparty_name`
- **Shape 2 (`processing`)**: 13 fields - **does not include** counterparty data (`payer_document`, `payer_ispb`, `recipient_document` absent), only what is in `outbound_requests`
- **Shape 3 (`failed`)**: includes `reason_code` + `reason_description` + nested `recipient.{name, key}` object (note: not `recipient_document` flat)
- **Shape 4 (QR code)**: different schema - has `tx_id`, `paid_at`, `pix_key`, always `direction="inbound"` and `type="pix_qrcode"`

**Recommendation**: inspect `data.status` first; use switch/case to dispatch to 4 distinct parsers. Do not assume cross-shape field presence.
:::

::: tip Official receipt
To generate a formatted receipt (PDF-ready, with institution data and BRL-formatted values), use [`GET /api/external/transactions/:id/receipt`](/en/pix-cashout-receipt) after settlement - the `/transactions/ref/:external_id` endpoint provides raw data for programmatic reconciliation, not visual formatting.
:::

## Error Response -- 404

```json
{
  "worked": false,
  "errors": {
    "not_found": "Transação não encontrada para o external_id informado"
  }
}
```

## Error Response -- 401

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

::: warning Uniqueness
`external_id` is not unique per account. If multiple transactions share the same `external_id`, the endpoint returns the most recent. We recommend using unique values to simplify reconciliation.
:::
