6.4 KiB
Reload (Easy TopUp, paid by BML card)
Top up a Dhiraagu prepaid number through the dhiraagu.com.mv Easy TopUp page. Dhiraagu only builds the order: the money moves on a BML Merchant Services transaction that Dhiraagu creates for it, which is then paid exactly like any card-only BML merchant link (BML API → Merchant Card Payment).
Reconstructed from docs/dhiraaguapi/tmp/dhiraagu_reload_gateway.md (a Firefox HAR).
Flow overview
GET /services/easy-topup → nonce #1
POST cart&act=recharge (nonce #1) → cartId
GET /services/payment-v2?cartid=<cartId> → nonce #2
POST merchant&act=form (nonce #2) → BML gateway's merchantId
POST payment&act=create (nonce #2) → paymentId, oid
POST bml&act=createV2 (nonce #2) → BML transaction url ──┐
│
── from here: the BML card-only merchant flow ── │
GET transaction.merchants…/<id>/paynow ←─────────────────────────────┘
… Pomelo tokenise, next-action, Wibmo 3-D Secure, MPGS … → TRANSACTION_CONFIRMED
GET transaction.merchants…/<id>?wait=1 → 302 dhiraagu-bml-response.aspx (tops up)
→ 302 /services/reload-receipt
After the payment the browser is sent transaction…/<id>?wait=1 →
dhiraagu-bml-response.aspx?transactionId=<id>&state=CONFIRMED&signature=… →
/services/reload-receipt?pyid=<paymentId>. This is what makes Dhiraagu top up the number —
a payment that stopped at BML's TRANSACTION_CONFIRMED was charged but not delivered until that
URL was opened. The card flow follows it for every merchant, see
BML API → Return to the merchant.
Recovering a stuck reload: open https://transaction.merchants.bankofmaldives.com.mv/<id>?wait=1
in a browser. BML signs the callback, so the transaction id is all that's needed. (curl gets a
Cloudflare 403 on the Dhiraagu hop; a browser works.)
Common
All API calls are POST https://www.dhiraagu.com.mv/api/sdk-dhr-webapi.ashx?website_id=CA2BB809-3A22-485B-A518-DA6B6DE653A5&sub=<sub>&act=<act>
with a JSON body and these headers:
| Header | Value |
|---|---|
User-Agent |
a browser UA (same as Number Lookup) |
Content-Type |
application/json |
X-Requested-With |
XMLHttpRequest |
Origin |
https://www.dhiraagu.com.mv |
nonce |
var nonce = "…" from the page that makes the call |
Every response is {"respStatus":"OK","resp":…} on success.
Each page has its own nonce: the cart call uses the Easy TopUp page's, the rest use the payment page's.
1. Settings (optional)
GET …&sub=setting&act=reload — the page reads its limits from here. Thijooree hardcodes them.
{"gstRate":0.08,"dailyLimit":3000,
"amountLimit":{"min":20,"max":1080,"message":"Enter a whole number amount between MVR 20 and 1000"},
"reloadPerDay":{"easyTopUp":4,"myAccount":6}, …}
| Rule | Value |
|---|---|
| Amount | whole MVR, 20 – 1000 (the message says 1000; max says 1080 — Thijooree uses 1000) |
| GST | 8%, included in the amount |
| Per day | MVR 3000, 4 Easy TopUps |
GST, as the page works it out: gst = round2(amount × 0.08 / 1.08), credited amount − gst
(MVR 20 → GST 1.48, credited 18.52).
2. Cart
sub=cart&act=recharge, nonce from GET /services/easy-topup.
{"formId":2,"serviceNumber":"7XXXXXX","amount":20,"amountGST":1.48,"amountRecharge":18.52,
"gstRate":0.08,"memberId":"","memberName":"","memberNId":"","customerId":"","customerCode":"","version":2}
{"cartId":"002773ed-…","formId":2,"cartAmount":20.00,"cartExpiry":"…",
"paymentUrl":"https://www.dhiraagu.com.mv/services/payment-v2?cartid=002773ed-…", …}
The page also calls sub=dhiraaguIO&act=infoSubscriberStatus ({"number"}) before this, to show
the number's status and balance. Thijooree skips it — Number Lookup has
already confirmed a prepaid number.
3. Payment gateway
sub=merchant&act=form, {"formId":2}, nonce from GET /services/payment-v2?cartid=<cartId>.
Lists the gateways; gatewayId: 1 is Bank of Maldives (2 = MIB, 3 = DhiraaguPay).
[{"merchantId":"98de333c-…","merchantId2":"3f5cf6b7-…","formId":2,"gatewayId":1,
"gatewayName":"Bank of Maldives", …}, …]
4. Payment
sub=payment&act=create
{"formId":2,"cartId":"<cartId>","gatewayId":1,"dhiraaguPayNumber":"","amount":"20.00",
"paymentMerchantId":"<BML merchantId>","memberId":"","tokenize":"","paymentType":"",
"recurringFrequency":"","bmlTokenId":""}
{"paymentId":"3ea4351b-…","oid":"ET20260006911381","gatewayId":1,"amount":20.00,"paymentStatus":0, …}
5. BML transaction
sub=bml&act=createV2, {"paymentId":"<paymentId>"}. Returns the BML Merchant Services
transaction (amounts in cents):
{"state":"INITIATED","amount":2000,"currency":"MVR","localId":"ET20260006911381",
"url":"https://transaction.merchants.bankofmaldives.com.mv/6abfec7afd7f4a4360fc1df4",
"redirectUrl":"https://www.dhiraagu.com.mv/api/dhiraagu-bml-response.aspx",
"expires":"…(10 min)…","customerReference":"WebApp - Topup", …}
The 24-hex id at the end of url is the transaction. Its /paynow page offers UnionPay +
MPGS cards only, no BML Pay, so it's paid by card + 3-D Secure.
Reload record
sub=reload&act=list, {"paymentId"}, nonce from the receipt page — what the receipt page shows:
{"oid":"ET20260006911381","transId":"<BML txn id>","serviceNumber":"7XXXXXX",
"amountPay":20.00,"amountTopup":18.52,"amountGST":1.48,
"paidStatus":1,"topupStatus":1,"reloadStatusDesc":"Successful", …}
Not used by Thijooree yet.
Cloudflare
www.dhiraagu.com.mv is behind Cloudflare. The browser capture carries a cf_clearance cookie,
but Number Lookup already works from the app with plain okhttp and a browser
UA, so these calls are made the same way.
Related: Number Lookup · BML Merchant Card Payment · App side: Transfer Flows