# Account Lookup & Transfer 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 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 — `routePath: B40` One route resolves every supported input: | Input format | Example | Resolves to | |---|---|---| | 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 | **Request**: ```json { "sfunc": "n", "xxid": "", "data": { "search": "7700000000000", "nonce": "", "appId": "", "sodium": "", "routePath": "B40", "xxid": "" } } ``` ### Input Rules - **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. ### Response **BML account**: ```json { "success": true, "data": [ { "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": "", "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": "", "appId": "", "sodium": "", "routePath": "T51", "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, "responseCode": "1", "reasonCode": "213", "reasonText": "Invalid OTP", "data": [ { "otpId": "50487016" } ] } ``` | `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 | `bankNo` | Transfer | |---|---|---|---| | 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` | --- ## Currency Codes | `transferCy` | Currency | |---|---| | `"462"` | MVR (Maldivian Rufiyaa) | | `"840"` | USD | --- ## 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) `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) — see Currency above | --- ## Notes - **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. ---   --- [← Personal Profile](07-profile.md)     **Next →** [Contacts](09-contacts.md)