Агуулгыг алгасах

Gerege App-аар төлөх

Ямар ч гадны систем — вэб дэлгүүр, мобайл апп, касс, kiosk, вендинг машин, нэхэмжлэх — хүнээс Gerege App-аар төлбөр авах нээлттэй API. Сервер тал: modules/miniapp 1.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

  1. 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-аар app intent үүсгэх боломжгүй — хоёр зам хэзээ ч холилдохгүй (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-аар (Node paymentIntents.unclaim, Go PaymentIntents.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 «удахгүй»