# Transaction History Fetch a paginated list of transactions for the active subscriber session. --- ## Endpoint ``` POST https://superapp.ooredoo.mv/api/mfaisaa-bff/mfino/v1.1/web/transactionInquiry/fetchSummary ``` Requires an active session (i.e. a valid [`loginExchangeKey`](02-login.md#step-2-domobilelogin)) obtained from `doMobileLogin`. Sessions expire after `mobileLoginSessionTimeout` seconds (240s) — see [Session expiry](#session-expiry) below. --- ## Request **Content-Type:** `application/x-www-form-urlencoded` | Field | Value | |---|---| | `role` | `RETAIL_SUBSCRIBER` (constant) | | `channel` | `SubscriberApp` — **not** `C03` as in login | | `loginExchangeKey` | From the login response | | `mdnId` | `` — same routine as `mdnId` in login | | `formData` | JSON object (see below), [html-safe-escaped](01-encryption.md#html-safe-gson--escape) | | `rndValue` | [Anti-replay nonce](01-encryption.md#anti-replay-envelope-rndvalue--csvalue) | | `csValue` | [Adler32 integrity check](01-encryption.md#anti-replay-envelope-rndvalue--csvalue) | ### `formData` JSON ```json { "actorRole": "RETAIL_SUBSCRIBER", "actorRoleId": "", "fromDate": "", "mdnId": "", "pageNo": "1", "recordSize": "70", "toDate": "", "transactionType": "" } ``` - `actorRoleId` comes from `suscriberId` at the top level of `doMobileLogin`'s success body — see [02-login.md](02-login.md#step-2-domobilelogin). It also appears as `pocketDetails[0].roleId` in the same response. - The inner `mdnId` is independently encrypted from the outer `mdnId` — same plaintext, different ciphertext (OAEP random padding). - `fromDate` / `toDate` are empty strings in the official app — the server returns all available history. --- ## curl Example ```bash # Requires a valid loginExchangeKey + suscriberId from a fresh login call python tmp/mfaisa_history.py 1 ``` See `tmp/mfaisa_history.py` for the full Python reference (it does the login, captures the session, then calls fetchSummary). --- ## Response ```json { "transactionInquiryDTOList": [ { "requestId": "", "referenceId": "", "sourceMDN": "-DT Pocket-", "sourcePocketId":"", "actorRoleType": "RETAIL_SUBSCRIBER", "actorRoleId": "", "commodityType": "WALLET", "channel": "SubscriberApp", "transactionAmount": { "amount": 1, "currencyCode": "MVR" }, "userStatus": "CONFIRMED", "trnStage": "AUTO_REVERSED", "trnType": "CASH_IN", "status": "FAILED", "trnDate": "2026-06-13 13:04:19", "narrationString": "Load Money", "typeSummaryString": "[{\"Transaction Type\":\"Load Money\",\"Deposit Pocket\":\"DT Pocket\",\"Reference\":\"\"}]", "errorCode": "INT_002", "errorDesc": "QR_CODE_GENERATED", "resolutionDetails": "Please reconcile with the payment gateway..." }, "..." ] } ``` Key fields used by Thijooree: | Field | Maps to `BankTransaction` | |---|---| | `trnDate` | `date` (already in `YYYY-MM-DD HH:mm:ss` form) | | `narrationString` | `description` (suffixed with `· Failed` when `status == "FAILED"`) | | `transactionAmount.amount` | `amount` (signed — see direction rule below) | | `transactionAmount.currencyCode` | `currency` | | `referenceId` (fallback `requestId`) | `id` + `reference` | | `typeSummaryString` → `Merchant Name` / `Receiver Name` / `Sender Name` | `counterpartyName` | | `sourceMDN` (e.g. `"-DT Pocket-"`) | `counterpartyName` fallback (first segment before `-`) | ### Debit / credit direction The response does not include a signed amount or direction flag. Direction is inferred from `trnType`: | `trnType` | Direction | |---|---| | `CASH_IN`, `RECEIVE_MONEY`, `*_IN` | credit (positive amount) | | everything else (`PURCHASE`, `TRANSFER`, …) | debit (negative amount) | ### Pagination The server does not return a `total` field. Thijooree treats "received a full `recordSize` (= 70) records" as the only signal that further pages may exist; the next call uses `pageNo = pageNo + 1`. Once a page comes back with fewer than 70 records, no more pages are fetched. ### Session expiry When the 240-second session lapses, the server still returns HTTP 200 but the body is its standard error envelope: ```json [ { "success": false, "message": "validation errors", "error": [ { "objectName": "LoginLog", "attributeName": "LoginLog", "attributeValue": "SESSION_EXPIRED", "errorCode": "SESSION_EXPIRED", "errorMessage": "SESSION_EXPIRED" } ] } ] ``` `MfaisaHistoryClient` parses this into `MfaisaSessionExpiredException`. Callers (`HistoryFetcher`, `TransferHistoryFragment`) catch it, call `BasedBankApp.refreshMfaisaSession(loginId)` to re-login transparently, and retry the same page once. ---   --- > **Next →** [Transfer Money](04-transfer.md) | **← Back to** [Login](02-login.md) | [README](README.md)