update docs
Auto Tag on Version Change / check-version (push) Failing after 13m32s

This commit is contained in:
2026-06-13 21:30:12 +05:00
parent 281864347e
commit a8cd22cbe1
51 changed files with 1830 additions and 469 deletions
+10
View File
@@ -211,6 +211,16 @@ GET https://www.bankofmaldives.com.mv/internetbanking/web/profile
`302` redirect (to `/web/redirect` or similar). The server has auto-activated the sole profile and set the `blaze_identity` cookie. Skip Step 6 and proceed directly to [OAuth Token Exchange](03-oauth-token.md).
In this fast-path the client has no real `profile_id` to track, so a placeholder `BmlProfile` is synthesized (`BmlLoginFlow.kt:127-135`):
| Field | Value |
|---|---|
| `profileId` | `username` (used as a stable temporary ID — replaced by the real customer number after `fetchUserInfo`) |
| `name` | `"Personal"` |
| `type` | `"Profile"` |
| `profileType` | `"default"` |
| `autoActivated` | `true` — sentinel; `activateProfile` skips the Step 6 GET and goes straight to OAuth |
---
## Step 6 — Activate Profile
+4 -2
View File
@@ -135,19 +135,21 @@ POST https://www.bankofmaldives.com.mv/internetbanking/oauth/token
**Content-Type:** `application/x-www-form-urlencoded`
**HTTP `User-Agent` header**: the browser/web UA (same as the initial token exchange), not the app UA. See `BmlLoginFlow.kt:341`.
| Field | Value |
|---|---|
| `grant_type` | `refresh_token` |
| `refresh_token` | Stored refresh token |
| `client_id` | `98C83590-513F-4716-B02B-EC68B7D9E7E7` |
| `Device-ID` | Same device ID from the original login |
| `User-Agent` | App user agent string |
| `User-Agent` | App user agent string (form field — distinct from the HTTP header above) |
| `x-app-version` | `2.1.44.348` |
```bash
curl --request POST \
--url 'https://www.bankofmaldives.com.mv/internetbanking/oauth/token' \
--header 'User-Agent: bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})' \
--header 'User-Agent: Mozilla/5.0 (Linux; Android {version}; {model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/... Mobile Safari/537.36' \
--data 'grant_type=refresh_token' \
--data 'refresh_token=def50200aabbcc...' \
--data 'client_id=98C83590-513F-4716-B02B-EC68B7D9E7E7' \
+11 -6
View File
@@ -78,7 +78,7 @@ curl --request GET \
"currency": "MVR",
"account_status": "Active",
"prepaid_card": false,
"product_code": "VISA",
"product_code": "C1007",
"account_visible": false,
"cardBalance": {
"AvailableLimit": 0.0,
@@ -94,7 +94,7 @@ curl --request GET \
"currency": "MVR",
"account_status": "Active",
"prepaid_card": true,
"product_code": "VISA",
"product_code": "C1007",
"account_visible": true,
"cardBalance": {
"AvailableLimit": 200.00,
@@ -164,7 +164,7 @@ curl --request GET \
| Field | Type | Description |
|---|---|---|
| `prepaid_card` | `bool` | `true` for prepaid cards |
| `product_code` | `string` | Card scheme (e.g. `"VISA"`) |
| `product_code` | `string` | BML product code, always `Cxxxx` (e.g. `"C1007"`) — see mapping below |
| `account_visible` | `bool` | `true` for credit cards, `false` for debit cards |
| `cardBalance.AvailableLimit` | `number` | Available credit/prepaid balance |
| `cardBalance.CurrentBalance` | `number` | Current outstanding balance |
@@ -179,7 +179,12 @@ curl --request GET \
### Product Code → Card Name
The `product_code` field identifies the specific card product. Known mappings:
The `product_code` field identifies the specific card product. Resolution is two-tiered (`util/bmlapi/BmlCardParser.kt`):
1. **Network icon** (Visa / Mastercard / Amex chip in the corner) — by prefix: `C1*` → Visa, `C3*` → Amex, `C8*` → Mastercard, with `C8905` and `C8995` overridden to Visa.
2. **Card image asset** — by exact-match list below; unknown codes fall back to `defaultcard.png`.
Known asset mappings:
| `product_code` | Card name | Asset |
|---|---|---|
@@ -202,12 +207,12 @@ The `product_code` field identifies the specific card product. Known mappings:
| `C3009`, `C3019`, `C3029`, `C3099`, `C3088`, `C3188` | Amex Credit Gold | `amex_credit_gold` |
| `C1001`, `C1011`, `C1082`, `C1081`, `C1101`, `C1111`, `C1181`, `C1182` | Visa Debit Generic | `visa_debit_generic` |
| `C1003`, `C1013`, `C1083`, `C1084`, `C1103`, `C1113`, `C1183`, `C1184` | Visa Gold | `visa_gold` |
| `C1005`, `C1006`, `C1089` | Visa Debit Islamic | `visa_debit_islamic` |
| `C1005`, `C1006`, `C1030`, `C1089` | Visa Debit Islamic | `visa_debit_islamic` |
| `C1007`, `C1027`, `C1097`, `C1107`, `C1197`, `C1077`, `C1177` | Visa Debit | `visa_debit` |
| `C1009`, `C1019`, `C1085`, `C1086`, `C1109`, `C1119`, `C1185`, `C1186` | Visa Platinum | `visa_platinum` |
| `C1017` | Visa Infinite | `visa_infinite` |
| `C1020`, `C1021` | Visa Debit Platinum | `visa_debit_platinum` |
| `C1030`, `C1090`, `C1130`, `C1033`, `C1133` | Visa Corporate | `visa_corporate` |
| `C1090`, `C1130`, `C1033`, `C1133` | Visa Corporate | `visa_corporate` |
| `C1040`, `C1041`, `C1047`, `C1048`, `C1050`, `C1051`, `C1087`, `C1088`, `C1140`, `C1141`, `C1147`, `C1148`, `C1150`, `C1151`, `C1187`, `C1188` | Visa Student Black | `visa_student_black` |
| `C1059`, `C1062`, `C1070`, `C1072`, `C1159`, `C1162` | Mastercard Prepaid Business | `master_prepaid_business` |
| `C1061`, `C1063`, `C1071`, `C1073`, `C1161`, `C1163` | Mastercard | `master` |
+70
View File
@@ -187,6 +187,76 @@ Fall back to `bookingDate` as-is.
---
## Pending History
Locked / pending amounts for a CASA account (e.g. unsettled card authorisations, holds). Returned as a flat list — no pagination.
### Endpoint
```
GET https://www.bankofmaldives.com.mv/internetbanking/api/mobile/history/pending/{accountId}
```
| Path parameter | Description |
|---|---|
| `accountId` | Internal account ID (`id` field from [dashboard](04-dashboard.md)) |
### Headers
| Header | Value |
|---|---|
| `Authorization` | `Bearer <access_token>` |
| `User-Agent` | `bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})` |
| `x-app-version` | `2.1.44.348` |
```bash
curl --request GET \
--url 'https://www.bankofmaldives.com.mv/internetbanking/api/mobile/history/pending/abc123def456' \
--header 'Authorization: Bearer <access_token>' \
--header 'User-Agent: bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})' \
--header 'x-app-version: 2.1.44.348'
```
### Response
```json
{
"success": true,
"payload": [
{
"LockedID": "L00012345",
"FromDate": "2026-05-16",
"LockedAmount": 75.00,
"Description": "Card authorisation — Merchant Name"
}
]
}
```
### Response Fields
| Field | Type | Description |
|---|---|---|
| `success` | `bool` | `true` on success |
| `payload` | `array` | List of pending entries (top-level array, **not** under `payload.history`) |
### Pending Entry
| Field | Type | Description |
|---|---|---|
| `LockedID` | `string` | Unique ID for the pending entry |
| `FromDate` | `string` | Date the hold was placed |
| `LockedAmount` | `number` | Held amount — always a positive number on the wire; the client treats it as a **debit** by negating (`BmlHistoryClient.kt:184`) |
| `Description` | `string` | Free-form description (counterparty/merchant) |
> **Amount sign:** the server returns `LockedAmount` as a positive number with no debit/credit indicator. All pending entries are debits (funds reserved out of the available balance), so the client negates the value before display.
> **Currency:** not returned by the server. The client assumes MVR.
Called from `AccountHistoryFragment.kt:263` to populate the pending tab of the account history view.
---
&nbsp;
---
+8 -1
View File
@@ -224,7 +224,14 @@ curl --request POST \
}
```
`success: false` — the `message` field contains the reason. Common causes: wrong OTP, insufficient balance, invalid account.
`success: false` — the error text may appear in either of two fields. The client prefers `payload` (when it is a non-blank string and not `"null"`) and falls back to `message` (`BmlTransferClient.kt:86-88`):
| Field | When used |
|---|---|
| `payload` (string) | Validation-style errors — e.g. insufficient balance, account-specific failures |
| `message` | Generic errors — e.g. invalid OTP, generic transfer failure |
Common causes: wrong OTP, insufficient balance, invalid account, currency mismatch.
---
+4
View File
@@ -148,6 +148,10 @@ curl --request GET \
| `name` | `string` | Account holder name |
| `agnt` | `string` | BIC of MIB — send as the `bank` field in the [transfer](08-transfer.md) request |
> **Client-synthesized fields**: when the app wraps this response for downstream code (`BmlValidateClient.kt:68`), it sets `trnType = "DOT"` and `validationType = "MIB"`. Neither is returned by the server.
>
> **No currency**: this endpoint does NOT return the MIB account's currency. The client sets `currency = ""` (`BmlValidateClient.kt:74-75`). Important for USD-vs-MVR transfer routing — currency must be sourced elsewhere (e.g. MIB's own lookup, see [MIB transfer docs](../mibapi/08-transfer.md)).
### Failure
```json
+37
View File
@@ -77,6 +77,16 @@ Expected response: `{ "code": 0, "payload": [...] }`
The OTP is a standard TOTP (RFC 6238, SHA-1, 30-second window, 6 digits) derived from the stored BML authenticator seed.
### Failure Handling
Each of the three POSTs validates the server's `code` field and throws on mismatch (`BmlTapToPayClient.kt:37, 42, 47`). The exception message is the server's `message` field:
| Step | Expected code | Throws if |
|---|---|---|
| 1a | `0` (rare) or `99` | code is neither — `message` propagated |
| 1b | `22` | code is not `22``message` propagated |
| 1c | `0` | code is not `0``message` propagated |
### Token Response
```json
@@ -239,6 +249,33 @@ All APDU responses use BER-TLV encoding. Tags are 1 or 2 bytes (hex string). Len
---
## Lifecycle
The HCE service (`BmlHostCardEmulatorService`) keeps a single active `BmlWalletToken` in a volatile companion-object field. Tokens are single-use — exactly one tap consumes one token.
### Companion API
```kotlin
BmlHostCardEmulatorService.setToken(token: BmlWalletToken)
BmlHostCardEmulatorService.clearToken()
BmlHostCardEmulatorService.onTransactionComplete: (success: Boolean) -> Unit
```
| Call | When |
|---|---|
| `setToken(token)` | After fetching a token, before prompting the user to tap |
| `clearToken()` | After the tap completes, when the prompt is dismissed, or on error |
| `onTransactionComplete(true)` | Fired immediately after the `READ RECORD` response (`BmlHostCardEmulatorService.kt:78`) |
| `onTransactionComplete(false)` | Fired from `onDeactivated` if GPO was never seen (`BmlHostCardEmulatorService.kt:35-38`) — i.e. the reader walked away before completing the EMV exchange |
### State Rules
- A token MUST be installed via `setToken` before the user taps. With no active token, `SELECT PPSE` launches `BmlTapToPayActivity` (a redirector to `MainActivity`) and returns `6F00`.
- The service tracks `gpoSent` to distinguish "user pulled the phone away" from a successful read. A successful `handleReadRecord` resets `gpoSent` to `false` via `onDeactivated` after the success callback has already fired.
- `BmlTapToPayActivity` provides the "Tap your phone…" prompt UI. The activity is responsible for calling `setToken` before showing the prompt and `clearToken` when dismissed.
---
## Prerequisites
- Valid `access_token` from [OAuth Token Exchange](03-oauth-token.md)
+4 -2
View File
@@ -150,7 +150,7 @@ POST https://www.bankofmaldives.com.mv/internetbanking/api/mobile/walletpayments
Expected response: `{ "success": true, "code": 99 }` (OTP required)
> **Note:** This step may be skipped. The app proceeds directly to Step 2b if the gateway already indicates OTP is required.
> **When this step is used:** the client only calls `preInitiatePayment` for **gateway QRs** — QR URLs that begin with `https://pay.bml.com.mv/app/` (`TransferFragment.kt:349, 1419-1423`). For PayMV-native static QRs (`QRS`), Step 2a is skipped and the flow starts at Step 2b.
### Step 2b — Request OTP Channel
@@ -195,6 +195,8 @@ Expected response:
}
```
> **Currency fallback:** if the server's `payload.currency` is blank, the client falls back to the `currency` value sent in the request (`BmlQrPayClient.kt:148`). The same applies to `merchant` and `amount` at the UI layer.
On failure:
```json
@@ -240,4 +242,4 @@ The OTP is a standard TOTP (RFC 6238, SHA-1, 30-second window, 6 digits) derived
---
[← Tap-to-Pay](12-tap-to-pay.md)
[← Tap-to-Pay](12-tap-to-pay.md) &nbsp;&nbsp;&nbsp; **Next →** [Notifications](14-notifications.md)
+171
View File
@@ -0,0 +1,171 @@
# Notifications
In-app notifications (transaction alerts, security events, marketing) are served from a separate host. Notifications are fetched in pages and can be bulk-marked as read.
The polling service runs in the background and posts an Android system notification for each unseen item (`service/NotificationPollingService.kt:64`).
---
## Base URL
```
https://app.bankofmaldives.com.mv/api/v2
```
Distinct from the main `internetbanking/api/mobile` host, but uses the same Bearer token.
---
## Prerequisites
- Valid `access_token` from [OAuth Token Exchange](03-oauth-token.md)
---
## Fetch Notifications
```
GET https://app.bankofmaldives.com.mv/api/v2/notifications?group={group}&page={page}
```
### Query Parameters
| Parameter | Type | Description |
|---|---|---|
| `group` | `string` | Filter by group — `ALL` (default), or a specific group (e.g. `ALERTS`) |
| `page` | `int` | 1-based page number |
### Headers
| Header | Value |
|---|---|
| `Authorization` | `Bearer <access_token>` |
| `User-Agent` | `bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})` |
| `x-app-version` | `2.1.44.348` |
```bash
curl --request GET \
--url 'https://app.bankofmaldives.com.mv/api/v2/notifications?group=ALL&page=1' \
--header 'Authorization: Bearer <access_token>' \
--header 'User-Agent: bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})' \
--header 'x-app-version: 2.1.44.348'
```
### Response
```json
{
"success": true,
"total": 137,
"payload": [
{
"id": "abc123",
"group": "ALERTS",
"type": "TRANSACTION",
"title": "Transaction Alert",
"message": "MVR 100.00 debited from 7730000000001",
"created_at": "2026-05-16T15:10:25",
"is_read": false,
"data": {
"account_number": "7730000000001",
"amount": "100.00",
"currency": "MVR",
"reference": "FT20260516123456"
}
}
]
}
```
### Top-level Fields
| Field | Type | Description |
|---|---|---|
| `success` | `bool` | `true` on success |
| `total` | `int` | Total notification count across all pages |
| `payload` | `array` | List of notifications for this page |
### Notification Object
| Field | Type | Description |
|---|---|---|
| `id` | `string` | Unique notification ID |
| `group` | `string` | Logical grouping (e.g. `ALERTS`) — also the value passed back to the `group` filter |
| `type` | `string` | Sub-type within the group (e.g. `TRANSACTION`) |
| `title` | `string` | Short headline |
| `message` | `string` | Body text |
| `created_at` | `string` | Timestamp — `yyyy-MM-dd'T'HH:mm:ss` (no timezone) |
| `is_read` | `bool` | Read state |
| `data` | `object?` | Optional structured detail payload — fields vary by type |
### `data` Field Flattening
Where present, the `data` object is flattened into the notification's detail view as key-value rows. The client transforms each `data` key with underscore → space and title-case (`BmlNotificationsClient.kt:93-94`):
```
"account_number" → "Account Number"
"reference" → "Reference"
```
Three synthetic rows are prepended:
| Row | Value |
|---|---|
| `Bank` | `BML` |
| `Group` | from `group` field |
| `Type` | from `type` field |
---
## Mark All Read
```
PUT https://app.bankofmaldives.com.mv/api/v2/notifications/read
```
### Headers
| Header | Value |
|---|---|
| `Authorization` | `Bearer <access_token>` |
| `User-Agent` | `bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})` |
| `x-app-version` | `2.1.44.348` |
| `accept` | `application/json` |
| `Content-Type` | `application/json` |
### Request Body
```json
{
"all": true
}
```
```bash
curl --request PUT \
--url 'https://app.bankofmaldives.com.mv/api/v2/notifications/read' \
--header 'Authorization: Bearer <access_token>' \
--header 'User-Agent: bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})' \
--header 'x-app-version: 2.1.44.348' \
--header 'accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"all":true}'
```
### Response
The client treats any 2xx response as success — the response body is discarded.
---
## Polling
`service/NotificationPollingService.kt:64` polls page 1 of every active BML session at a fixed interval, diffs the result against a local cache, and posts an Android system notification for each new item.
---
&nbsp;
---
[← QR Payment](13-qr-payment.md) &nbsp;&nbsp;&nbsp; **Next →** [Card Freeze](15-card-freeze.md)
+121
View File
@@ -0,0 +1,121 @@
# Card Freeze / Unfreeze
Lock or unlock a BML card to block / allow new authorisations. The same endpoint handles both actions, distinguished by the `action` field.
---
## Endpoint
```
POST https://www.bankofmaldives.com.mv/internetbanking/api/mobile/services/card/freeze
```
---
## Prerequisites
- Valid `access_token` from [OAuth Token Exchange](03-oauth-token.md)
- `cardId` is the **internal card UUID** (`BankAccount.internalId`, sourced from the `id` field of a `Card` entry in the [dashboard](04-dashboard.md) response) — NOT the displayed 16-digit card number
---
## Request
### Body
**Content-Type:** `application/json`
```json
{
"card": "<internalId>",
"action": "freeze"
}
```
| Field | Type | Notes |
|---|---|---|
| `card` | `string` | Internal card UUID — the `id` from the dashboard Card object |
| `action` | `string` | `"freeze"` to lock the card; `"unfreeze"` to unlock |
### Headers
| Header | Value |
|---|---|
| `Authorization` | `Bearer <access_token>` |
| `User-Agent` | `bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})` |
| `x-app-version` | `2.1.44.348` |
| `accept` | `application/json` |
| `Content-Type` | `application/json` |
```bash
curl --request POST \
--url 'https://www.bankofmaldives.com.mv/internetbanking/api/mobile/services/card/freeze' \
--header 'Authorization: Bearer <access_token>' \
--header 'User-Agent: bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})' \
--header 'x-app-version: 2.1.44.348' \
--header 'accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"card":"abc-123-def-456","action":"freeze"}'
```
---
## Response
```json
{
"success": true,
"code": 0,
"payload": "Card frozen successfully",
"message": ""
}
```
### Fields
| Field | Type | Description |
|---|---|---|
| `success` | `bool` | `true` on success |
| `code` | `int` | `0` on success; non-zero indicates an error |
| `payload` | `string` | Human-readable confirmation text (may be blank) |
| `message` | `string` | Fallback error/info text |
Success is determined by **both** `success == true` AND `code == 0` (`BmlCardClient.kt:46`). Either condition alone is not enough.
### Display Message
The client prefers `payload` for the confirmation text and falls back to `message` when `payload` is blank (`BmlCardClient.kt:49`):
```
payload (if non-blank) → fallback message
```
---
## Failure
```json
{
"success": false,
"code": 1,
"payload": "",
"message": "Card cannot be frozen at this time"
}
```
Returned with HTTP `200` for application-level errors. The `message` (or `payload`) field contains the reason.
### Server / Auth Errors
| HTTP Code | Behaviour |
|---|---|
| `401` / `419` | Throws `AuthExpiredException` — refresh the token or re-login |
| `5xx` | Throws `BankServerException("BML")` — server-side failure, retry |
---
&nbsp;
---
[← Notifications](14-notifications.md)
+3
View File
@@ -25,6 +25,7 @@ The login process is stateful and must be executed in order:
| Web login / OAuth | `https://www.bankofmaldives.com.mv/internetbanking` |
| REST API (authenticated) | `https://www.bankofmaldives.com.mv/internetbanking/api/mobile` |
| Foreign limits API | `https://app.bankofmaldives.com.mv/api/v2` |
| Notifications API | `https://app.bankofmaldives.com.mv/api/v2` |
---
@@ -190,6 +191,8 @@ The access token expires after `expires_in` seconds (typically 3600). On a `401`
| 11 | [Foreign Limits](11-foreign-limits.md) | USD foreign transaction limits by card and channel |
| 12 | [Tap-to-Pay](12-tap-to-pay.md) | NFC HCE contactless payment — token fetch and EMV APDU exchange |
| 13 | [QR Payment](13-qr-payment.md) | PayMV QR payment — QR formats, payrequest lookup, 3-step pay flow |
| 14 | [Notifications](14-notifications.md) | Notifications list, mark-as-read, and polling |
| 15 | [Card Freeze](15-card-freeze.md) | Freeze / unfreeze a BML card |
---