# OTP / 2FA Verification Submit a TOTP code to complete login when `two_factor_required` was `true` in the [login response](01-login.md). --- ## Endpoint ``` POST https://fahipay.mv/api/app/otp/ ``` --- ## Prerequisites - Completed the [login step](01-login.md) and received `two_factor_required: true` - The `__Secure-sess` session cookie from the login response must be present - A valid TOTP code from the user's authenticator app --- ## Request **Content-Type:** `multipart/form-data` ### Form Fields | Field | Value | Notes | |---|---|---| | `code` | `123456` | 6-digit TOTP code from the user's authenticator app | | `channel` | `totp` | Always `totp` | | `action` | `login` | Always `login` for the login flow | | `grant_type` | `auth_id` | Always `auth_id` | | `lang` | `en` | Always `en` | | `version` | `2.0.0` | App version string | | `platform` | `BasedBank` | Client identifier (`app` in the original Fahipay app) | | `device[available]` | `true` | Same device fields as login — must match | | `device[platform]` | `Android` | | | `device[uuid]` | `a1b2c3d4e5f60718` | Must be the **same UUID** used in the login request | | `device[model]` | `22101320I` | | | `device[manufacturer]` | `Xiaomi` | | | `device[isVirtual]` | `false` | | | `device[serial]` | `unknown` | | > The `device[uuid]` must be identical to the one sent in the login request. The server uses this to tie the OTP challenge to the login attempt. --- ## curl Example ```bash curl --request POST \ --url https://fahipay.mv/api/app/otp/ \ --compressed \ --header 'Cookie: __Secure-sess=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ --header 'accept: application/json' \ --header 'accept-encoding: gzip, deflate, br' \ --header 'connection: keep-alive' \ --header 'user-agent: Mozilla/5.0 (Linux; Android 14; 22101320I Build/AP2A.240905.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.70 Mobile Safari/537.36' \ --form 'code=123456' \ --form 'channel=totp' \ --form 'action=login' \ --form 'grant_type=auth_id' \ --form 'lang=en' \ --form 'version=2.0.0' \ --form 'platform=BasedBank' \ --form 'device[available]=true' \ --form 'device[platform]=Android' \ --form 'device[uuid]=a1b2c3d4e5f60718' \ --form 'device[model]=22101320I' \ --form 'device[manufacturer]=Xiaomi' \ --form 'device[isVirtual]=false' \ --form 'device[serial]=unknown' ``` --- ## Responses ### Success ```json { "title": "Success", "authID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "msg": "Code verification successful", "type": "success" } ``` | Field | Type | Description | |---|---|---| | `authID` | `string` | 40-char hex token — use as `authid` header for all subsequent requests | | `type` | `string` | `"success"` | | `msg` | `string` | Human-readable confirmation | --- ### Failure — Wrong code ```json { "title": "Error", "msg": "Invalid OTP code", "type": "error" } ``` --- ### Failure — Expired / session mismatch ```json { "title": "Error", "msg": "Session expired. Please login again.", "type": "error" } ``` If the session cookie has expired or the UUID does not match, re-run the full login flow from [Step 1](01-login.md). --- ## TOTP Details Fahipay uses standard RFC 6238 TOTP: | Parameter | Value | |---|---| | Algorithm | HMAC-SHA1 | | Period | 30 seconds | | Digits | 6 | | Encoding | Base32 secret | The user's TOTP seed is set up during initial Fahipay account creation and is the same secret used in any standard authenticator app (Google Authenticator, Aegis, etc.). --- ## Storing the Session After receiving `authID`, persist both values for future sessions: | Value | Description | |---|---| | `authID` | 40-char hex token — send as `authid` header | | `__Secure-sess` | Cookie value — send as `Cookie: __Secure-sess=` | On app restart, attempt requests with the stored session before falling back to a full re-login. ---   --- [← Login](01-login.md)     **Next →** [Profile](03-profile.md)