Gerege App-аар төлөх¶
Ямар ч гадны систем — вэб дэлгүүр, мобайл апп, касс, kiosk, вендинг машин, нэхэмжлэх — хүнээс Gerege App-аар төлбөр авах нээлттэй API. Сервер тал:
modules/miniapp1.7.0 (2026-10-27). Mini app-ын төлбөрийн (Mini app төлбөр) хөдөлгүүр, webhook, тооцоо, sandbox нь яг ижил; ялгаа нь intent-ийг хэн нэгний token-гүйгээр үүсгэж, хүн дараа нь Gerege App дотроо өөртөө авдаг (claim) явдал.Энэ хуудас — нийтлэг суурь (бүртгэл, auth, claim, sandbox, лавлах). Урсгал бүрийн алхам алхмаар заавар — §4. «удахгүй» = энэ хувилбарт хэрэгжээгүй (§11).
1. Худалдагч гэж юу вэ¶
Худалдагч бол mini app-ын нэг төрөл: kind: "merchant". Ижил registry, client id/secret (live, test), webhook,
review, тооцоо, аналитиктай — гэхдээ launcher-т хэзээ ч гарахгүй, entry URL, origin, manifest шаардахгүй.
kind: "miniapp" |
kind: "merchant" |
|
|---|---|---|
| Хүн хаанаас төлөх | Gerege App доторх таны вэб апп, bridge requestPayment |
Таны вэб/апп/машин: pay_url (redirect, QR) эсвэл терминалын sticker/NFC |
| Intent үүсгэх | хүний access token (Bearer) |
апп-ын client credential (Basic) |
presentment |
app |
qr · redirect · terminal |
Хүний нэр (user_ref) |
апп бүрт тогтмол pairwise sub |
төлбөр бүрт санамсаргүй u_<32 hex> (зөвшөөрөл өгөөгүй тул тогтмол нэр авахгүй) |
| Manifest, launcher | заавал | байхгүй |
Олон эзэмшигчтэй платформ (машин бүр өөр эзэнтэй) нэг худалдагч апп дотор эзэмшигч бүрийг дэд худалдагч болгоно — дэд худалдагч.
2. Бүртгэл ба review¶
- Gerege App-ын workspace-ийн консол (API:
POST /api/v1/miniapp/dev/apps):
{ "kind": "merchant", "slug": "vending", "name": "Vending.mn", "category": "services",
"icon_url": "https://vending.mn/icon-512.png", "developer_name": "Вендинг ХХК", "developer_email": "dev@vending.mn" }
Scope нь автоматаар profile.basic + payments. kind-ийг дараа нь зөвхөн ноорог/татгалзсан үед өөрчилнө.
name ба icon_url нь хүнд төлөх цонхонд харагдана (review баталсан хэлбэрээр).
2. API түлхүүр: консолоос (API: POST …/dev/apps/{id}/keys, preset «Checkout сервер», «Вендинг / kiosk
backend» …) → id gk_test_… ба secret gks_test_… — secret нэг удаа харагдана. Live түлхүүр одоогоор
POST …/dev/apps/{id}/credentials {"environment": "live"}-ээр (хуучин mapp_… / gma_cs_… хос — орчныхоо бүх
scope-той; шинэ API-аар live үүсгэх нь «удахгүй»). Webhook: POST …/dev/apps/{id}/webhook {"url"} → whsec_… нэг
удаа (Webhooks).
3. Redirect checkout хийх бол буцах host-уудаа бүртгэнэ: PATCH …/dev/apps/{id} {"return_hosts": ["shop.mn"]} —
≤ 5, яг host (вэб checkout §2).
4. Review: POST …/dev/apps/{id}/submit. Худалдагчид manifest шаардахгүй (…/manifest/check → 409 merchant_no_manifest);
харин privacy_url, terms_url, support_url, идэвхтэй live webhook endpoint (webhook_url-ийн №1, эсвэл нэмсэн
аль нэг — алдааны path нь webhook_url хэвээр), live secret заавал, https хуулийн хуудсууд 200
хариулах ёстой (mailto: support зөвшөөрнө) — дутуу бол 400 not_ready (details). Дараа нь оператор батлаж,
апп-ын payout дансыг тохируулна (PUT /review/apps/{id}/payout).
Батлагдахаас өмнө ч test түлхүүрээр бүгдийг туршина (§6).
3. Auth¶
Худалдагчийн бүх дуудлага: Authorization: Basic base64(<түлхүүрийн id>:<secret>) — gk_<орчин>_…:gks_<орчин>_…
(эсвэл хуучин mapp_…:gma_cs_…). Base URL
https://geregeapp.mn/api/v1/miniapp. Хязгаар: минутад 600 (burst 120) — intent, терминал, дэд худалдагч тус бүр.
- Client secret зөвхөн таны сервер дээр. Терминал, машин, kiosk, браузер, мобайл апп secret ХЭЗЭЭ Ч барихгүй — тэд
pay_urlэсвэл терминалынurl-ийг л харуулна. Машин → таны backend → Gerege. - Хүний token-оор (
Bearer) claimless intent үүсгэх боломжгүй, client credential-аарappintent үүсгэх боломжгүй — хоёр зам хэзээ ч холилдохгүй (400 presentment_required). - Credential-ийн орчин (test / live) intent-ийн
livemode-ыг шийднэ; түлхүүр зөвхөн өөрийн орчны intent-ийг харна. - Scope: түлхүүр бүр зөвхөн өөрийн scope-уудыг —
payments:read(intent унших, жагсаах),payments:write(үүсгэх, capture, cancel, unclaim),refunds:write,terminals:read/:write,sub_merchants:read/:write,payout_links:write,settlements:read. Дутуу бол403 insufficient_scope+required_scope. Preset: «Checkout сервер» (payments, refunds), «Вендинг / kiosk backend» (+ терминал, дэд худалдагч, payout-link), «Терминал суулгагч», «Зөвхөн унших». Test түлхүүрт бүртгэл бичих scope (terminals:write,sub_merchants:write,payout_links:write) олгогдохгүй. Түлхүүр солих (roll, давхцалтай), хүчингүй болгох — консолд; IP allowlist — «удахгүй».
4. Аль guide минийх вэ¶
| Таны систем | presentment |
Guide |
|---|---|---|
| Вэб дэлгүүр | redirect |
Вэб дэлгүүр |
| Өөрийн iOS / Android апп | redirect (буцах нь таны Universal Link) |
Мобайл апп |
| Касс, POS, kiosk — сагс бүрт дэлгэцэнд QR | qr |
Касс, POS, kiosk |
| Вендинг машин — бараа гарсны дараа мөнгө авах | terminal + manual |
Вендинг машин |
| Байнгын цэг (машин, ширээ, хаалга) — QR/NFC sticker | terminal |
Терминал ба NFC sticker |
| Олон эзэмшигч (маркетплейс, машины эзэд) | дээрхийн аль нь ч + sub_merchant_id |
Дэд худалдагч |
| Нэхэмжлэх, сар бүрийн төлбөр | redirect (таны холбоосоор) |
Нэхэмжлэх |
| Gerege App дотор нээгддэг вэб апп | app |
Mini app төлбөр |
Нийтлэг сэдэв: барьцаа (manual capture), тулгалт.
5. pay_url, claim, user_ref¶
pay_url=https://geregeapp.mn/pay/<24 тэмдэгт>— claimless intent үүсгэх хариунд (ба ижилIdempotency-Key-ийн давталтад — ижил холбоос) л байна;GET, жагсаалт, webhook-д хэзээ ч үгүй. Энэ бол claim-ийн bearer secret: лог-д бичихгүй, тухайн хүнээс өөр хэнд ч харуулахгүй. Token-д дүн, хүлээн авагч байхгүй; сервер зөвхөн SHA-256-ийг нь хадгална.- Claim — хүн
pay_url-ийг уншуулах эсвэл терминалд утсаа хүргэхэд Gerege App intent-ийг тэр хүнийх болгоно (payment_intent.claimed). Төлөх цонхонд худалдагчийн бүртгэлтэй нэр, терминалынlabel/location, дэд худалдагчийн нэр, дүн — Face ID-аас өмнө. Худалдагчийн intent-ийнdescription-ийг Gerege App харуулахгүй (M4) — тэр нь хүний хэтэвчний хуулгад л орно. - Claim-ийн хамгаалалт (терминалын код хэвлэгддэг тул хэн ч алсаас claim хийж чадна): баталгаажаагүй claim
90 секундэд дуусаж дараагийн хүн авна (шинэ
user_ref, дахинclaimed); нэг хүн нэг дор ≤ 3 баталгаажаагүй claim (429 too_many_open_claims); өөр хүн claim хийсэн intent-д409 already_claimed+retry_after: 90; таPOST /payment-intents/{id}/unclaim-аар (NodepaymentIntents.unclaim, GoPaymentIntents.Unclaim) суллана. user_ref— claim хүртэлnull, дараа нь төлбөр бүрт санамсаргүйu_<32 hex>: та нэг хүний худалдан авалтуудыг хооронд нь холбож чадахгүй. Нэр, регистр, утас, данс — хэзээ ч ирэхгүй.min_age(13–21, апп-ынхаас багагүй) — Gerege төлөгчийг claim ба confirm үед шалгана: eID-гүй →403 verification_required, нас хүрэхгүй →403 age_restricted.
6. Sandbox (test горим)¶
- Test түлхүүрээр (
gk_test_…, эсвэл хуучинmapp_test_…) test intent үүсгэж, claim, capture, cancel, refund, unclaim хийнэ. Мөнгө хөдлөхгүй,livemode: false; payout данс, core banking шаардахгүй. - Терминал, дэд худалдагчийг test түлхүүр зөвхөн уншина — бүртгэл нь хоёр орчинд нэг тул бичих (үүсгэх, засах,
payout-link) нь live түлхүүр эсвэл консол (
403 live_only). Терминалд test сагс live сагсыг хаахгүй. - Test claimless intent-ийг зөвхөн апп-ын эзэн ба тест хэрэглэгчид (таны байгууллагын идэвхтэй гишүүд —
консол) claim хийнэ; бусдад тэр intent байхгүй мэт (
404). - Үр дүнг дүнгийн сүүлийн хоёр орон шийднэ (Mini app төлбөр §6):
…01→failed(test_declined),…02→canceled, бусад →succeeded(manual болrequires_capture). - Webhook-ийн хүргэлт, дахин илгээх,
webhook.test— консолд (консол §1). - Хүний талыг утасгүй дуурайх «Симуляц» — «удахгүй».
7. API лавлах¶
Бүгд /api/v1/miniapp угтвартай, Basic.
| Method | Зам | Хариу |
|---|---|---|
| POST | /payment-intents |
201 / 200 (давталт) — intent + pay_url. Idempotency-Key заавал |
| GET | /payment-intents/{id} · /payment-intents?reference=&status=&limit=&after= |
intent · {data, has_more} |
| POST | /payment-intents/{id}/capture · /cancel · /unclaim |
intent (capture нь 202 байж болно) |
| POST | /payment-intents/{id}/refunds |
{amount?, reason?} + Idempotency-Key → 201 / 202 / 200 |
| GET · POST | /terminals |
{data: [Terminal]} · 201/200 Terminal (live) |
| GET · PATCH | /terminals/{id} |
Terminal |
| GET · POST | /sub-merchants |
{data: [SubMerchant]} · 201/200 SubMerchant (live) |
| GET · PATCH | /sub-merchants/{id} |
SubMerchant |
| POST | /sub-merchants/{id}/payout-link |
201 PayoutLink (live) |
| GET | /sub-merchants/{id}/payout-links |
{data: [PayoutLink]} (сүүлийн 50) |
| GET | /settlements · /settlements/{id} |
Mini app төлбөр §7 |
| GET | /pay/{token} · /pay/t/{code} |
нийтийн, auth-гүй: худалдагчийн нэр, терминал, дүн, төлөв (тайлбар, reference, хэн төлж буй — үгүй); минутад 120 |
Claimless intent үүсгэх талбарууд (Mini app төлбөр §2-ын бусад талбар дээр нэмэгдэнэ):
| Талбар | Дүрэм |
|---|---|
presentment |
qr · redirect · terminal (Basic-д заавал) |
terminal_id |
terminal-д заавал, бусдад хориотой |
sub_merchant_id |
заавал биш; терминалынх бол автоматаар (өөр байвал 400) |
return_url |
redirect-д заавал (qr, terminal-д болно); host нь return_hosts-д; https; ≤ 2048 |
min_age |
13–21, апп-ынхаас багагүй |
capture_within |
зөвхөн manual: 60–604 800 с, анхдагч 604 800 |
Intent-ийн шинэ талбарууд (бүх intent-д, app-д ч): presentment, terminal, sub_merchant, return_url,
claimed_at, min_age, capture_within; user_ref claim хүртэл null.
{ "id": "pi_…", "object": "payment_intent", "status": "requires_confirmation", "amount": 3500, "currency": "MNT",
"description": "Захиалга #77120", "reference": "77120", "user_ref": null, "livemode": true, "capture_method": "manual",
"refunded_amount": 0, "fee": null, "net": null, "failure_code": null, "expires_at": "…", "capture_before": null,
"confirmed_at": null, "created_at": "…", "metadata": {"machine": "VM-0007"},
"presentment": "terminal", "terminal": "4b8e…", "sub_merchant": "9a7c…", "return_url": null,
"claimed_at": null, "min_age": null, "capture_within": 180,
"pay_url": "https://geregeapp.mn/pay/Qk3v…" }
8. Тооцоо¶
Mini app төлбөр §7-тай ижил, нэг ялгаа: урсгал (апп, дэд худалдагч) тус бүрт.
- Тооцоо унтраалттай (анхдагч; production одоо
shadow): capture-ийн бүтэн дүн шууд payout руу — дэд худалдагчийнх бол түүний батлагдсан данс руу, үгүй бол апп-ын. - Оператор асаасан үед: дэд худалдагч бүр өөрийн клиринг-тэй, шимтгэл, хуваарь нь апп-ын дүрмээр.
Settlementобъект (GET /settlements,settlement.paid) нэмэлт"sub_merchant": "<id>" | null(null= апп-ын өөрийн урсгал). Дэлгэрэнгүй: дэд худалдагч §5.
9. Webhook¶
Webhooks-тай ижил гарын үсэг, retry. Худалдагчид чухал event-ууд:
| type | Хэзээ |
|---|---|
payment_intent.claimed |
Хүн intent-ийг өөртөө авсан (user_ref, claimed_at орсон) — «утсаараа баталгаажуулна уу» |
payment_intent.requires_capture |
Manual: мөнгө барьцаалагдсан — бараагаа өгөөд capture / cancel |
payment_intent.succeeded |
Төлөгдсөн |
payment_intent.expired |
Claimless intent-ийн хугацаа дууссан — claim хийгдсэн ч, хийгдээгүй ч; мөн manual hold-ын capture_within дууссан (failure_code: "authorization_expired") |
payment_intent.canceled |
Та (эсвэл хүн) цуцалсан |
payment_intent.failed |
Баталгаажуулалт амжилтгүй (failure_code); хүн хугацаа дуустал дахин оролдож болно |
refund.succeeded · refund.failed · settlement.paid |
Буцаалт, тооцоо |
expiredбаcanceled. Claimless intent хугацаа дуусахадpayment_intent.expired. Mini app-ын (app) intent хуучнаарааpayment_intent.canceled+status: "expired"— OMAS-д бичсэн backend-ууд эвдрэхгүй.- Бүх intent event-д
presentment,terminal,sub_merchant(id) байна. - Event commit хийгдмэгц шууд нэг удаа илгээгдэнэ (машины хүлээлт секундээр); амжилтгүй бол ердийн retry хуваарь.
- At-least-once: нэг event дахин ирж болно, дараалал баталгаагүй —
id-аар давхардлыг арилга, шийдвэрээ intent-ийгGET-ээр дахин уншаад гарга. Хүлээн авагчийн жишээ:examples/node/src/webhook.ts,examples/go/cmd/webhook/main.go.
10. Алдаа¶
Хэлбэр нь Алдааны код-тай ижил: {"error": "<Монгол мессеж>", "code": "<код>", …};
credential-ийн алдаа OAuth хэлбэрээр {"error": "invalid_client", "error_description"}.
| HTTP | code | Хэзээ | Юу хийх |
|---|---|---|---|
| 400 | presentment_required |
Basic-аар presentment-гүй (эсвэл app) intent |
qr / redirect / terminal |
| 400 | validation_error |
details[].path: presentment, terminal_id, sub_merchant_id, return_url, min_age, capture_within, … |
талбараа засна |
| 400 | idempotency_key_required |
Idempotency-Key алга |
захиалгын дугаараа өг |
| 400 | invalid_sub_merchant |
терминалын sub_merchant_id буруу |
|
| 400 | code_immutable |
дэд худалдагчийн code-ыг өөрчлөх гэсэн |
шинэ дэд худалдагч |
| 401 | invalid_client |
client id/secret буруу, Basic алга | credential |
| 403 | insufficient_scope |
түлхүүрт энэ route-ын scope алга (required_scope) |
түлхүүрийн scope |
| 403 | live_only |
test түлхүүрээр терминал, дэд худалдагч, payout-link бичих | live түлхүүр эсвэл консол |
| 409 | terminal_busy |
терминалд нээлттэй intent байна (payment_intent: түүний id) |
тэрийг cancel хийгээд дахин |
| 409 | terminal_disabled · sub_merchant_disabled |
идэвхгүй | PATCH status: active |
| 409 | payouts_not_configured |
live: апп-ын эсвэл дэд худалдагчийн батлагдсан payout алга | оператор / payout-link |
| 409 | reference_taken |
өөр терминал энэ reference-тэй |
|
| 409 | not_unclaimable |
баталгаажуулалт явж байгаа intent-ийг unclaim | хүлээ |
| 409 | idempotency_conflict |
key өөр body-той ашиглагдсан | |
| 409 | not_capturable · expired · not_cancelable · in_progress |
capture/cancel-ийн төлөв таарахгүй (payment_intent-тэй) |
intent-ийг уншаад шийд |
| 422 | account_unsupported |
payout дансны эзэмшигч Gerege App-ын хүн ч, байгууллага ч биш | өөр данс |
| 422 | no_admin |
байгууллагын данс, гэхдээ тэр байгууллагад батлах админ алга | байгууллага админ томилно |
| 502 | core_unavailable |
core banking хариу өгсөнгүй («мэдэгдсэнгүй») | дахин |
| 503 | directory_unavailable |
байгууллагын админуудыг түр тодорхойлж чадсангүй | дахин |
| 503 | payments_unavailable · pay_url_unavailable |
суулгацад core banking / PUBLIC_ORIGIN алга |
дахин, оператор |
Бүх кодын жагсаалт — Алдааны код. Сүлжээний алдаа, 429, 5xx — ижил
Idempotency-Key-ээр дахин илгээх нь аюулгүй.
11. Хэрэгжилтийн төлөв¶
| Хэсэг | Төлөв |
|---|---|
kind: "merchant", return_hosts, худалдагчийн review (хуулийн хуудас + оператор) |
✓ (API; консолын дэлгэц цөмд) |
Claimless intent (qr, redirect, terminal), pay_url, min_age, capture_within, claim-ийн хамгаалалт, unclaim |
✓ |
Терминал, дэд худалдагч, эзэмшигчийн баталдаг payout холболт (terms), (апп, дэд худалдагч)-ын тооцоо |
✓ |
payment_intent.claimed / .expired, шууд webhook хүргэлт, нийтийн GET /pay/{token}, /pay/t/{code} |
✓ |
Node SDK (paymentIntents.create(params, opts), terminals, subMerchants), Go client (miniapp.NewClient) |
✓ |
Ажилладаг жишээ: examples/node, examples/go (checkout, вендинг, webhook) |
✓ |
Scope-той, нэртэй, солигддог API түлхүүр (gk_ / gks_, miniapp 1.8.0) |
✓ (live-ийг шинэ API-аар үүсгэх, IP allowlist — «удахгүй») |
Gerege App iOS: QR, апп доторх NFC уншигч, /pay/ Universal Link → claim → төлөх цонх; payout батлах дэлгэц; NFC sticker бичигч |
✓ (Universal Link ба арын NFC уншилт — цөмийн AASA /pay/* production-д гармагц) |
Компьютер дээрх https://geregeapp.mn/pay/<token> QR хуудас (цөмийн shell) |
«удахгүй» |
App Clip (https://appclip.geregeapp.mn/pay?t=<code>; Clip дотор eID + SMS кодоор төлөх) |
«удахгүй» |
Дүнтэй хэсэгчилсэн capture (POST /capture {amount}) |
«удахгүй» — бүтэн capture + буцаалт |
Олон webhook endpoint (орчин бүрт ≤ 5, шүүлтүүр, secret солих), events API (GET /events, miniapp 1.9.0) |
✓ |
| Самбар, тайлан, симуляц, хэвлэх хуудас | «удахгүй» |
| Хүн дүнгээ өөрөө бичих терминал; утсаа терминалд хүргэж төлөх (NFC & SE); NTAG 424 DNA | «удахгүй» |