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

Төлбөрийн урсгалууд ба claim

presentment нь хүн intent-д яаж хүрэхийг хэлнэ. Дөрөв бий; app-аас бусад гурав нь claimless — хүнгүй төрж, хүн Gerege App-д уншуулахдаа өөртөө claim хийнэ. Аль нь танд: Урсгалаа сонгох.

1. Дөрвөн урсгал

presentment Хэн үүсгэх Хүн яаж хүрэх Төлсний дараа
app mini app-ын backend, хүний token (Bearer) Gerege App доторх таны апп, bridge requestPayment bridge хариу; backend шалгана
redirect худалдагчийн backend (Basic) + return_url pay_url: утсанд Universal Link → Gerege App; компьютерт QR хуудас («удахгүй») апп return_url?pi=<id>-г нээнэ
qr худалдагчийн backend (Basic) дэлгэц дээрх pay_url-ийн QR → Gerege App-ын QR уншигч дэлгэц webhook-оор шинэчлэгдэнэ
terminal худалдагчийн backend (Basic) + terminal_id терминалын байнгын url (sticker QR, NFC NDEF URI) машин webhook-оор гаргана

Хүний тал: Gerege App (iOS)-ын апп доторх QR товч ба NFC уншигч → claim → төлөх цонх — TestFlight 121-ээс хойшх build-д. Камераар уншуулах (/pay Universal Link), компьютер дээрх /pay хуудас, App Clip — «удахгүй». API бүхэлдээ бэлэн.

2. pay_url

https://geregeapp.mn/pay/<token>        ← qr, redirect (бас terminal intent-д)
https://geregeapp.mn/pay/t/<code>       ← терминалын байнгын url (дүнгүй)
  • Token = claim-ийн bearer secret. 24 тэмдэгт (144 бит санамсаргүй), сервер зөвхөн SHA-256-ийг нь хадгална.
  • Зөвхөн үүсгэх хариунд (ба ижил Idempotency-Key-ийн давталтад — ижил холбоос). GET, жагсаалт, webhook-д хэзээ ч байхгүй. Лог, аналитикт бүү бич.
  • Дүн, хүлээн авагч URL-д байхгүй. Дүнг сервер intent-ээс уншина; хэн нэгэн URL засаж дүн өөрчлөх боломжгүй.
  • Intent-тэй хамт үхнэ: intent дууссан (expired, canceled, succeeded) бол token юу ч нээхгүй.
  • Нийтийн харагдац GET /api/v1/miniapp/pay/{token} (session-гүй): апп-ын нэр, icon, терминал, дүн, төлөв, claimed — тайлбар, reference, хэн claim хийсэн байхгүй. Компьютер дээрх хуудас үүнийг polling хийнэ.

3. Claim

Claimless intent-ийг хүн өөртөө авах үйлдэл: POST /api/v1/miniapp/payments/claim {"token"} эсвэл {"terminal"} (Gerege App хийнэ, хүний session-ээр).

таны backend ─create (Basic)─▶ intent (хүнгүй, user_ref: null)
                                   │
хүн уншуулна ─▶ Gerege App ─claim─▶ шалгалт: token / терминал → апп төлбөр авч болох уу →
                                            насны хязгаар, eID баталгаажуулалт (min_age, requires_verified)
                                   │ хүнийх боллоо: user_ref = u_<шинэ санамсаргүй>, claimed_at
                                   ├────────── webhook payment_intent.claimed ──▶ таны backend («утсаараа баталгаажуул»)
                                   ▼
                     төлөх цонх (бүртгэлийн нэрс) → Face ID → confirm
  • Нэг хүнд idempotent: дахин claim → мөн тэр intent.
  • Терминалаар: эхлээд энэ хүнийх болсон нээлттэй intent, дараа нь claim хийгдээгүй, дараа нь claim нь суларсан.
  • Test intent-ийг зөвхөн апп-ыг бүртгэсэн хүн ба тест хэрэглэгчид claim хийнэ; бусдад байхгүй мэт (404).

4. Claim-ийн хамгаалалт

Терминалын код хэвлэгдсэн, /pay/t хуудас нийтийнх — хэн ч алсаас claim хийж чадна. Тиймээс:

Дүрэм Юуны эсрэг
Баталгаажаагүй claim 90 секундэд суларна — дараагийн хүн авна (шинэ user_ref, дахин payment_intent.claimed); өмнөх хүн intent-ийг харахаа больно алсаас claim хийгээд машиныг хаах
Өөр хүний идэвхтэй claim → 409 already_claimed + retry_after: 90 хоёр хүн нэг сагс
Нэг хүн нэг дор баталгаажаагүй ≤ 3 claim → 429 too_many_open_claims олон машиныг нэг дор хаах
Худалдагч POST /payment-intents/{id}/unclaim — баталгаажаагүй claim-ийг суллана (хүн явчихсан, буруу хүн уншуулсан) дэлгэцийн өмнө гацах
Терминалын нэр, байршил Face ID-аас өмнө бүртгэлээс sticker солих
Идэвхгүй терминалын сагсыг token-оор ч төлөхгүй (409 terminal_disabled) унтраасан машин

Цаашид: NTAG 424 DNA tag-ийн SUN (уншуулах бүрт шинэ гарын үсэгтэй URL — утас машины дэргэд байгааг нотолно) — «удахгүй».

Машины дэлгэцийг «Утсаараа баталгаажуулна уу» төлвөөс 90 с-ийн дараа буцаах нь зөв.

5. Redirect-ийн return_url

  • Host нь апп-ын return_hosts-д (≤ 5, яг host — scheme, port, path, wildcard-гүй) бүртгэлтэй https хаяг. Буцах host-ыг review харсан байх ёстой тул return_hosts зөвхөн ноорог/татгалзсан үед өөрчлөгдөнө.
  • Апп төлсний дараа return_url-д зөвхөн ?pi=<intent id> нэмж нээнэ — үр дүн биш. Хэн ч энэ URL-ийг гараар бичиж болно: таны backend GET /payment-intents/{pi}-ээр status, amount, reference-ийг өөрийн захиалгатай тулгана.