# QR Payment BML supports QR-based payments via the PayMV network. There are two QR types — static merchant QRs (no preset amount) and gateway QRs (amount preset by merchant). Both are paid via the same 3-step TOTP-authenticated flow. --- ## QR Code Types | Type code | Name | Amount | |---|---|---| | `QRS` | Static QR | `0.00` — user enters amount | | `QRR` | Gateway / dynamic QR | Preset by merchant | --- ## QR Code Formats BML QR codes appear in two formats. ### 1. Plain URL QR ``` https://pay.bml.com.mv/app/ ``` The entire URL is base64-encoded and passed directly to the payrequest lookup API. ### 2. Combined EMV-style QR Used in Fahipay/PayMV combo QRs that embed multiple payment networks. The BML gateway URL is embedded as a TLV value at a fixed path. TLV path: **root tag `35` → sub-tag `20` → sub-sub-tag `01`** The value at tag `01` is the full `https://pay.bml.com.mv/app/...` URL. --- ## PayMV QR Format (TLV) PayMV QRs (static, PayMV-native) use a decimal TLV encoding (not BER-TLV): ``` <2-digit decimal tag><2-digit decimal length>... ``` ### Root-level tags (key fields for scanning) | Tag | Field | |---|---| | `26` | Merchant account information (container) | | `54` | Transaction amount | | `59` | Merchant / recipient name | | `62` | Additional data (container) | ### Sub-tags | Parent | Tag | Field | |---|---|---| | `26` | `03` | Account number | | `62` | `08` | Payment purpose / reference | > For the full PayMV QR format spec including generation (receive-payment QRs), acquirer BIC mapping, CRC algorithm, and all tags — see [PayMV QR Format](../thijooree/18-paymv-qr-format.md). --- ## Step 1 — Resolve QR to Merchant Details ### Endpoint ``` GET https://www.bankofmaldives.com.mv/internetbanking/api/mobile/walletpayments/payrequest/{base64Url} ``` `{base64Url}` is the full QR URL (e.g. `https://pay.bml.com.mv/app/...`) base64-encoded with standard encoding (with padding). ### Headers | Header | Value | |---|---| | `Authorization` | `Bearer ` | | `User-Agent` | `bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})` | | `x-app-version` | `2.1.44.348` | ```bash curl --request GET \ --url 'https://www.bankofmaldives.com.mv/internetbanking/api/mobile/walletpayments/payrequest/' \ --header 'Authorization: Bearer ' \ --header 'User-Agent: bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})' \ --header 'x-app-version: 2.1.44.348' ``` ### Response ```json { "success": true, "payload": { "trxn_hash": "", "narrative1": "Merchant Name", "narrative2": "Address Line 1", "narrative3": "Address Line 2", "amount": "1.03", "currency": "MVR" } } ``` ### Response Fields | Field | Description | |---|---| | `trxn_hash` | The base64 URL — used as `requestId` in payment steps | | `narrative1` | Merchant name | | `narrative2` | Merchant address line 1 | | `narrative3` | Merchant address line 2 | | `amount` | Payment amount (`"0.00"` for static QRS) | | `currency` | Currency code (typically `"MVR"`) | --- ## Step 2 — Pay (3-Step TOTP Flow) All three steps POST to the same endpoint: ``` POST https://www.bankofmaldives.com.mv/internetbanking/api/mobile/walletpayments/pay ``` ### Headers | Header | Value | |---|---| | `Authorization` | `Bearer ` | | `User-Agent` | `bml-mobile-banking/348 ({manufacturer}; Android {version}; {model})` | | `x-app-version` | `2.1.44.348` | | `Content-Type` | `application/json` | | `Accept` | `application/json` | ### Step 2a — Initiate (no channel) ```json { "action": "approve", "debitAccount": "", "requestId": "", "amount": 1.03, "currency": "MVR" } ``` Expected response: `{ "success": true, "code": 99 }` (OTP required) > **Note:** This step may be skipped. The app proceeds directly to Step 2b if the gateway already indicates OTP is required. ### Step 2b — Request OTP Channel ```json { "action": "approve", "debitAccount": "", "requestId": "", "amount": 1.03, "currency": "MVR", "channel": "token" } ``` Expected response: `{ "success": true, "code": 22 }` (OTP generated) ### Step 2c — Confirm with TOTP ```json { "action": "approve", "debitAccount": "", "requestId": "", "amount": 1.03, "currency": "MVR", "channel": "token", "otp": "" } ``` Expected response: ```json { "success": true, "code": 0, "payload": { "merchant": "Merchant Name", "amount": "1.03", "currency": "MVR" } } ``` On failure: ```json { "success": false, "message": "Payment failed" } ``` --- ## Request Fields | Field | Type | Description | |---|---|---| | `action` | `string` | Always `"approve"` | | `debitAccount` | `string` | Internal account UUID (not the display account number) — from dashboard `internalId` field | | `requestId` | `string` | The `trxn_hash` from the payrequest lookup | | `amount` | `number` | Payment amount as a number (e.g. `1.03`) | | `currency` | `string` | Currency code (e.g. `"MVR"`) | | `channel` | `string` | `"token"` — present in steps 2b and 2c only | | `otp` | `string` | TOTP code — present in step 2c only | > The `debitAccount` field takes the internal UUID from the dashboard response, **not** the displayed account number. See [Dashboard](04-dashboard.md) for the account object structure. --- ## OTP The OTP is a standard TOTP (RFC 6238, SHA-1, 30-second window, 6 digits) derived from the stored BML authenticator seed — the same seed used for login 2FA. --- ## Prerequisites - Valid `access_token` from [OAuth Token Exchange](03-oauth-token.md) - TOTP seed enrolled via BML app - Account `internalId` from [Dashboard](04-dashboard.md) ---   --- [← Tap-to-Pay](12-tap-to-pay.md)