update mib api docs

This commit is contained in:
2026-10-23 05:38:33 +05:00
parent 740030e061
commit 2764c6e452
10 changed files with 662 additions and 658 deletions
+209 -149
View File
@@ -2,197 +2,244 @@
Two-step process: look up the recipient to validate the account and get the holder name, then execute the transfer.
All endpoints are on the WebView subdomain. See [README](README.md) for cookie and AJAX header format.
```
Referer: https://faisamobilex-wv.mib.com.mv/transfer/quick
```
All endpoints are on the encrypted API (`sfunc=n`, session key). See [README](README.md) for the request format. The source account must belong to the **currently selected** profile — call `P47` for its profile first (see [03-accounts.md](03-accounts.md)).
---
## Step 1 — Account Lookup
## Step 1 — Account Lookup — `routePath: B40`
The lookup endpoint depends on the format of the input:
One route resolves every supported input:
| Input format | Endpoint | Body field |
| Input format | Example | Resolves to |
|---|---|---|
| Starts with `7`, exactly 13 digits | `AjaxAlias/getIPSAccount` | `benefAccount` |
| Starts with `9`, exactly 17 digits | `ajaxBeneficiary/getAccountName` | `accountNo` |
| Starts with `7` or `9`, exactly 7 digits | `AjaxAlias/getAlias` | `aliasName` |
| Starts with `A` followed by 6 digits | `AjaxAlias/getAlias` | `aliasName` |
| Contains `@` (email) | `AjaxAlias/getAlias` | `aliasName` |
| Starts with `7`, exactly 13 digits | `7700000000000` | BML / local bank account |
| Starts with `9`, exactly 17 digits | `90100000000000000` | MIB account |
| Starts with `7` or `9`, exactly 7 digits | `9600001` | Favara mobile alias |
| `A` followed by 6 digits | `A000001` | Favara National ID alias |
| Contains `@` | `user@example.com` | Favara email alias |
---
### 1a. IPS Account — BML / local bank (13 digits, starts with `7`)
```
POST https://faisamobilex-wv.mib.com.mv/AjaxAlias/getIPSAccount
```
Body: `benefAccount=7700000000000`
**Response**:
**Request**:
```json
{
"success": true,
"responseCode": "2",
"accountName": "ACCOUNT HOLDER NAME",
"bankBic": "MALBMVMV"
}
```
- `accountName` — account holder name
- `bankBic` — bank BIC (e.g. `MALBMVMV` for BML)
- Account number is the input itself — not returned in response
Use `bankNo=3` and `transferLocal` for the transfer.
> **USD cross-bank accounts**: `getIPSAccount` only succeeds for **MVR** cross-bank accounts. A 13-digit `7…` account that is denominated in USD returns `success: false` here and cannot be resolved via IPS at all. The client hardcodes `currency = "MVR"` for IPS results (`MibTransferClient.kt:135-137`). For USD BML→MIB transfers the user must first save a BML contact (see Notes below).
---
### 1b. MIB Internal Account (17 digits, starts with `9`)
```
POST https://faisamobilex-wv.mib.com.mv/ajaxBeneficiary/getAccountName
```
Body: `accountNo=90100000000000000`
**Response**:
```json
{
"success": true,
"accountName": "ACCOUNT HOLDER NAME",
"currencyCode": "462"
}
```
- `accountName` may be at root level or inside a `data` object — check both (`MibTransferClient.kt:160-161`)
- `currencyCode` may also be at root level or inside `data` (`MibTransferClient.kt:162-163`). `"462"` = MVR, `"840"` = USD. The client maps this into `MibIpsAccountInfo.currency` ∈ `{"MVR", "USD", ""}` — this is the **MIB→MIB USD detection** fix from commit `16fd909`.
- Bank is always MIB (`MADVMVMV`)
Use `bankNo=2` and `transferInternal` for the transfer.
---
### 1c. Favara Alias — shortcodes, A-IDs, emails
```
POST https://faisamobilex-wv.mib.com.mv/AjaxAlias/getAlias
```
Body: `aliasName=<alias>`
**Response**:
```json
{
"success": true,
"responseCode": "2",
"sfunc": "n",
"xxid": "<session xxid>",
"data": {
"BfyNm": "Account Holder Name",
"CdtrAcct": {
"Acct": "90100000000000000",
"FinInstnId": "MADVMVMV"
}
"search": "7700000000000",
"nonce": "<computed nonce>",
"appId": "<appId>",
"sodium": "<random 20-bit int>",
"routePath": "B40",
"xxid": "<session xxid>"
}
}
```
- `BfyNm` — beneficiary name (trim whitespace)
- `CdtrAcct.Acct` — resolved account number to use for the transfer
- `CdtrAcct.FinInstnId` — bank BIC (`MADVMVMV` = MIB, `MALBMVMV` = BML)
### Input Rules
Use `bankNo=2` (MIB) or `3` (BML/local) depending on `FinInstnId`, and the matching transfer endpoint.
- **Mobile aliases** must be the bare 7 digits. `+960 9600001` and `+9609600001` return no match.
- **National ID aliases** need an uppercase `A` — `a000001` returns no match, `A000001` resolves. The client uppercases the prefix before sending (`MibTransferClient.kt`).
- Partial input (e.g. `9600`) returns an empty `data` array.
---
### Lookup Errors
All three lookup endpoints return `success: false` with a human-readable `reasonText` on failure:
```json
{
"success": false,
"reasonText": "Account not found"
}
```
Always show `reasonText` directly to the user.
---
## Step 2 — Execute Transfer
Two endpoints depending on the destination bank:
| `bankNo` | Endpoint | Destination |
|---|---|---|
| `2` | `ajaxTransfer/transferInternal` | MIB internal account |
| `3` | `ajaxTransfer/transferLocal` | BML or other local bank |
```
POST https://faisamobilex-wv.mib.com.mv/ajaxTransfer/transferInternal
POST https://faisamobilex-wv.mib.com.mv/ajaxTransfer/transferLocal
```
### Request Body (form-urlencoded)
| Field | Description |
|---|---|
| `benefName` | Recipient name (from lookup) |
| `benefNo` | `0` (not a saved contact) |
| `fromAccountNo` | Source account number |
| `benefAccountNo` | Destination account number |
| `transferCy` | Currency numeric code (`"462"` = MVR, `"840"` = USD) |
| `benefCurrencyCode` | Same as `transferCy` |
| `amount` | Amount as string (e.g. `"100.00"`) |
| `bankNo` | `2` = MIB internal, `3` = local/BML |
| `purpose` | Transfer purpose; send `"-"` if blank |
| `otp` | OTP from the user |
| `otpType` | `"3"` (SMS/authenticator OTP) |
### Response — Success
### Response
**BML account**:
```json
{
"success": true,
"data": [
{
"trxId": "TRX20260516001",
"date": "2026-05-16 15:10:25"
"benefName": "ACCOUNT HOLDER NAME",
"benefAccount": "7700000000000",
"bankCode": "MALBMVMV",
"benefBankName": "Bank of Maldives"
}
]
}
```
**MIB account**:
```json
{
"success": true,
"data": [
{
"benefName": "ACCOUNT HOLDER NAME",
"benefAccount": "90100000000000000",
"bankCode": "MIB",
"benefBankName": "MIB",
"transferCy": "462",
"transferCyDesc": "MVR"
}
]
}
```
**Favara alias** (resolving to an MIB account):
```json
{
"success": true,
"data": [
{
"benefName": "Account Holder Name ",
"benefAccount": "90100000000000000",
"bankCode": "MADVMVMV",
"benefBankName": "Maldives Islamic Bank PLC."
}
]
}
```
| Field | Description |
|---|---|
| `benefName` | Account holder name — trim whitespace |
| `benefAccount` | Resolved account number to use for the transfer |
| `bankCode` | `"MIB"` or a bank BIC (`MADVMVMV` = MIB, `MALBMVMV` = BML). Normalize `"MIB"` to `MADVMVMV`. |
| `benefBankName` | Bank display name |
| `transferCy` / `transferCyDesc` | Account currency — present for MIB account lookups only |
### Lookup Errors
No match returns `success: true` with an empty `data` array:
```json
{ "success": true, "data": [] }
```
Show "account not found" in that case.
### Currency
| Lookup | Currency |
|---|---|
| MIB account | From `transferCyDesc` (`"MVR"` / `"USD"`) |
| Favara alias → MIB | Not returned — unknown |
| BML / local | `"MVR"` — cross-bank lookups only resolve MVR accounts |
> **USD cross-bank accounts**: a BML account denominated in USD cannot be resolved here. For USD BML→MIB transfers the user must first save a BML contact (see Notes below).
---
## Step 2 — Execute Transfer
Two routes depending on the destination bank:
| `bankNo` | `routePath` | Destination |
|---|---|---|
| `2` | `T50` | MIB internal account |
| `3` | `T51` | BML or other local bank (via Favara) |
**Request**:
```json
{
"sfunc": "n",
"xxid": "<session xxid>",
"data": {
"benefName": "ACCOUNT HOLDER NAME",
"benefNo": "0",
"fromAccountNo": "90101000000001000",
"benefAccountNo": "7700000000000",
"transferCy": "462",
"benefCurrencyCode": "462",
"amount": "100.00",
"bankNo": "3",
"purpose": "",
"otp": "123456",
"otpType": "3",
"nonce": "<computed nonce>",
"appId": "<appId>",
"sodium": "<random 20-bit int>",
"routePath": "T51",
"xxid": "<session xxid>"
}
}
```
| Field | Description |
|---|---|
| `benefName` | Recipient name (from lookup) |
| `benefNo` | `"0"` (not a saved contact) |
| `fromAccountNo` | Source account number |
| `benefAccountNo` | Destination account number |
| `transferCy` | Currency numeric code (`"462"` = MVR, `"840"` = USD) |
| `benefCurrencyCode` | Same as `transferCy` |
| `amount` | Amount as string (e.g. `"100.00"`, `".01"`) |
| `bankNo` | `"2"` = MIB internal, `"3"` = local/BML |
| `purpose` | Transfer remarks; may be empty |
| `otp` | Current TOTP code |
| `otpType` | `"3"` (authenticator OTP) |
### Response — Success
**`T50`** (internal):
```json
{
"success": true,
"responseCode": "2",
"reasonCode": "2011",
"reasonText": "Internal transfer success",
"data": [
{ "date": "2026-05-16 15:10:25", "trxId": "97999863", "availableBalance": "37.41" }
],
"accountBalance": [ ... ]
}
```
**`T51`** (local):
```json
{
"success": true,
"responseCode": "2",
"reasonCode": "2011",
"reasonText": "Local transfer completed successfully via Favara",
"data": [
{ "date": "2026-05-16 15:10:25", "trxId": "817054125" }
]
}
```
| Field | Description |
|---|---|
| `trxId` | Transaction ID |
| `date` | Completion timestamp |
| `availableBalance` | `T50` only — source account balance after the transfer |
| `accountBalance` | `T50` only — refreshed balances for the selected profile (same shape as in [03-accounts.md](03-accounts.md)) |
### Response — Failure
Failures return HTTP `400` with an encrypted body:
```json
{
"success": false,
"reasonText": "Insufficient balance"
"responseCode": "1",
"reasonCode": "213",
"reasonText": "Invalid OTP",
"data": [ { "otpId": "50487016" } ]
}
```
`reasonText` contains the error reason. On HTTP `419`, the session has expired — re-login required.
| `reasonCode` | `reasonText` | Meaning |
|---|---|---|
| `213` | `Invalid OTP` | Wrong or stale OTP |
| `707` | `That OTP is already used!` | The OTP was already accepted for an earlier request |
| `201` | `Transaction currency does not match From Account currency!` | `transferCy` doesn't match the source account |
Show `reasonText` to the user.
### OTP Retry
On `213` or `707` the client waits for the next 30-second TOTP window (plus 1 second for clock skew), generates a new code and resends the transfer **once**. A second failure of any kind is shown to the user (`MibTransferHandler.kt`).
---
## Transfer Type Summary
| Recipient | Lookup endpoint | `bankNo` | Transfer endpoint |
| Recipient | Lookup | `bankNo` | Transfer |
|---|---|---|---|
| MIB (17-digit `9…`) | `getAccountName` | `2` | `transferInternal` |
| BML (13-digit `7…`) | `getIPSAccount` | `3` | `transferLocal` |
| Favara alias → MIB | `getAlias` | `2` | `transferInternal` |
| Favara alias → BML | `getAlias` | `3` | `transferLocal` |
| MIB (17-digit `9…`) | `B40` | `2` | `T50` |
| BML (13-digit `7…`) | `B40` | `3` | `T51` |
| Favara alias → MIB | `B40` | `2` | `T50` |
| Favara alias → BML | `B40` | `3` | `T51` |
---
@@ -205,23 +252,36 @@ POST https://faisamobilex-wv.mib.com.mv/ajaxTransfer/transferLocal
---
## Other Transfer-Screen Routes
Called by the official app when opening the transfer screen. Not consumed by thijooree.
| `routePath` | Request | Returns |
|---|---|---|
| `T63` | — | Currencies with rates (`numericCode`, `code`, `name`, `rate`) |
| `T66` | `currencyCode` | Sell rate for a currency (`sellRate`) |
| `T70` | — | Upload settings (`numFiles`, `fileSize`) |
| `T71` | optional `transferCy` | AML thresholds (`eddAmount`, `cddAmount`, `currencyCode`) |
---
## `MibIpsAccountInfo` (client model)
All three lookups return this unified structure (`MibModels.kt:42-47`):
`B40` lookups are mapped into this structure (`MibModels.kt`):
| Field | Description |
|---|---|
| `accountName` | Account holder name (trimmed) |
| `accountNumber` | Resolved account number |
| `bankId` | Bank BIC (`MADVMVMV` = MIB, `MALBMVMV` = BML, etc.) |
| `currency` | `"MVR"`, `"USD"`, or `""` (unknown). Populated from `currencyCode` for MIB internal lookups; hardcoded `"MVR"` for IPS lookups; default `""` for alias lookups. |
| `currency` | `"MVR"`, `"USD"`, or `""` (unknown) — see Currency above |
---
## Notes
- **BML → MIB USD transfers** require a saved BML contact first. Because `getIPSAccount` rejects USD accounts (`success: false`), the app cannot validate the BML USD account number directly. The workaround in `TransferFragment.kt` is to call `MibContactsClient.createContact` (see [09-contacts.md](09-contacts.md)) to auto-add the BML account as a beneficiary, then transfer to that beneficiary. Introduced in commit `16fd909`.
- **Session expiry**: HTTP `419` on either lookup or transfer means the session expired. See [README](README.md) for the unified expiry detection rules.
- **BML → MIB USD transfers** require a saved BML contact first. Because USD BML accounts can't be resolved via `B40`, the app cannot validate the account number directly. The workaround in `TransferFragment.kt` is to add the BML account as a beneficiary (see [09-contacts.md](09-contacts.md)), then transfer to that beneficiary.
- **Session expiry**: see [README](README.md) for the unified expiry detection rules.
---