# Monetarie PIX - Partner Integration Guide

**Version:** 1.0
**Date:** 2026-02-07
**Classification:** Confidential
**Audience:** Technical teams of financial institutions integrating with Monetarie PIX

---

## Table of Contents

1. [Overview](#1-overview)
2. [Architecture & Connectivity](#2-architecture--connectivity)
3. [Authentication](#3-authentication)
4. [API Reference — PIX Key Directory (DICT)](#4-api-reference--pix-key-directory-dict)
5. [API Reference — Instant Payments (SPI)](#5-api-reference--instant-payments-spi)
6. [API Reference — Settlement & QR Codes](#6-api-reference--settlement--qr-codes)
7. [API Reference — MED 2.0 Fraud Recovery](#7-api-reference--med-20-fraud-recovery)
8. [ISO 20022 Message Catalog](#8-iso-20022-message-catalog)
9. [Error Handling (RFC 7807)](#9-error-handling-rfc-7807)
10. [Rate Limiting](#10-rate-limiting)
11. [Security Requirements](#11-security-requirements)
12. [Onboarding Checklist](#12-onboarding-checklist)
13. [Testing & Homologation](#13-testing--homologation)
14. [Appendix A — BACEN Error Codes](#appendix-a--bacen-error-codes)
15. [Appendix B — NATS Event Subjects](#appendix-b--nats-event-subjects)
16. [Core Banking Integration (NATS)](#14-core-banking-integration-nats) — **Start here for PIX ↔ Core integration**

---

## 1. Overview

### What is Monetarie PIX?

Monetarie PIX is a Brazilian Central Bank (BACEN) compliant instant payment processing platform. It provides:

- **DICT** — PIX Key Directory management (API v2.10.0)
- **SPI** — Instant Payment initiation, processing and settlement
- **Settlement** — Netting, reconciliation, fee management
- **QR Code** — Static and dynamic QR code generation (BR Code EMV)
- **MED 2.0** — Fraud recovery (Mecanismo Especial de Devolucao)

### Integration Model

```
┌──────────────────────┐         ┌────────────────────────────────┐
│  Partner Institution │         │         Monetarie PIX             │
│                      │         │                                │
│  ┌──────────────┐    │  HTTPS  │  ┌─────────────────────────┐  │
│  │ Your System  ├────┼────────►│  │ Settlement Service      │  │
│  │              │    │  :4003  │  │ (API Gateway, port 4003)│  │
│  └──────────────┘    │         │  └──┬──────────┬───────────┘  │
│                      │         │     │          │              │
└──────────────────────┘         │  ┌──▼────┐  ┌──▼────┐        │
                                 │  │ DICT  │  │  SPI  │        │
                                 │  │ :4001 │  │ :4002 │        │
                                 │  └───────┘  └───────┘        │
                                 └────────────────────────────────┘
```

**All external traffic connects to the Settlement Service (port 4003).** It acts as the API gateway, proxying requests to the DICT and SPI services internally.

### Base URLs

| Environment | URL |
|------------|-----|
| **Development** | `https://pixadmin-dev.fluxiq.com.br` |
| **Homologation** | `https://pix-h.fluxiq.com.br` (future) |
| **Production** | `https://pix.fluxiq.com.br` (future) |

---

## 2. Architecture & Connectivity

### Protocol & Transport

| Parameter | Value |
|----------|-------|
| Protocol | HTTPS (TLS 1.2+) |
| Content-Type | `application/json` |
| Error Content-Type | `application/problem+json` (RFC 7807) |
| Character Encoding | UTF-8 |
| Max Request Size | 10 MB |
| Timeout | 30 seconds (default) |

### Required Request Headers

| Header | Required | Description |
|--------|----------|-------------|
| `Authorization` | Yes | `Bearer <JWT_TOKEN>` |
| `Content-Type` | Yes (POST/PUT/PATCH) | `application/json` |
| `X-Participant-ISPB` | Recommended | Your institution's 8-digit ISPB code |
| `X-Request-ID` | Recommended | UUID v4 for distributed tracing |
| `X-Correlation-ID` | Optional | For correlating related requests |
| `Accept` | Optional | `application/json` (default) |

### Response Headers

| Header | Description |
|--------|-------------|
| `X-Request-ID` | Echo of your request ID (or auto-generated) |
| `X-RateLimit-Limit` | Your rate limit bucket capacity |
| `X-RateLimit-Remaining` | Remaining tokens in current window |
| `X-RateLimit-Reset` | Unix timestamp when bucket resets |
| `Retry-After` | Seconds to wait (only on HTTP 429) |

---

## 3. Authentication

Monetarie PIX supports two authentication modes:

| Mode | Use Case | Mechanism |
|------|----------|-----------|
| **Bearer Token (API)** | Core banking integrations, service-to-service | `Authorization: Bearer <jwt>` header |
| **HttpOnly Cookie (Browser)** | Admin portal, operator UI | Automatic cookie-based session |

**API integrations MUST use Bearer token mode.** Cookie-based auth is for the admin UI only.

### 3.1 Login (API Mode — for Core Banking Integrations)

```http
POST /api/v1/auth/login
Content-Type: application/json

{
  "login": "your_username",
  "password": "your_password"
}
```

**Response (200 OK):**

The response sets an HttpOnly session cookie AND returns user data. For API clients that cannot use cookies, extract the JWT from the `Set-Cookie` header's `__monetarie_session` value, or use the `Authorization: Bearer` header on subsequent calls.

```json
{
  "success": true,
  "user": {
    "id": "1",
    "username": "integration",
    "email": "integration@yourbank.com",
    "fullName": "Integration User",
    "role": "integration",
    "permissions": ["payments:read", "payments:write", "keys:read", "keys:write"]
  }
}
```

> **Note:** The JWT token is no longer returned in the JSON body. It is delivered as an HttpOnly cookie (`__monetarie_session`). API clients should use one of these approaches:
>
> 1. **Recommended:** Send credentials, capture the `Set-Cookie: __monetarie_session=<jwt>` from the response headers, and use that JWT value as `Authorization: Bearer <jwt>` on all subsequent requests.
> 2. **Alternative:** If your HTTP client supports cookie jars (like cURL with `-b` flag), cookies will be handled automatically.

**Response (401 Unauthorized):**
```json
{
  "error": "authentication_failed",
  "message": "Invalid username or password"
}
```

### 3.2 Using the Token (API Clients)

Include the JWT token in all subsequent requests via the Authorization header:

```http
GET /api/v1/payments
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
X-Participant-ISPB: 12345678
```

**CSRF:** API clients using `Authorization: Bearer` headers do NOT need to send CSRF tokens. CSRF validation only applies to cookie-based sessions.

### 3.3 Token Details

| Property | Value |
|----------|-------|
| Algorithm | HMAC-SHA256 (HS256) |
| Expiry | 24 hours |
| Issuer | `monetarie` |
| Delivery | `Set-Cookie: __monetarie_session` (HttpOnly, Secure, SameSite=Strict) |

**JWT Claims:**
```json
{
  "sub": "user_id",
  "username": "integration",
  "email": "integration@yourbank.com",
  "ispb": "12345678",
  "institution_id": 1,
  "iat": 1738886400,
  "exp": 1738972800,
  "iss": "monetarie"
}
```

### 3.4 Token Refresh

```http
POST /api/v1/auth/refresh
Authorization: Bearer <current_token>
```

### 3.5 RSA-Encrypted Login (Optional, Browser Only)

The admin portal encrypts login credentials client-side using RSA-OAEP before transmission. API clients do NOT need to use this — plain JSON login is fully supported and recommended for server-to-server integrations.

```http
GET /api/v1/auth/public-key
```

Returns the RSA public key (PEM format) used by the admin portal for credential encryption.

### 3.5 SSO Integration (Monetarie Backoffice)

If your institution already uses Monetarie Core, you can authenticate via SSO:

1. Monetarie Core issues an SSO token with `target_system: "pix"`
2. Include it as `Authorization: Bearer <sso_token>`
3. The gateway tries SSO first, falls back to JWT

---

## 4. API Reference — PIX Key Directory (DICT)

All DICT endpoints are proxied through the gateway at port 4003.

### 4.1 Create PIX Key

```http
POST /api/v2/entries
Authorization: Bearer <token>
Content-Type: application/json

{
  "key_type": "CPF",
  "key_value": "12345678901",
  "owner_type": "NATURAL_PERSON",
  "owner_cpf_cnpj": "12345678901",
  "owner_name": "JOAO SILVA",
  "trade_name": null,
  "branch_code": "0001",
  "account_number": "123456",
  "account_type": "CACC",
  "opening_date": "2020-01-15"
}
```

**Key Types:** `CPF`, `CNPJ`, `PHONE`, `EMAIL`, `EVP`
**Account Types:** `CACC` (checking), `SLRY` (salary), `SVGS` (savings), `TRAN` (transactional)

**Response (201 Created):**
```json
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "key_type": "CPF",
  "key_value": "12345678901",
  "owner_type": "NATURAL_PERSON",
  "owner_cpf_cnpj": "12345678901",
  "owner_name": "JOAO SILVA",
  "ispb": "12345678",
  "branch_code": "0001",
  "account_number": "123456",
  "account_type": "CACC",
  "status": "active",
  "creation_date": "2026-02-07T10:00:00Z",
  "key_owner_since": "2026-02-07T10:00:00Z"
}
```

### 4.2 Query PIX Key

```http
GET /api/v2/entries/12345678901
Authorization: Bearer <token>
```

### 4.3 Delete PIX Key

```http
DELETE /api/v2/entries/12345678901
Authorization: Bearer <token>
```

### 4.4 List PIX Keys

```http
GET /api/v2/entries?key_type=CPF&status=active&limit=50&offset=0
Authorization: Bearer <token>
```

### 4.5 Search by Account

```http
GET /api/v2/entries/by-account?ispb=12345678&branch=0001&account=123456&account_type=CACC
Authorization: Bearer <token>
```

### 4.6 Block/Unblock Key

```http
POST /api/v2/entries/12345678901/block
Authorization: Bearer <token>
Content-Type: application/json

{
  "reason": "FRAUD_SUSPICION"
}
```

```http
POST /api/v2/entries/12345678901/unblock
Authorization: Bearer <token>
```

### 4.7 Portability Claims

**Create Claim (request key transfer):**
```http
POST /api/v2/entries/12345678901/claims
Authorization: Bearer <token>
Content-Type: application/json

{
  "claimer_tax_id": "12345678901",
  "claimer_account": "654321",
  "claimer_branch": "0001",
  "claimer_account_type": "CACC",
  "claimer_name": "JOAO SILVA",
  "claimer_owner_type": "NATURAL_PERSON"
}
```

**Confirm Claim (donor institution):**
```http
POST /api/v2/claims/{claim_id}/confirm
Authorization: Bearer <token>
```

**Cancel Claim:**
```http
POST /api/v2/claims/{claim_id}/cancel
Authorization: Bearer <token>
```

**Complete Claim (claimer institution):**
```http
POST /api/v2/claims/{claim_id}/complete
Authorization: Bearer <token>
```

### 4.8 Event Notifications

Poll for pending DICT events:
```http
GET /api/v2/event-notifications
Authorization: Bearer <token>
```

Acknowledge received events:
```http
POST /api/v2/event-notifications/acknowledge
Authorization: Bearer <token>
Content-Type: application/json

{
  "notification_ids": ["id1", "id2", "id3"]
}
```

### 4.9 CID File Sync

```http
POST /api/v2/cids/files
GET /api/v2/cids/files/{file_id}
GET /api/v2/cids/events
```

---

## 5. API Reference — Instant Payments (SPI)

### 5.1 Create Payment (pacs.008)

```http
POST /api/v1/payments
Authorization: Bearer <token>
Content-Type: application/json

{
  "transaction": {
    "amount": 15000,
    "debtor_ispb": "12345678",
    "creditor_ispb": "17184037",
    "debtor_document": "12345678901",
    "creditor_document": "98765432109",
    "debtor_account": "123456",
    "creditor_account": "654321",
    "local_instrument": "DICT",
    "description": "Payment for services",
    "creditor_proxy": "98765432109"
  }
}
```

**Amount:** In centavos (integer). Example: `15000` = R$ 150.00

**Local Instruments:**

| Code | Description |
|------|-------------|
| `MANU` | Manual entry (account + branch) |
| `DICT` | Via PIX key |
| `QRDN` | Dynamic QR Code |
| `QRES` | Static QR Code |
| `QRIP` | PIX Immediate Payment (Cobranca) |
| `INIC` | Payment Initiation Service (Open Finance) |

**Response (201 Created):**
```json
{
  "id": "uuid",
  "end_to_end_id": "E12345678202602071234ABCD1234",
  "amount": 15000,
  "status": "processing",
  "debtor_ispb": "12345678",
  "creditor_ispb": "17184037",
  "local_instrument": "DICT",
  "created_at": "2026-02-07T10:00:00Z"
}
```

### 5.2 List Payments

```http
GET /api/v1/payments?from_date=2026-02-01&to_date=2026-02-07&status=settled&limit=50&offset=0
Authorization: Bearer <token>
```

**Filter Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `from_date` | date | Start date (YYYY-MM-DD) |
| `to_date` | date | End date (YYYY-MM-DD) |
| `status` | string | pending, processing, accepted, settled, rejected, cancelled, returned |
| `debtor_ispb` | string | Filter by debtor ISPB |
| `creditor_ispb` | string | Filter by creditor ISPB |
| `local_instrument` | string | MANU, DICT, QRDN, QRES, QRIP, INIC |
| `min_amount` | integer | Min amount in centavos |
| `max_amount` | integer | Max amount in centavos |
| `limit` | integer | Page size (default 50) |
| `offset` | integer | Offset for pagination |

### 5.3 Get Payment Details

```http
GET /api/v1/payments/{id}
Authorization: Bearer <token>
```

### 5.4 Payment History

```http
GET /api/v1/payments/{id}/history
Authorization: Bearer <token>
```

### 5.5 Create Return (pacs.004)

```http
POST /api/v1/transactions/{transaction_id}/return
Authorization: Bearer <token>
Content-Type: application/json

{
  "amount": 15000,
  "reason_code": "MD06",
  "reason_description": "Customer requested return",
  "requester": "creditor"
}
```

**Return Reason Codes:**

| Code | Description |
|------|-------------|
| `AC03` | Invalid creditor account |
| `AM04` | Insufficient funds |
| `CUST` | Customer request |
| `FRAD` | Fraud |
| `FR09` | End customer request (MED) |
| `MD06` | Return by end customer |
| `FOCR` | Following cancellation request |
| `SL01` | Specific service (Saque/Troco cash) |
| `SL02` | Specific service (Saque/Troco cash) |
| `BE08` | Related reference invalid |

### 5.6 Balance Inquiry (camt.060)

```http
GET /api/v1/balance
Authorization: Bearer <token>
```

**Additional balance endpoints:**
```http
GET /api/v1/balance/account/{ispb}       # Balance by participant
GET /api/v1/balance/history/{ispb}        # Historical balance
GET /api/v1/balance/intraday/{ispb}       # Intraday movements
GET /api/v1/balance/positions             # All participant positions
GET /api/v1/balance/liquidity/{ispb}      # Liquidity status
GET /api/v1/balance/forecast/{ispb}       # Balance forecast
```

### 5.7 Batch Payments (pain.001/002)

```http
POST /api/v1/batch
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Payroll 2026-02",
  "items": [
    {"amount": 350000, "creditor_ispb": "17184037", "creditor_account": "12345", ...},
    {"amount": 280000, "creditor_ispb": "02332886", "creditor_account": "67890", ...}
  ]
}
```

```http
GET /api/v1/batch                 # List batches
GET /api/v1/batch/{id}            # Batch details
GET /api/v1/batch/{id}/items      # Individual items
POST /api/v1/batch/{id}/process   # Submit for processing
POST /api/v1/batch/{id}/cancel    # Cancel batch
```

### 5.8 Recurrence (Scheduled Payments)

```http
POST /api/v1/recurrence
GET /api/v1/recurrence
GET /api/v1/recurrence/{id}
PUT /api/v1/recurrence/{id}
POST /api/v1/recurrence/{id}/pause
POST /api/v1/recurrence/{id}/resume
POST /api/v1/recurrence/{id}/cancel
GET /api/v1/recurrence/{id}/executions
```

### 5.9 Statements (camt.053)

```http
POST /api/v1/statements/generate
Authorization: Bearer <token>
Content-Type: application/json

{
  "from_date": "2026-02-01",
  "to_date": "2026-02-07",
  "format": "json"
}
```

```http
GET /api/v1/statements                    # List statements
GET /api/v1/statements/{id}               # Statement detail
GET /api/v1/statements/{id}/download      # Download file
GET /api/v1/statements/{id}/export/{fmt}  # Export (csv, xlsx, pdf)
GET /api/v1/statements/formats            # Available formats
GET /api/v1/statements/summaries/{year}   # Annual summaries
```

### 5.10 Echo Test (pibr.001/002)

```http
POST /api/v1/echo
Authorization: Bearer <token>
Content-Type: application/json

{
  "echo_data": "PING_TEST_12345"
}
```

**Response (200 OK):**
```json
{
  "status": "ok",
  "echo_data": "PING_TEST_12345",
  "response_time_ms": 45
}
```

Use this endpoint to verify connectivity to the BACEN SPI network.

---

## 6. API Reference — Settlement & QR Codes

### 6.1 QR Code — Static

```http
POST /api/v1/qr-codes/static
Authorization: Bearer <token>
Content-Type: application/json

{
  "pix_key": "12345678901",
  "merchant_name": "LOJA TESTE LTDA",
  "merchant_city": "SAO PAULO",
  "description": "Pagamento na loja"
}
```

### 6.2 QR Code — Dynamic

```http
POST /api/v1/qr-codes/dynamic
Authorization: Bearer <token>
Content-Type: application/json

{
  "pix_key": "12345678901",
  "amount": 15000,
  "merchant_name": "LOJA TESTE LTDA",
  "merchant_city": "SAO PAULO",
  "description": "Pedido #12345",
  "txid": "PEDIDO12345",
  "expires_in": 3600
}
```

### 6.3 QR Code Operations

```http
GET /api/v1/qr-codes                         # List QR codes
GET /api/v1/qr-codes/{id}                     # QR code details
GET /api/v1/qr-codes/txid/{tx_id}             # Query by transaction ID
GET /api/v1/qr-codes/{id}/status              # Check status
POST /api/v1/qr-codes/{id}/use                # Mark as used
POST /api/v1/qr-codes/{id}/cancel             # Cancel
PUT /api/v1/qr-codes/{id}/deactivate          # Deactivate
POST /api/v1/qr-codes/validate                # Validate BR Code payload
GET /api/v1/qr-codes/{id}/revisions           # Revision history
POST /api/v1/qr-codes/{id}/revisions          # Create revision
```

### 6.4 Composite QR Codes

```http
POST /api/v1/qr-codes/composite              # Create composite QR
GET /api/v1/qr-codes/composite/{id}           # Details
GET /api/v1/qr-codes/composite/{id}/components  # Components
```

### 6.5 Settlement Sessions

```http
GET /api/v1/sessions                           # List sessions
POST /api/v1/sessions                          # Create session
GET /api/v1/sessions/current/{type}            # Current active session (d0, d1, d2)
GET /api/v1/sessions/{id}                      # Session details
POST /api/v1/sessions/{id}/open                # Open session
POST /api/v1/sessions/{id}/close               # Close session
POST /api/v1/sessions/{id}/finalize            # Finalize session
POST /api/v1/sessions/{id}/cancel              # Cancel session
GET /api/v1/sessions/{id}/statistics           # Session statistics
```

**Session Lifecycle:** `SCHEDULED` -> `OPEN` -> `PROCESSING` -> `CLOSED` -> `FINALIZED`

### 6.6 Reports

```http
GET /reports/templates                          # Available templates
POST /reports/generate                          # Generate report
GET /reports/generated                          # List generated reports
GET /reports/generated/{id}                     # Report details
GET /reports/generated/{id}/download            # Download report
GET /reports/schedules                          # Scheduled reports
```

---

## 7. API Reference — MED 2.0 Fraud Recovery

### 7.1 Create Funds Recovery

```http
POST /api/v2/funds-recoveries
Authorization: Bearer <token>
Content-Type: application/json

{
  "original_transaction_id": "E12345678202602071234ABCD1234",
  "amount": 15000,
  "reason": "FRAUD_SUSPICION",
  "details": "Customer reported unauthorized transaction"
}
```

### 7.2 Recovery Operations

```http
GET /api/v2/funds-recoveries                   # List recoveries
GET /api/v2/funds-recoveries/{id}               # Recovery details
PUT /api/v2/funds-recoveries/{id}               # Update status
POST /api/v2/funds-recoveries/{id}/cancel       # Cancel recovery
POST /api/v2/funds-recoveries/{id}/start-refund # Initiate refund
```

### 7.3 Tracking & Reports

```http
GET /api/v2/funds-recoveries/{id}/tracking-graph       # Fund flow graph
POST /api/v2/funds-recoveries/{id}/tracking-graph      # Generate graph
GET /api/v2/funds-recoveries/{id}/infraction-reports    # Related infractions
GET /api/v2/funds-recoveries/{id}/refunds               # Associated refunds
POST /api/v2/funds-recoveries/{id}/refund               # Create refund
GET /api/v2/funds-recoveries/{id}/refund-summary        # Refund summary
```

### 7.4 Infraction Reports

```http
GET /api/v2/infraction-reports                          # List infractions
GET /api/v2/infraction-reports/{id}                     # Details
PUT /api/v2/infraction-reports/{id}/acknowledge          # Acknowledge
PUT /api/v2/infraction-reports/{id}/analyse               # Submit analysis
PUT /api/v2/infraction-reports/{id}/close                 # Close infraction
```

### 7.5 Refund Requests

```http
GET /api/v2/refund-requests                              # List refunds
GET /api/v2/refund-requests/{id}                         # Details
PUT /api/v2/refund-requests/{id}/complete                # Complete refund
POST /api/v2/refund-requests/{id}/cancel                  # Cancel refund
```

---

## 8. ISO 20022 Message Catalog

Monetarie PIX supports all 27 BACEN SPI message types:

### Payment Messages

| Type | Name | Direction | Purpose |
|------|------|-----------|---------|
| pacs.008 | FIToFICstmrCdtTrf | Outbound | Payment initiation |
| pacs.002 | FIToFIPmtStsRpt | Inbound | Payment status (ACCC/RJCT/PDNG) |
| pacs.004 | PmtRtr | Outbound | Payment return |
| pacs.028 | FIToFIPmtStsReq | Outbound | Status inquiry |

### Balance & Reports

| Type | Name | Direction | Purpose |
|------|------|-----------|---------|
| camt.052 | BkToCstmrAcctRpt | Inbound | Intraday balance report |
| camt.053 | BkToCstmrStmt | Inbound | End-of-day statement |
| camt.054 | BkToCstmrDbtCdtNtfctn | Inbound | Debit/credit notification |
| camt.055 | CstmrPmtCxlReq | Outbound | Cancellation request |
| camt.060 | AcctRptgReq | Outbound | Balance inquiry |

### Batch Payments

| Type | Name | Direction | Purpose |
|------|------|-----------|---------|
| pain.001 | CstmrCdtTrfInitn | Outbound | Batch initiation |
| pain.002 | CstmrPmtStsRpt | Inbound | Batch status |

### Recurrence (PIX Automatico)

| Type | Name | Direction | Purpose |
|------|------|-----------|---------|
| pain.009 | MndtInitnReq | Outbound | Mandate initiation |
| pain.011 | MndtAmdmntReq | Outbound | Mandate amendment |
| pain.012 | MndtAccptncRpt | Inbound | Mandate acceptance |
| pain.013 | CdtrPmtActvtnReq | Outbound | Creditor payment activation |

### Administrative

| Type | Name | Direction | Purpose |
|------|------|-----------|---------|
| admi.002 | admi.002 | Inbound | System event notification |
| admi.004 | admi.004 | Outbound | System event acknowledgment |
| admi.005 | admi.005 | Bidirectional | System status |
| admi.006 | admi.006 | Bidirectional | Resend request |
| admi.007 | admi.007 | Bidirectional | Receipt acknowledgment |
| admi.009 | admi.009 | Bidirectional | Session info |
| admi.011 | admi.011 | Bidirectional | Config request |

### Connectivity

| Type | Name | Direction | Purpose |
|------|------|-----------|---------|
| pibr.001 | EchoReq | Outbound | Echo request (connectivity test) |
| pibr.002 | EchoResp | Inbound | Echo response |

### PIX Cash (Saque/Troco)

| Type | Name | Direction | Purpose |
|------|------|-----------|---------|
| camt.025 | RctAck | Outbound | Receipt acknowledgment |
| camt.029 | RsltnOfInvstgtn | Bidirectional | Investigation resolution |

---

## 9. Error Handling (RFC 7807)

All error responses follow RFC 7807 Problem Details format:

```json
{
  "type": "about:blank",
  "title": "Error Title",
  "status": 400,
  "detail": "Detailed human-readable description",
  "instance": "/api/v2/entries/12345678901",
  "code": "AB03"
}
```

**Content-Type:** `application/problem+json`

### Common HTTP Status Codes

| Status | Meaning | When |
|--------|---------|------|
| 200 | OK | Successful GET/PUT/PATCH |
| 201 | Created | Successful POST (resource created) |
| 204 | No Content | Successful DELETE |
| 400 | Bad Request | Invalid parameters, missing fields |
| 401 | Unauthorized | Missing/invalid/expired token |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Duplicate key, concurrent modification |
| 422 | Unprocessable Entity | Business rule violation |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected system error |
| 503 | Service Unavailable | Service not ready |

### BACEN-Specific Error Codes

| Code | Description | HTTP Status |
|------|-------------|-------------|
| AB03 | Timeout | 408 |
| AB06 | Offline | 503 |
| AB09 | Unexpected error | 500 |
| AC03 | Invalid creditor account | 422 |
| AC06 | Account blocked | 422 |
| AC14 | Invalid creditor account type | 422 |
| AM04 | Insufficient funds | 422 |
| AM09 | Wrong amount | 422 |
| AM18 | Invalid number of transactions | 422 |
| BE01 | Invalid debtor | 422 |
| BE17 | Invalid creditor | 422 |
| DS04 | Order rejected | 422 |
| FF01 | Invalid file format | 400 |
| MD01 | No valid mandate | 422 |
| RC01 | Bank identifier incorrect | 422 |
| RR04 | Regulatory reason | 422 |

---

## 10. Rate Limiting

### Rate Limit Categories

Your institution is assigned a category based on transaction volume:

| Category | Capacity | Refill/min | Typical Institutions |
|----------|----------|------------|---------------------|
| A | 50,000 | 25,000 | Major banks (BB, Itau, Bradesco) |
| B | 25,000 | 12,500 | Large fintechs (Nubank, Inter) |
| C | 10,000 | 5,000 | Medium institutions |
| D | 5,000 | 2,500 | Smaller banks |
| E | 2,000 | 1,000 | Payment institutions |
| F | 1,000 | 500 | Small payment institutions |
| G | 500 | 250 | Micro institutions |
| H | 1,000 | 500 | Default (new integrations) |

### Handling Rate Limits

When you receive HTTP 429:

```json
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Please wait before trying again.",
  "retry_after": 60
}
```

**Best Practices:**
1. Implement exponential backoff
2. Respect `Retry-After` header
3. Monitor `X-RateLimit-Remaining` to proactively throttle
4. Use batch endpoints for bulk operations
5. Cache responses where possible

### Exempt Endpoints (No Rate Limiting)

- `POST /api/v1/auth/login`
- `POST /api/v1/auth/logout`
- `POST /api/v1/auth/refresh`
- `GET /api/v1/auth/me`
- `GET /health`
- `GET /ready`

---

## 11. Security Requirements

### Transport Security

- **TLS 1.2+** required for all connections
- Certificate pinning recommended for production
- All HTTP automatically redirected to HTTPS

### Authentication Security

- Store JWT tokens securely (never in localStorage for web apps)
- Rotate tokens before expiry (use `/api/v1/auth/refresh`)
- Use `X-Participant-ISPB` header for proper rate limiting and audit

### BACEN Compliance (for Direct RSFN Participants)

If your institution connects directly to BACEN through Monetarie:

1. **mTLS Certificates** — ICP-Brasil CPIC certificates for transport
2. **XMLDSig Signing** — ICP-Brasil CPIA certificates for message signing
3. **Audit Trail** — 10-year retention for ICOM messages, 2-year for DICT reads
4. **XML Archival** — SHA-256 hash integrity for all archived messages

### IP Whitelisting

Contact Monetarie operations to whitelist your IP addresses for production access.

---

## 12. Onboarding Checklist

### Phase 1 — Setup (Week 1)

- [ ] Sign Monetarie PIX integration agreement
- [ ] Receive API credentials (username/password)
- [ ] Receive assigned ISPB code and rate limit category
- [ ] Configure network access (IP whitelist)
- [ ] Set up development environment

### Phase 2 — Development (Weeks 2-4)

- [ ] Implement authentication flow (login, token management, refresh)
- [ ] Implement PIX key management (DICT API)
- [ ] Implement payment initiation (pacs.008)
- [ ] Implement payment status handling (pacs.002)
- [ ] Implement return flow (pacs.004)
- [ ] Implement balance inquiry (camt.060/052)
- [ ] Implement error handling (RFC 7807)
- [ ] Implement rate limit handling (429 + Retry-After)

### Phase 3 — Homologation (Weeks 5-6)

- [ ] Run echo test (`POST /api/v1/echo`) — verify connectivity
- [ ] Execute happy path scenario — send payment, verify acceptance
- [ ] Execute rejection scenario — verify proper error handling
- [ ] Execute return flow — send payment, then return
- [ ] Execute balance check — verify balance reporting
- [ ] Execute full cycle — payment + notification + balance
- [ ] Run stress test — 50+ concurrent payments
- [ ] Run MED 2.0 recovery flow (if applicable)
- [ ] Verify rate limiting behavior under load

### Phase 4 — Go-Live (Week 7)

- [ ] Switch to production credentials
- [ ] Configure production IP whitelist
- [ ] Verify production connectivity
- [ ] Execute smoke tests in production
- [ ] Enable monitoring and alerting
- [ ] Document escalation procedures

### Support Contacts

| Channel | Contact |
|---------|---------|
| Technical Support | suporte@fluxiq.com.br |
| Operations (24/7) | operacoes@fluxiq.com.br |
| Emergency Hotline | +55 11 XXXX-XXXX |

---

## 13. Testing & Homologation

### Simulator Mode

Monetarie provides a built-in BACEN simulator for testing without connecting to the real BACEN network. The simulator:

- Responds to all 27 SPI message types
- Configurable accept rate (default 90%)
- Simulates response delays (50-500ms)
- Supports all 8 standard test scenarios
- Generates realistic inbound messages

**Simulator is enabled in the development environment by default.**

### Test Accounts

| PIX Key | Type | Institution | Owner |
|---------|------|-------------|-------|
| 12345678901 | CPF | Monetarie | JOAO SILVA TESTE |
| 98765432100 | CPF | Monetarie | MARIA SANTOS TESTE |
| +5511999990001 | PHONE | Monetarie | PEDRO OLIVEIRA |
| teste@fluxiq.com.br | EMAIL | Monetarie | ANA COSTA |
| 33344455566 | CPF | Itau (simulated) | ROBERTO ALMEIDA |
| user@nubank.com.br | EMAIL | Nubank (simulated) | FERNANDO SOUZA |

### Test Scenario: Happy Path

```bash
# 1. Authenticate
curl -X POST https://pixadmin-dev.fluxiq.com.br/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"login":"integration","password":"Monetarie@2026!"}'

# 2. Create payment (save the token from step 1)
curl -X POST https://pixadmin-dev.fluxiq.com.br/api/v1/payments \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction": {
      "amount": 15000,
      "debtor_ispb": "12345678",
      "creditor_ispb": "17184037",
      "debtor_document": "12345678901",
      "creditor_document": "33344455566",
      "debtor_account": "123456",
      "creditor_account": "654321",
      "local_instrument": "DICT",
      "creditor_proxy": "33344455566"
    }
  }'

# 3. Check payment status
curl https://pixadmin-dev.fluxiq.com.br/api/v1/payments/<payment_id> \
  -H "Authorization: Bearer <token>"
```

---

## Appendix A — BACEN Error Codes

### Rejection Codes (pacs.002 RJCT)

| Code | Category | Severity | Description |
|------|----------|----------|-------------|
| AB03 | TIMEOUT | ERROR | Transaction timeout |
| AB06 | CLEARING | ERROR | Offline clearing |
| AB09 | SYSTEM | ERROR | Unexpected error |
| AC03 | ACCOUNT | ERROR | Invalid creditor account number |
| AC06 | ACCOUNT | ERROR | Account blocked |
| AC14 | ACCOUNT | ERROR | Invalid creditor account type |
| AG03 | AMOUNT | ERROR | Transaction not supported |
| AM01 | AMOUNT | ERROR | Zero amount |
| AM04 | AMOUNT | ERROR | Insufficient funds |
| AM09 | AMOUNT | ERROR | Wrong amount |
| AM18 | AMOUNT | ERROR | Invalid number of transactions |
| BE01 | DEBTOR | ERROR | Inconsistent with end customer |
| BE17 | CREDITOR | ERROR | Unknown creditor |
| DS04 | CLEARING | ERROR | Order rejected |
| DS24 | CLEARING | WARNING | Order accepted technically |
| DT02 | DEBTOR | ERROR | Invalid date/time |
| DT05 | DEBTOR | ERROR | Date/time out of range |
| FF01 | FORMAT | ERROR | Invalid file format |
| MD01 | MANDATE | ERROR | No mandate |
| RC01 | CLEARING | ERROR | Bank identifier incorrect |
| RR04 | REGULATORY | ERROR | Regulatory reason |
| SL01 | SERVICE | WARNING | Specific service offered |
| SL02 | SERVICE | WARNING | Specific service offered |

### Return Codes (pacs.004)

| Code | Category | Severity | Description |
|------|----------|----------|-------------|
| FR09 | FRAUD | ERROR | End customer refund request (MED) |
| MD06 | DEBTOR | ERROR | Return by end customer |
| FOCR | CLEARING | ERROR | Following cancellation request |
| SL11 | SERVICE | WARNING | Cash withdrawal return |
| BE08 | DEBTOR | ERROR | Related reference invalid |

---

## Appendix B — NATS Event Subjects

If your integration uses event-driven patterns (e.g., webhook callbacks), these are the NATS JetStream subjects you can subscribe to:

### Transaction Events

| Subject | Event |
|---------|-------|
| `monetarie.spi.transaction.created` | New transaction initiated |
| `monetarie.spi.transaction.processing` | Transaction being processed |
| `monetarie.spi.transaction.accepted` | Transaction accepted by BACEN |
| `monetarie.spi.transaction.settled` | Transaction settled |
| `monetarie.spi.transaction.rejected` | Transaction rejected |
| `monetarie.spi.transaction.returned` | Transaction returned |
| `monetarie.spi.return.created` | Return initiated |
| `monetarie.spi.return.settled` | Return settled |

### Balance Events

| Subject | Event |
|---------|-------|
| `monetarie.spi.balance.updated.<ispb>` | Balance changed for participant |
| `monetarie.spi.block.created.<ispb>` | Balance block applied |
| `monetarie.spi.block.released.<ispb>` | Balance block released |

### DICT Events

| Subject | Event |
|---------|-------|
| `monetarie.dict.keys.created` | PIX key registered |
| `monetarie.dict.keys.deleted` | PIX key deleted |
| `monetarie.dict.keys.blocked` | PIX key blocked |
| `monetarie.dict.claims.initiated` | Portability claim started |
| `monetarie.dict.claims.completed` | Portability claim completed |

### Settlement Events

| Subject | Event |
|---------|-------|
| `monetarie.settlement.session.opened` | Settlement session opened |
| `monetarie.settlement.session.closed` | Settlement session closed |
| `monetarie.settlement.netting.completed` | Netting cycle completed |
| `monetarie.settlement.reconciliation.completed` | Reconciliation done |

---

## 14. Core Banking Integration (NATS)

This section is the **integration spec for the Core Banking team**. It documents the bidirectional NATS integration between PIX and Core Banking, enabling Internet Banking users to send/receive PIX payments, manage keys, and perform lookups.

**PIX side is fully implemented.** Core team must complete the items listed in [Section 14.9](#149-core-team-action-items).

---

### 14.1 Architecture Overview

```
┌────────────────────┐     NATS JetStream (shared cluster)     ┌──────────────────────┐
│                    │                                          │                      │
│   CORE BANKING     │  monetarie.core.pix.*   ──────────────►    │   PIX SUBSYSTEM      │
│                    │  (MONETARIE_CORE stream)                    │                      │
│  Publisher.ex      │                                          │  CoreEventProcessor  │
│  PixConsumer.ex    │  monetarie.spi.transaction.*  ◄──────────   │  InboundProcessor    │
│  PixHandler.ex     │  monetarie.spi.return.*       ◄──────────   │  StatusUpdater       │
│                    │  monetarie.settlement.session.* ◄─────────  │  Scheduler           │
│                    │  (MONETARIE_SPI / MONETARIE_SETTLEMENT)        │                      │
└────────────────────┘                                          └──────────────────────┘
```

**NATS cluster:** Shared `nats-dev-{1,2,3}` (10.10.40.{5,7,4}:4222)

---

### 14.2 Authentication — Shared JWT Secret

PIX now accepts Guardian HS256 tokens signed by Core. The secret resolution chain (in order):

| Priority | Env Var | Source |
|----------|---------|--------|
| 1 | `JWT_SECRET` | PIX-native secret |
| 2 | `GUARDIAN_SECRET_KEY` | Core Guardian secret |
| 3 | `SECRET_KEY_BASE` | Shared Phoenix secret |

**Issuer handling:**

| `iss` claim | Accepted? | `target_system` required? |
|-------------|-----------|---------------------------|
| `"monetarie"` | Yes | No |
| `"monetarie-sso"` | Yes | Yes (`"pix"`) |
| `"monetarie"` | Yes (PIX-native) | No |

Core Guardian config (`config.exs`) uses `issuer: "monetarie"` — this works out of the box with the updated PIX auth.

**Dev environment:** For local testing, both services must share the same secret value. Core dev currently uses `"dev-only-secret-key-not-for-production"` in `config/dev.exs`. Set `JWT_SECRET` to this value when running PIX locally against Core dev, or vice-versa.

---

### 14.3 NATS Contract — Core → PIX (6 events)

Core publishes to `monetarie.core.pix.<event>`. PIX creates the `MONETARIE_CORE` stream and consumes via the `core-event-processor` durable consumer.

> **IMPORTANT:** The `"event"` field is the **routing key**. PIX pattern-matches on this field to dispatch to the correct handler. If it's missing or misspelled, the message goes to the unknown-event fallback (logged + acked, no processing).

**Amounts are always in centavos (integer).** R$ 150,00 = `15000`.

#### 14.3.1 `payment_request` — Send PIX

Subject: `monetarie.core.pix.payment_request`

```json
{
  "event": "payment_request",
  "transaction_id": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 15000,
  "debtor_ispb": "53822116",
  "creditor_ispb": "00360305",
  "end_to_end_id": "E5382211620260207143025abc12345678",
  "local_instrument": "pacs.008",
  "institution_id": 1,
  "branch_id": 1
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `event` | string | **Yes** | Must be `"payment_request"` |
| `transaction_id` | string (UUID) | No | Core's transaction reference. If omitted, PIX generates one |
| `amount` | integer | **Yes** | Amount in centavos |
| `debtor_ispb` | string (8 digits) | **Yes** | Payer's ISPB |
| `creditor_ispb` | string (8 digits) | **Yes** | Payee's ISPB |
| `end_to_end_id` | string (34 chars) | No | E2E ID. If omitted, PIX generates one (format: `E<ISPB><YYYYMMDDHHmmss><random11>`) |
| `local_instrument` | string | No | ISO 20022 message type. Defaults to `"pacs.008"` |
| `institution_id` | integer | No | Defaults to `1` |
| `branch_id` | integer | No | Defaults to `1` |

**What PIX does:** Creates an outbound Transaction record → publishes `monetarie.spi.transaction.created` (which triggers OutboundSender → BACEN).

#### 14.3.2 `return_request` — Return PIX

Subject: `monetarie.core.pix.return_request`

```json
{
  "event": "return_request",
  "original_transaction_id": "42",
  "amount": 15000,
  "reason_code": "MD06"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `event` | string | **Yes** | Must be `"return_request"` |
| `original_transaction_id` | string/integer | **Yes** | PIX transaction ID (from `monetarie.spi.transaction.created` event) |
| `amount` | integer | **Yes** | Return amount in centavos |
| `reason_code` | string | No | BACEN reason code (e.g., `"MD06"`, `"SL02"`) |

**What PIX does:** Looks up original transaction → creates pacs.004 return → publishes `monetarie.spi.transaction.returned`.

#### 14.3.3 `key_create` — Create PIX Key

Subject: `monetarie.core.pix.key_create`

```json
{
  "event": "key_create",
  "key_type": "CPF",
  "key_value": "12345678901",
  "owner_name": "João Silva",
  "owner_document": "12345678901",
  "owner_ispb": "53822116",
  "account_number": "123456",
  "account_type": "CACC",
  "branch": "0001"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `event` | string | **Yes** | Must be `"key_create"` |
| `key_type` | string | **Yes** | One of: `CPF`, `CNPJ`, `PHONE`, `EMAIL`, `EVP` |
| `key_value` | string | **Yes** | The key value (CPF digits, phone with +55, email, etc.) |
| `owner_name` | string | No | Account holder name |
| `owner_document` | string | No | CPF/CNPJ |
| `owner_ispb` | string | No | Owner's ISPB |
| `account_number` | string | No | Account number |
| `account_type` | string | No | `"CACC"` (checking), `"SVGS"` (savings), `"SLRY"` (salary) |
| `branch` | string | No | Branch code |

**What PIX does:** Proxies to DICT service `POST /api/v2/entries` → publishes `monetarie.dict.keys.created`.

#### 14.3.4 `key_delete` — Delete PIX Key

Subject: `monetarie.core.pix.key_delete`

```json
{
  "event": "key_delete",
  "key_value": "12345678901"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `event` | string | **Yes** | Must be `"key_delete"` |
| `key_value` | string | **Yes** | The key value to delete |

**What PIX does:** Proxies to DICT service `DELETE /api/v2/entries/:key` → publishes `monetarie.dict.keys.deleted`.

#### 14.3.5 `dict_lookup` — Look Up PIX Key (Request-Reply)

Subject: `monetarie.core.pix.dict_lookup`

```json
{
  "event": "dict_lookup",
  "key_value": "+5511999999999",
  "reply_subject": "monetarie.core.reply.dict-lookup.abc123"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `event` | string | **Yes** | Must be `"dict_lookup"` |
| `key_value` | string | **Yes** | Key to look up |
| `reply_subject` | string | **Yes** | NATS subject where PIX sends the response |

**Reply payload** (published to `reply_subject`):

```json
// Success
{"status": "found", "data": {"key_type": "PHONE", "key_value": "+5511999999999", "owner_name": "Maria Santos", "ispb": "00360305", "account_number": "123456"}}

// Not found
{"status": "not_found", "data": null}

// Error
{"status": "error", "error": "DICT returned status 500"}
```

#### 14.3.6 `balance_inquiry` — Query SPI Balance (Request-Reply)

Subject: `monetarie.core.pix.balance_inquiry`

```json
{
  "event": "balance_inquiry",
  "ispb": "53822116",
  "reply_subject": "monetarie.core.reply.balance.abc456"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `event` | string | **Yes** | Must be `"balance_inquiry"` |
| `ispb` | string (8 digits) | **Yes** | ISPB to query |
| `reply_subject` | string | **Yes** | NATS subject for response |

**Reply payload:**

```json
// Success
{"ispb": "53822116", "available": 5000000, "blocked": 150000, "total": 5150000, "status": "ok"}

// No balance record
{"ispb": "53822116", "available": 0, "blocked": 0, "total": 0, "status": "not_found"}
```

All amounts in centavos.

---

### 14.4 NATS Contract — PIX → Core (existing, enhanced)

Core's `PixConsumer` (stream `MONETARIE_PIX`, consumer `core-pix-consumer`) already subscribes to:
- `monetarie.spi.transaction.*`
- `monetarie.spi.payment.*`
- `monetarie.spi.return.*`
- `monetarie.settlement.session.*`

PIX has now added **Core-compatible fields** to all events so `PixHandler` can process them directly:

| Field | Type | Description |
|-------|------|-------------|
| `type` | string | Event category: `"pix_transaction"`, `"pix_return"` |
| `transaction_id` | string/integer | PIX internal transaction ID |
| `amount` | integer | Amount in centavos |
| `direction` | string | `"INBOUND"` or `"OUTBOUND"` |
| `end_to_end_id` | string | SPI E2E identifier |
| `status` | string | Current status (`"settled"`, `"rejected"`, etc.) |
| `source` | string | Always `"pix"` |
| `published_at` | string (ISO 8601) | Event timestamp |

#### Example: Transaction Created Event

Published to `monetarie.spi.transaction.created`:

```json
{
  "transaction_id": 42,
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "message_type": "pacs.008",
  "event_type": "TRANSACTION_CREATED",
  "debtor_ispb": "53822116",
  "creditor_ispb": "00360305",
  "end_to_end_id": "E5382211620260207143025abc12345678",
  "direction": "OUTBOUND",
  "created_at": "2026-02-07T14:30:25.123456Z",
  "type": "pix_transaction",
  "amount": 15000,
  "source": "pix",
  "published_at": "2026-02-07T14:30:25.123456Z"
}
```

#### Example: Transaction Settled Event

Published to `monetarie.settlement.transaction.settled`:

```json
{
  "transaction_id": 42,
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "debtor_ispb": "53822116",
  "creditor_ispb": "00360305",
  "end_to_end_id": "E5382211620260207143025abc12345678",
  "direction": "OUTBOUND",
  "settled_at": "2026-02-07T14:30:35.654321Z",
  "type": "pix_transaction",
  "status": "settled",
  "source": "pix",
  "published_at": "2026-02-07T14:30:35.654321Z"
}
```

---

### 14.5 Migration — Core Publisher Changes

Core's `Publisher` currently publishes PIX-related events to **`ledger.transaction.pix*`** subjects. These are **not consumed by PIX** (PIX only consumes from `monetarie.core.pix.*`).

**Current Core publisher subjects (to be migrated):**

| Current Subject | New Subject | Event |
|----------------|-------------|-------|
| `ledger.transaction.pix` | `monetarie.core.pix.payment_request` | PIX payment initiation |
| `ledger.transaction.pix_payment` | `monetarie.core.pix.payment_request` | QR code payment |
| `ledger.transaction.pix_return` | `monetarie.core.pix.return_request` | Return/refund |

**Note:** The `ledger.*` subjects can continue to exist for Core-internal consumption. The new `monetarie.core.pix.*` subjects are **additional** publications for PIX.

---

### 14.6 Error Handling & Retries

PIX's `CoreEventProcessor` has built-in retry and dead-letter handling:

| Behavior | Configuration |
|----------|---------------|
| Max retries | 5 attempts (exponential backoff by JetStream) |
| Ack timeout | 30 seconds |
| Unknown events | Acked immediately (no retry), logged as warning |
| Permanent failure | Published to DLQ (`monetarie.dlq.monetarie.core.pix`) |
| Malformed JSON | Acked (no retry), published to DLQ |

**For request-reply events** (`dict_lookup`, `balance_inquiry`): If PIX encounters an error, it publishes an error response to the `reply_subject` rather than silently failing:

```json
{"status": "error", "error": "description of what went wrong"}
```

Core should implement a timeout (recommended: 10 seconds) when waiting for reply-subject responses.

---

### 14.7 End-to-End Flows

#### Flow 1: Banking User Sends PIX

```
1. Banking User → Core UI (clicks "Send PIX")
2. Core Backend → NATS: publish to monetarie.core.pix.payment_request
3. PIX CoreEventProcessor: validates + creates Transaction (status=PENDING)
4. PIX → NATS: monetarie.spi.transaction.created
5. PIX OutboundSender: sends pacs.008 to BACEN
6. BACEN → PIX InboundProcessor: pacs.002 response (ACCC=settled, RJCT=rejected)
7. PIX StatusUpdater: updates Transaction status
8. PIX → NATS: monetarie.spi.transaction.settled (or .rejected)
9. Core PixHandler: receives event → updates ledger + TigerBeetle
```

#### Flow 2: Banking User Looks Up Key Before Sending

```
1. Core Backend → NATS: publish to monetarie.core.pix.dict_lookup (with reply_subject)
2. PIX CoreEventProcessor: queries DICT service
3. PIX → NATS: publishes result to reply_subject
4. Core: receives reply with key holder details
5. Core: shows confirmation screen to user
6. User confirms → triggers Flow 1 (payment_request)
```

#### Flow 3: Banking User Returns PIX

```
1. Core Backend → NATS: publish to monetarie.core.pix.return_request
2. PIX CoreEventProcessor: looks up original transaction, creates pacs.004 return
3. PIX → NATS: monetarie.spi.transaction.returned
4. PIX OutboundSender: sends pacs.004 to BACEN
5. Core PixHandler: receives returned event → credits user ledger
```

---

### 14.8 GKE Secret Configuration

Both PIX and Core must reference the **same** JWT secret in GKE.

**PIX namespace (`pix`) — already configured:**

```yaml
env:
- name: JWT_SECRET
  valueFrom:
    secretKeyRef:
      name: monetarie-shared-jwt-secret
      key: secret
- name: GUARDIAN_SECRET_KEY
  valueFrom:
    secretKeyRef:
      name: monetarie-shared-jwt-secret
      key: secret
```

**Core namespace (`core`) — needs to reference the same secret:**

```yaml
env:
- name: GUARDIAN_SECRET_KEY
  valueFrom:
    secretKeyRef:
      name: monetarie-shared-jwt-secret
      key: secret
```

**Option A (recommended):** Create the K8s secret in both namespaces:
```bash
# Generate a strong secret
SECRET=$(openssl rand -base64 48)

# Create in both namespaces
kubectl create secret generic monetarie-shared-jwt-secret \
  --namespace=core --from-literal=secret="$SECRET"

kubectl create secret generic monetarie-shared-jwt-secret \
  --namespace=pix --from-literal=secret="$SECRET"
```

**Option B:** Use a shared-secrets mechanism (e.g., Sealed Secrets, External Secrets Operator).

---

### 14.9 Core Team Action Items

| # | Action | Priority | Details |
|---|--------|----------|---------|
| 1 | **Add publisher for `monetarie.core.pix.*`** | BLOCKER | Add 6 new publish functions in `Publisher` for the Core→PIX events. The `"event"` field must match exactly (see Section 14.3). Existing `ledger.transaction.pix*` subjects can remain for internal use. |
| 2 | **Create shared K8s secret** | BLOCKER | Create `monetarie-shared-jwt-secret` in both `core` and `pix` namespaces with the same value (see Section 14.8). |
| 3 | **Validate PixHandler compatibility** | HIGH | Verify that `PixHandler.handle_transaction/1` works with the new fields added to `monetarie.spi.transaction.*` events (`type`, `source`, `published_at`). These are additive — no existing fields were removed. |
| 4 | **Implement reply-subject consumer** | HIGH | For `dict_lookup` and `balance_inquiry`, Core must subscribe to its `reply_subject` and handle the JSON response within a 10s timeout. |
| 5 | **Dev environment secret alignment** | MEDIUM | For local development, set PIX `JWT_SECRET` to Core's dev secret (`"dev-only-secret-key-not-for-production"` from `config/dev.exs`) or vice-versa. |
| 6 | **Add `MONETARIE_CORE` stream to Core NATS setup** | LOW | PIX auto-creates the `MONETARIE_CORE` stream. Core only needs to publish to `monetarie.core.pix.*` — no stream creation needed on Core side. However, Core should ensure its NATS connection can reach the shared cluster. |

### 14.10 Verification Checklist

After both sides are deployed:

```bash
# 1. Auth — Core token accepted by PIX
TOKEN_CORE=$(curl -s https://coreapi-dev.fluxiq.com.br/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@monetarie.com.br","password":"Monetarie#Adm@2026"}' | jq -r .token)

curl -s https://pixapi-dev.fluxiq.com.br/api/v1/payments \
  -H "Authorization: Bearer $TOKEN_CORE" -w "\n%{http_code}"
# Expected: 200 (not 401)

# 2. NATS stream exists
kubectl exec -n pix deployment/pix-backend -- bin/monetarie_pix eval \
  'IO.inspect(Shared.Nats.JetStream.publish_core_event("payment_request", %{"event" => "payment_request", "amount" => 100, "debtor_ispb" => "53822116", "creditor_ispb" => "00360305"}))'
# Expected: :ok

# 3. Core→PIX flow (manual NATS publish)
kubectl exec -n nats deployment/nats-0 -- nats pub monetarie.core.pix.balance_inquiry \
  '{"event":"balance_inquiry","ispb":"53822116","reply_subject":"test.reply.123"}'
# Check PIX logs for: [CoreEventProcessor] Balance inquiry for ISPB: 53822116
```

---

*Document generated by Monetarie Engineering Team — 2026-02-07*
