# Bank of Abyssinia

> Detail page: public SPA URL, underlying API endpoint, token format, and return shape.

Bank of Abyssinia's `cs.bankofabyssinia.com/slip/` is a React SPA that fetches its data from a same-origin JSON endpoint. We bypass the SPA entirely and hit the underlying API directly.

## URL format

### Public slip URL (what users share)

```
https://cs.bankofabyssinia.com/slip/?trx=<TOKEN>
```

| Part | Pattern | Example |
| --------- | --------------------------------- | ------------------------ |
| host | literal | `cs.bankofabyssinia.com` |
| `<TOKEN>` | `FT[A-Z0-9]{15}` (17 chars total) | `FT00000000000000A` |

### What we actually hit

```
GET https://cs.bankofabyssinia.com/api/onlineSlip/getDetails/?id=<TOKEN>
Accept: application/json
Referer: https://cs.bankofabyssinia.com/slip/?trx=<TOKEN>
```

### Token anatomy

The 17-char URL token is approximately `<12-char reference><5-char suffix>`. The reference echoed inside the receipt body (`transactionReference`) is just the leading 12 chars; the trailing 5 look like a channel/branch suffix. The API wants the **full 17**, not the inner reference.

## Return type

`receipt.source === "boa-json"`. Amounts are numbers.

```ts
interface BoaReceipt {
	source: 'boa-json';

	// Identity
	transactionReference?: string; // 12-char inner reference
	paymentReference?: string;
	transactionDate?: string; // "DD/MM/YY HH:MM"
	transactionType?: string; // "Account Transfer" | …

	// Counterparties
	receiverName?: string;
	receiverAccount?: string; // masked: "1******00"

	// Amounts (numeric)
	transferredAmount?: number;
	serviceCharge?: number;
	vat?: number;
	totalAmount?: number;
	currency?: string; // "ETB"

	// Free-text
	transferredAmountInWord?: string;
	narrative?: string; // e.g. "Transfer"

	// Upstream envelope status (from header.status)
	upstreamStatus?: string; // typically "success"
}
```

### Sample (placeholder values)

```json
{
	"source": "boa-json",
	"transactionReference": "FT00000000",
	"paymentReference": "",
	"transactionDate": "01/01/26 00:00",
	"transactionType": "Account Transfer",
	"receiverName": "<receiver name>",
	"receiverAccount": "1******00",
	"transferredAmount": 10,
	"serviceCharge": 0,
	"vat": 0,
	"totalAmount": 10,
	"currency": "ETB",
	"transferredAmountInWord": "TEN BIRR",
	"narrative": "Transfer",
	"upstreamStatus": "success"
}
```

## Quirks

- **The slip page is a 456-byte React shell**: `curl` against the public URL returns the empty SPA; the receipt data only lands after the JS bundle fetches the API. We avoid that round trip entirely by going to the API directly.
- **No payer fields are exposed**: unlike telebirr or CBE, BoA's public slip never includes the sender's name or account. Only the receiver side is visible.
- **Envelope has a `header` wrapper**: the raw upstream returns `{ header: { status, audit, … }, body: [ { ...receipt } ] }`. We unwrap to a single object and lift `header.status` to `upstreamStatus`.
- **Amount strings include the currency**: some upstream fields like `amountDebitedWithCurrency` arrive as `"ETB10.50"`. Our parser strips the optional 3-letter prefix.
