Siinqee Bank unavailable (9 days). Known, ongoing.Status →
links.et

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

https://mbreciept.cbe.com.et/<id>           # id contains a "-"
PartPatternExample
hostliteralmbreciept.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.

https://mbreciept.cbe.com.et/<token>        # no dash, mixed case
PartPatternExample
<token>16+ [A-Za-z0-9], at least one lowercasefHCxz62uM8157lCfet

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

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.

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)

{
	"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)

{
	"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.

On this page