# Concepts

Fundamental concepts for integrating with the Monetarie API.

## Security Architecture

The API employs **three independent layers of protection**. All are mandatory.

### Layer 1 -- API Key + Secret

Each integrator receives a pair of credentials (`client_id` and `client_secret`). The secret is never stored in plain text -- we only store the hash. When a request arrives, the submitted secret is compared against the stored hash. If it does not match, the request is rejected immediately, before reaching business logic.

### Layer 2 -- Per-Request HMAC-SHA512 Signature

In addition to the API Key, each transactional request (POST) must include an HMAC-SHA512 signature in the `hmac` header.

The process works as follows:

1. The integrator serializes the request body as JSON
2. Generates the HMAC-SHA512 hash using the `client_secret` as the key
3. Sends the hash in hexadecimal format in the `hmac` header

On our side, we recalculate the hash using the same method and compare it with the received value. If any byte of the content is altered in transit (e.g., in a man-in-the-middle attack), the signature will not match and the request is rejected with a 401 error. This comparison is performed using **constant-time comparison**, which prevents timing attacks that attempt to discover the signature byte by byte.

### Layer 3 -- Mandatory IP Whitelist

Each API Key can only be used from previously authorized IPs. Even if someone gains access to the credentials, they will not be able to use the API from another IP. Requests from unauthorized IPs receive `403 Forbidden`.

### Additional Protections

| Protection | Description |
|------------|-------------|
| **Rate Limiting** | 90,000 requests/minute per IP. Unauthenticated endpoints: 5 req/min |
| **AWS WAF** | Web application firewall protecting the API |
| **Mandatory HTTPS** | TLS 1.2 or higher on all connections |
| **HSTS** | HTTP Strict Transport Security enabled |

Full details: [Authentication](/en/auth-token) | [HMAC-SHA512](/en/hmac)

### Why HMAC and not mTLS?

mTLS (mutual TLS) adds authentication via X.509 certificate at the connection level. It is a valid layer, but in our scenario per-request HMAC provides equivalent or more suitable protection:

| Aspect | mTLS | HMAC-SHA512 |
|--------|------|-------------|
| **What it validates** | The connection (TLS channel) | Each individual request |
| **Payload integrity** | No -- if the connection is trusted, requests pass through | Yes -- any change to the body causes the request to be rejected |
| **Operational management** | Complex: issuance, rotation, revocation, CRL/OCSP | Simple: generate new pair, update, invalidate previous |
| **Common incidents** | Expired or mismanaged certificates | Rare -- key is a string with no complex lifecycle |

TLS already ensures transport encryption. HMAC serves as an additional layer, ensuring payload integrity and authenticity -- something that mTLS alone does not cover.

## Monetary Values

The Monetarie API uses two different units depending on the direction:

| Direction | Unit | Scale | Example R$ 30.00 |
|-----------|------|-------|-------------------|
| **Request sent** (request body) | centavos | BRL x 100 | `3000` |
| **Response received** (response body) | base units | BRL x 10,000 | `300000` |

### Quick Conversion

- **To send**: multiply the BRL value by 100. R$ 30.00 = `3000`
- **To read responses**: divide by 10,000. `300000` / 10,000 = R$ 30.00
- **Never use floating point** -- always integers

### Reference Table

| BRL Value | Request (centavos) | Response (base units) |
|-----------|--------------------|-----------------------|
| R$ 1.00 | `100` | `10000` |
| R$ 30.00 | `3000` | `300000` |
| R$ 150.50 | `15050` | `1505000` |
| R$ 1,000.00 | `100000` | `10000000` |

::: danger Attention
The value `3000` in the request (R$ 30.00) becomes `300000` in the response. They are the same BRL value, represented in different units. If you divide the response by 100 instead of 10,000, you will get R$ 3,000.00 instead of R$ 30.00.
:::

## External ID

The `external_id` field is an optional identifier that you define in your system to track transactions. It is accepted in cash-in and cash-out endpoints and returned in all associated responses and webhooks.

| Attribute | Value |
|-----------|-------|
| Required | No |
| Maximum length | 128 characters |
| Allowed characters | Alphanumeric, `.`, `_`, `:`, `-` |
| Regex | `^[a-zA-Z0-9._:\-]+$` |
| Example | `"order-9876"`, `"invoice-4521"`, `"ref:2026-03-07:001"` |

In addition to being returned in responses, you can query a transaction by `external_id`:

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

