Files
thijooree/docs/mfaisaapi
shihaam 43f3cca2aa
Auto Tag on Version Change / check-version (push) Failing after 13m41s
ooredoo mfaisa
2026-06-27 14:25:46 +05:00
..
2026-06-27 14:25:46 +05:00
2026-06-27 14:25:46 +05:00
2026-06-27 14:25:46 +05:00
2026-06-27 14:25:46 +05:00
2026-06-27 14:25:46 +05:00

Ooredoo M-Faisa API Documentation

Reverse-engineered from traffic captures and live Frida hooks of the official Ooredoo SuperApp (com.mventus.ooredoomaldives).

Play Store


Overview

M-Faisa is Ooredoo Maldives' mobile wallet, exposed via a JSON/form-encoded REST API on superapp.ooredoo.mv. The wire format is unusual in three ways:

  1. Field-level RSA encryption. The MSISDN (mdnId, mobileNumber, userName, initiatingMDN, identifier) and the mPIN (mPin) are each encrypted with a different RSA public key before being placed in the request body. See 01-encryption.md.
  2. Anti-replay envelope. Every session-scoped form-encoded POST carries an rndValue (RSA-encrypted timestamp) and a csValue (Adler32 of formDataJson + nonceStr). See 01-encryption.md → rndValue / csValue.
  3. Cloudflare-fingerprinted header order. A User-Agent header sent explicitly (instead of letting OkHttp add it last) returns HTTP 400.

Base URL

https://superapp.ooredoo.mv

All M-Faisa endpoints are mounted at /api/mfaisaa-bff/mfino/v1.1/web/....


Authentication Model

Value How obtained How used
loginExchangeKey Returned by doMobileLogin on success Held in memory only; identifies the session
Session timeout mobileLoginSessionTimeout field, default 240 seconds After expiry the user must re-login (no refresh-token flow)

Because there is no refresh, Thijooree re-runs fetchSubscriberByMDN + doMobileLogin on every cold-start refresh, using the saved msisdn + mPIN from CredentialStore. The SESSION_EXPIRED error envelope is also caught at runtime and the session is silently re-established before retrying the failed request.


Common Request Headers

Content-Type: application/json; charset=UTF-8           (fetchSubscriberByMDN)
Content-Type: application/x-www-form-urlencoded         (every other endpoint)
Host: superapp.ooredoo.mv
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.12.0

Do NOT set User-Agent in code. Cloudflare fingerprints the header order; an explicit User-Agent header is pushed to the front of the request and the request is rejected with HTTP 400. Let OkHttp's BridgeInterceptor add the default okhttp/4.12.0 at the end.


Login Flow

Client                                                Server
  |                                                     |
  |  POST /fetchSubscriberByMDN                         |
  |  { mdnId: encryptMobile(msisdn) }                   |
  |---------------------------------------------------->|
  |  { success, subscriberRegistered, kycStatus, ... }  |
  |<----------------------------------------------------|
  |                                                     |
  |  (abort if subscriberRegistered=false               |
  |   or kycStatus != "Full KYC")                       |
  |                                                     |
  |  POST /doMobileLogin                                |
  |  channel=C03                                        |
  |  formData={ deviceGeoInfo, mPin: encryptPin(mpin),  |
  |             mobileNumber: ..., userName: ...,       |
  |             role:"RETAIL_SUBSCRIBER",               |
  |             tenantCode:"ooredoo" }                  |
  |  formDataCs=null                                    |
  |---------------------------------------------------->|
  |  { success, loginExchangeKey, pocketDetails: [...]} |
  |<----------------------------------------------------|

Documents

# File Description
1 Encryption & Anti-Replay Mobile / mPin RSA, the rndValue + csValue envelope, the Gson = quirk, key-extraction story
2 Login Subscriber lookup + mPIN login
3 Transaction History Paginated history per session
4 Transfer Money Three-step wallet-to-wallet send: recipient lookup → initiate (server SMSes OTP) → confirm

 


Next → Encryption & Anti-Replay