Withdrawals to a bank¶
Request, follow and cancel moving money from a Gerege Wallet account (a person's or an organisation's) to a real bank account. About 6 minutes to read. You need a person signed in to Gerege App, or an organisation's admin; enough balance on the account; and the real bank account's number.
Why a withdrawal is a «request»
Gerege Wallet's bank code 0098 is not issued by the Bank of Mongolia (it is temporary). So no other bank can send money to a Gerege Wallet IBAN, and Gerege Wallet cannot send straight to another bank. A withdrawal is a request: the amount is held on your account (so it cannot be spent twice), the operator transfers it from its own real bank account to the account you named and records the bank's transaction reference. Top-ups likewise go through the operator's real account.
How it works¶
- You send a request → the amount is held on your account →
requested. - The operator takes the request →
processing(from this moment it cannot be canceled — the operator is paying it at the real bank). - The operator pays at the real bank and enters the bank's transaction reference →
paid, the hold is taken from your account, andbank_referencecarries that reference. Or the operator rejects it →rejected, the hold is released back. - You get a «money sent» notification (amount, bank name) or a «returned» one; the reason for a rejection is shown in the app.
Timing: withdrawals are paid out by the operator by hand (in working hours). A service-level commitment (SLA) is to be announced.
Sending a request¶
| Who | Path |
|---|---|
| A person, their own active MNT account | POST /api/v1/bank/me/accounts/{id}/withdrawals |
| An organisation's admin | POST /api/v1/bank/org/{tenant}/accounts/{id}/withdrawals |
curl -sS https://geregeapp.mn/api/v1/bank/me/accounts/$ACCOUNT_ID/withdrawals \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Idempotency-Key: wd-2026-10-27-0001" \
-H "Content-Type: application/json" \
-d '{"amount": 250000, "bank_name": "Khan Bank", "bank_account": "5012345678", "holder_name": "Alisa Bat"}'
| Field | Rule |
|---|---|
amount |
1 000 – 50 000 000 ₮, whole; at most the account's available balance |
bank_name |
2 – 100 characters |
bank_account |
an MN IBAN or a number of 5 – 20 digits (spaces and dashes removed). A Gerege Wallet (0098) IBAN is use_transfer — send a transfer instead |
holder_name |
2 – 100 characters, the holder of the receiving account |
Idempotency-Keyis required, 8 – 128 characters. The same key with the same body → that request (200); another body →409 idempotency_conflict. If the connection drops (the request may staypending), send it again with the same key.- One owner may have at most 3 open requests (waiting, up to
processing) at a time. - Rate limit — 6 a minute.
- SMS confirmation: above a threshold the operator sets, the first answer is
428 confirmation_required{challenge_id, phone (masked), expires_at}and a code goes to your verified phone. Send the same request (same body, sameIdempotency-Key) again with the headersX-Confirmation-Id: <challenge_id>andX-Confirmation-Code: <code>. The code is bound to this account, amount, receiving account and key — it does nothing for another withdrawal. For an organisation's withdrawal the code goes to the admin's own number.
The answer 201 (new) is the withdrawal, requested.
The withdrawal object¶
{
"id": "4c1f…",
"account_id": "…",
"account_number": "0980000017",
"amount": 250000,
"currency": "MNT",
"status": "requested",
"destination": {"bank_name": "Khan Bank", "bank_account": "5012345678", "holder_name": "Alisa Bat"},
"bank_reference": null,
"failure_code": null,
"reject_reason": null,
"cancelable": true,
"created_at": "…", "updated_at": "…",
"processing_at": null, "paid_at": null, "rejected_at": null, "canceled_at": null
}
status |
Meaning | Cancel |
|---|---|---|
pending |
the hold's outcome is not known — send again with the same Idempotency-Key; the platform looks for it after 5 minutes and, if not found within an hour, marks it failed (nothing held) |
yes |
requested |
the amount is held, waiting for the operator | yes |
processing |
the operator took it and is paying it at the real bank | no |
paid |
paid; bank_reference = the bank's transaction reference |
— |
rejected |
the operator rejected it (reject_reason), the hold released |
— |
canceled |
you canceled it, the hold released | — |
failed |
no hold could be placed (failure_code: for example insufficient_funds, account_frozen, hold_not_placed) |
— |
Listing, reading, canceling¶
| Method | Path (a person; for an organisation /api/v1/bank/org/{tenant}/…) |
Answer |
|---|---|---|
| GET | /api/v1/bank/me/accounts/{id}/withdrawals?limit=&before= |
{"data": [Withdrawal], "next_before": time \| null} — newest first, limit default 50, ≤ 100; for the next page before=<next_before> |
| GET | /api/v1/bank/me/accounts/{id}/withdrawals/{wid} |
Withdrawal / 404 |
| POST | /api/v1/bank/me/accounts/{id}/withdrawals/{wid}/cancel |
while pending / requested 200 (canceled, the hold released); already canceled 200; anything else → 409 not_cancelable {status} |
An organisation's requests and cancellations are written to the organisation's audit log. In Gerege App (iOS): a person uses Wallet → «Withdraw to a bank»; an organisation's admin Settings → Wallet → «Organisation account» (open the account, balance, transactions, withdraw). Sending a request, following it and cancelling it before the operator starts are all in the app.
Errors¶
| HTTP | code |
When |
|---|---|---|
| 400 | — | Idempotency-Key missing or not 8 – 128 |
| 400 | invalid_amount |
not 1 000 – 50 000 000 |
| 400 | invalid_bank_name · invalid_holder_name |
not 2 – 100 characters |
| 400 | invalid_bank_account |
not an MN IBAN or 5 – 20 digits |
| 400 | use_transfer |
a Gerege Wallet (0098) account — a transfer, not a withdrawal |
| 403 | — | not an admin, on an organisation's route |
| 404 | — | the account is not yours / no such withdrawal |
| 409 | idempotency_conflict |
the key was used for another request |
| 409 | too_many_open |
3 open requests already (open) |
| 409 | not_cancelable |
processing or finished (status) |
| 422 | account_unavailable |
money cannot leave the account now (inactive, not MNT) |
| 422 | insufficient_funds |
the available balance is not enough (nothing is recorded) |
| 428 | confirmation_required |
confirm with the SMS code (above) |
| 400 · 403 · 410 · 429 · 502 · 503 | wrong_code (attempts_left), confirmation_invalid, phone_required, code_expired, too_many_codes, sms_failed, sms_unavailable |
SMS confirmation errors |
| 503 | withdrawals_unavailable |
withdrawals are not enabled on this installation |
| 503 | license_required |
the ledger is temporarily read-only |