::: tip Tracking
Use the `external_id` to correlate Monetarie transactions with orders, invoices, or records in your system. Duplicate values are not rejected, but we recommend uniqueness to simplify reconciliation.
:::

## Idempotency

Write requests (POST) accept the `Idempotency-Key` header to prevent duplicate processing. If the same key is sent in a second identical request within 24 hours, the API returns the original cached response instead of processing again.

```
Idempotency-Key: unique-request-id-123
```

| Attribute | Value |
|-----------|-------|
| Header | `Idempotency-Key` |
| Maximum length | 256 characters |
| Cache TTL | 24 hours |
| Applies to | POST only (cash-in, cash-out, refund, webhooks, CPF) |
| Replay response | Header `X-Idempotent-Replay: true` |

::: warning Important
The idempotency key considers method + path + key. Two requests to different endpoints with the same key are treated as distinct operations.
:::

## Transaction Status

Monetarie uses a **unified vocabulary** across POST responses, GET responses and webhook bodies - the same value appears in all surfaces. See [PIX Lifecycle](/en/pix-lifecycle) for the full map.

### Cash In (Receipts)

| Status | Where it appears | Description |
|--------|------------------|-------------|
| `active` | POST `/pix/cash-in` response | Freshly generated QR Code |
| `created` | Webhook `pix.charge.created` body | QR Code created |
| `paid` | Webhook `pix.charge.paid` body | **Terminal.** PIX received and credited |
| `settled` | GET `/transactions/:id` response | **Terminal.** Same as `paid` - transaction already in `transactions` |
| `pending` | GET when QR not yet paid | QR active, awaiting payment |
| `expired` | GET when QR expired | QR was not paid within TTL |
| `cancelled` | GET when QR was cancelled | Charge cancelled by the merchant |

### Cash Out (Transfers)

| Status | Where it appears | Description |
|--------|------------------|-------------|
| `accepted` | POST `/pix/cash-out` response (HTTP 202) | Intermediate - accepted for async processing |
| `processing` | Webhook `pix.payout.processing` + GET while in flight | Intermediate - sent to SPI, awaiting BACEN |
| `settled` | Webhook `pix.payout.confirmed` + GET when settled + POST response (HTTP 200 fast-track) | **Terminal success.** Debit confirmed by SPI/BACEN |
| `rejected` | Webhook `pix.payout.failed` body | **Terminal failure.** Rejected by SPI, hold released |
| `failed` | GET `/transactions/:id` when failed | **Terminal failure.** Same as `rejected`, but appears in GET |
| `returned` | Webhook `pix.payout.returned` body | Sent PIX returned after settlement (full or partial) |

::: tip Golden rule for reconciliation
Only treat as final when you receive `pix.payout.confirmed` (status `settled`) or `pix.payout.failed` (status `rejected`). `accepted` and `processing` are intermediate.
:::

## End-to-End ID (E2E ID)

Unique identifier of a PIX transaction within the Central Bank ecosystem. Standard format:

```
E{ISPB}{YYYYMMDDHHMM}{sequential}
```

**Example:** `E46026562202603071530000001`

| Component | Value | Description |
|-----------|-------|-------------|
| `E` | Fixed prefix | Identifies as E2E ID |
| `46026562` | Monetarie ISPB | 8 digits |
| `202603071530` | UTC date and time | YYYYMMDDHHMM (12 digits) |
| `000001` | Sequential | 6 digits |

The E2E ID is automatically generated by Monetarie and returned in the response of each PIX operation. Use it to track transactions between institutions.

## PIX Key Types

| Type | Format | Example | Individual Limit | Business Limit |
|------|--------|---------|------------------|----------------|
| `cpf` | 11 digits | `12345678901` | 1 | -- |
| `cnpj` | 14 digits | `12345678000190` | -- | 1 |
| `email` | Valid email | `contato@empresa.com.br` | 5 | 20 |
| `phone` | area code + number (11 digits) | `11999998888` | 5 | 20 |
| `evp` | UUID v4 (random key) | `a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d` | 5 | 20 |

## Response Pattern

All API responses follow the pattern:

### Success

```json
{
  "worked": true,
  ...
}
```

### Error

```json
{
  "worked": false,
  "detail": "Error description"
}
```

The `worked` field indicates whether the operation succeeded (`true`) or failed (`false`). In case of error, the `detail` field describes the reason.
