# CBE

> Detail page: four URL shapes (two short-link variants and two direct endpoints), two response schemas (PDF and JSON), and how the resolver routes between them.

CBE has the busiest URL surface of any provider: four supported shapes that resolve to one of two upstream backends. Pass any of them; the resolver figures out the right call.

## URL formats

### 1. Short-link, **dashed** id → PDF backend

```
https://mbreciept.cbe.com.et/<id>           # id contains a "-"
```

| Part | Pattern | Example |
|---|---|---|
| host | literal | `mbreciept.cbe.com.et` |
| `<id>` | `FT[A-Z0-9]+-\d+` | `FT00000000-12345678` |

**Resolution:** dash is stripped → call `apps.cbe.com.et:100/?id=<stripped>` which returns a PDF. We parse with `pdf-parse`.

### 2. Short-link, **plain** token → JSON backend

```
https://mbreciept.cbe.com.et/<token>        # no dash, mixed case
```

| Part | Pattern | Example |
|---|---|---|
| `<token>` | 16+ `[A-Za-z0-9]`, at least one lowercase | `fHCxz62uM8157lCfet` |

**Resolution:** passed through to `mb.cbe.com.et/api/v1/transactions/public/transaction-detail/<token>` which returns JSON.

### 3. Direct PDF

```
https://apps.cbe.com.et:100/?id=<id>
https://apps.cbe.com.et:100/BranchReceipt/<id>
```

Pass-through. Returns a PDF.

### 4. Direct JSON

```
https://mb.cbe.com.et/api/v1/transactions/public/transaction-detail/<id>
```

Pass-through. Returns JSON.

## Return types

CBE has **two** response shapes, depending on which backend the URL resolves to. The `source` field discriminates: present (`"mb-json"`) for the JSON backend, **absent** for the PDF backend (the legacy parser).

### PDF: `source` is absent

```ts
interface CbePdfReceipt {
  // No `source` field; discriminate by its absence + providerKey === 'cbe'

  // Counterparties (mostly strings: names + masked accounts)
  payerName?: string;
  payerAccount?: string;             // masked: "1****0000"
  receiverName?: string;
  receiverAccount?: string;          // masked

  // Transaction
  paymentDate?: string;              // free text, e.g. "1/1/2026, 00:00:00 AM"
  reference?: string;                // FT-prefixed id
  paymentReason?: string;            // free text

  // Amounts (numeric, already parsed)
  transferredAmount?: number;
  serviceCharge?: number;
  vat?: number;
  totalAmount?: number;
  currency?: string;                 // "ETB" | "USD" | …
  amountInWords?: string;

  // Customer block (receipt holder profile)
  customerName?: string;
  branch?: string;

  // Company-info block (CBE's own VAT registration)
  vatReceiptNo?: string;
  vatRegistrationNo?: string;
  vatRegistrationDate?: string;
}
```

### JSON: `source: "mb-json"`

Same base fields as PDF, plus everything `mb.cbe.com.et` returns that the PDF doesn't expose.

```ts
interface CbeMbJsonReceipt {
  source: 'mb-json';

  // Shared with PDF
  payerName?: string;
  payerAccount?: string;
  receiverName?: string;
  receiverAccount?: string;
  paymentDate?: string;              // ISO 8601, e.g. "2026-01-01T00:00:00Z"
  reference?: string;
  paymentReason?: string;
  transferredAmount?: number;
  serviceCharge?: number;
  vat?: number;
  totalAmount?: number;
  currency?: string;
  vatReceiptNo?: string;

  // JSON-only enrichments
  transactionType?: string;          // e.g. "ACNX"
  processingDate?: string;           // "YYYYMMDD"
  debitValueDate?: string;
  creditValueDate?: string;
  chargeCode?: string;               // e.g. "WAIVE"
  debitTheirRef?: string;
  creditTheirRef?: string;

  commissions?: Array<{ type: string; amount: number; currency: string }>;
  taxes?: Array<{ type: string; amount: number; currency: string }>;
  paymentDetails?: string[];         // free-text notes
  creditAmount?: number;             // usually equal to debitAmount minus rounding
}
```

### Sample: PDF backend (placeholder values)

```json
{
  "payerName": "<payer name>",
  "payerAccount": "1****0000",
  "receiverName": "<receiver name>",
  "receiverAccount": "1****0000",
  "paymentDate": "1/1/2026, 00:00:00 AM",
  "reference": "FT00000000",
  "paymentReason": "Account Transfer",
  "transferredAmount": 100,
  "serviceCharge": 1.74,
  "vat": 0.26,
  "totalAmount": 102,
  "currency": "ETB",
  "amountInWords": "<amount in words>",
  "customerName": "<receipt holder>",
  "branch": "<branch>",
  "vatReceiptNo": "ABC0000",
  "vatRegistrationNo": "0000",
  "vatRegistrationDate": "1/1/2020"
}
```

### Sample: JSON backend (placeholder values)

```json
{
  "source": "mb-json",
  "payerName": "<payer name>",
  "payerAccount": "1********0000",
  "receiverName": "<receiver name>",
  "receiverAccount": "1********0000",
  "paymentDate": "2026-01-01T00:00:00Z",
  "reference": "FT00000000",
  "paymentReason": "Mobile Banking Transfer",
  "transferredAmount": 260,
  "serviceCharge": 0.61,
  "vat": 0.08,
  "totalAmount": 260.61,
  "currency": "ETB",
  "vatReceiptNo": "FT00000000",
  "transactionType": "ACNX",
  "processingDate": "20260101",
  "chargeCode": "WAIVE",
  "commissions": [{ "type": "COMFTMB", "amount": 0.5, "currency": "ETB" }],
  "taxes":       [{ "type": "15",     "amount": 0.08, "currency": "ETB" }],
  "paymentDetails": ["Mobile Banking Transfer"],
  "creditAmount": 260
}
```

## Quirks

- **`mb.cbe.com.et` is gated**: without the right `x-app-id`, `x-app-version`, `Referer`, `Origin`, and `User-Agent`, CBE returns `500 Security Alert: Invalid or tampered legacy token!`. links.et sends the full browser-equivalent header set on every JSON request.
- **PDF body has positional-only fields**: in the company-info block, labels are stacked first and values stacked second. Empty cells are omitted from values, which makes positional pairing fragile. We extract only the last three values (`vatReceiptNo` / `vatRegistrationNo` / `vatRegistrationDate`) which are stable across receipts.
- **Two amount string formats**: `mb.cbe.com.et` sometimes prefixes amounts with the currency (`"ETB0.50"`), sometimes returns bare decimals (`"260.00"`). Our parser handles both.
- **PDF endpoint runs on port `100`**: non-standard, but is the official URL. Direct port 443 doesn't work.
