Терминалаар test төлбөр (sticker, NFC, машин)¶
Юу хийх: байнгын терминал (QR sticker / NFC tag / вендинг машин) бүртгэж, түүнд test сагс уяж, «уншуулаад» барьцаалж, capture эсвэл cancel хийнэ. Хугацаа: ~10 минут, Quickstart-ийн §1–§5-ыг хийсэн бол. Мөнгө хөдлөхгүй.
qr-аас ялгаа: QR/sticker нь терминалыг л нэрлэнэ, дүнг хэзээ ч биш. Дүн нь тухайн мөчид терминалд уясан нэг
нээлттэй intent-ээс ирнэ. Ойлголт: Худалдагч, дэд худалдагч, терминал.
1. Бэлтгэл¶
Quickstart-аас дараах хувьсагчид бэлэн байна: GEREGE, GEREGE_SESSION, APP_ID,
GEREGE_CLIENT_ID / GEREGE_CLIENT_SECRET (test түлхүүр, payments:*), ажиллаж байгаа webhook.py ба tunnel.
2. Терминал бүртгэх (консолоос)¶
Терминал, дэд худалдагч нь хоёр орчинд нэг бүртгэл — тиймээс бичих нь зөвхөн live түлхүүр эсвэл консол;
test түлхүүрээр POST /terminals → 403 live_only (алдагдсан sandbox secret бодит машиныг өөрчлөхгүй). Sandbox-д
консолын API-аар бүртгэнэ:
curl -sS "$GEREGE/dev/apps/$APP_ID/terminals" \
-H "Authorization: Bearer $GEREGE_SESSION" -H 'Content-Type: application/json' \
-d '{"label": "Тест машин", "location": "Оффис, 3 давхар", "reference": "test-vm-1"}' | tee terminal.json | jq
export TERMINAL_ID=$(jq -r .id terminal.json)
export TERMINAL_CODE=$(jq -r .code terminal.json)
{
"id": "4b8e2f0a-7c1d-4e3b-9a6f-2d5c8e1b7a90",
"object": "terminal",
"code": "7k2m9x4q3p",
"url": "https://geregeapp.mn/pay/t/7k2m9x4q3p",
"label": "Тест машин",
"location": "Оффис, 3 давхар",
"reference": "test-vm-1",
"sub_merchant": null,
"status": "active",
"created_at": "2026-10-27T03:00:00Z",
"updated_at": "2026-10-27T03:00:00Z"
}
reference— таны машины дугаар, апп дотор өвөрмөц: ижилreference-ээр дахинPOST→ тэр терминал200.codeсерверийнх, хэзээ ч өөрчлөгдөхгүй.url-ийг sticker-ийн QR ба NFC tag-ийн NDEF URI record болгоно.label,locationнь хүний төлөх цонхонд Face ID-аас өмнө гарна (бүртгэлээс — sticker дээрх бичгээс биш).
3. Sticker¶
Туршилтад QR-ээ өөрөө зурна: qrencode -o sticker.png "$(jq -r .url terminal.json)" (эсвэл дурын QR үүсгэгч).
Серверээс хэвлэх хуудас (PDF: QR + нэр + код) — «удахгүй». NFC tag бичих, sticker сонгох заавар — «удахгүй»
(Guides-ийн терминалын хуудас).
4. Сагс уях¶
Сагс бүрт таны сервер терминалд intent уяна — manual capture, богино capture_within:
curl -sS "$GEREGE/payment-intents" -u "$GEREGE_CLIENT_ID:$GEREGE_CLIENT_SECRET" \
-H 'Content-Type: application/json' -H 'Idempotency-Key: basket-2001' \
-d "{\"amount\": 2500, \"description\": \"Захиалга №2001\", \"reference\": \"basket-2001\",
\"presentment\": \"terminal\", \"terminal_id\": \"$TERMINAL_ID\", \"expires_in\": 120,
\"capture_method\": \"manual\", \"capture_within\": 120}" | tee basket.json | jq '{id, status, presentment, terminal, capture_within}'
export PI=$(jq -r .id basket.json)
{ "id": "pi_3Fk9Lm2Qw8Er5Ty7Ui1Op4As", "status": "requires_confirmation", "presentment": "terminal",
"terminal": "4b8e2f0a-7c1d-4e3b-9a6f-2d5c8e1b7a90", "capture_within": 120 }
Терминалд claim хийгдээгүй нээлттэй intent орчин бүрт нэг. Хоёр дахь сагс:
curl -sS "$GEREGE/payment-intents" -u "$GEREGE_CLIENT_ID:$GEREGE_CLIENT_SECRET" \
-H 'Content-Type: application/json' -H 'Idempotency-Key: basket-2002' \
-d "{\"amount\": 1800, \"description\": \"Захиалга №2002\", \"presentment\": \"terminal\",
\"terminal_id\": \"$TERMINAL_ID\", \"capture_method\": \"manual\"}" | jq
Нэг sticker дээр хоёр сагс байвал хүн аль машины өмнө зогсож байгаагаа сонгох болно — тиймээс эхлээд хуучныг
POST /payment-intents/{id}/cancel хийгээд дахин үүсгэнэ. Test сагс live сагсыг хаахгүй (орчин тусдаа).
5. Уншуулах (claim) ба төлөх¶
Утсаар уншуулах
Gerege App (iOS)-ын апп доторх QR товч ба «NFC уншуулах» нь терминалыг claim хийнэ — TestFlight 121-ээс хойшх build-д (test сагсыг «ТЕСТ» тэмдэгтэй). Камераар/ар талын NFC-ээр (Universal Link) ба App Clip — «удахгүй». Тэр build байхгүй бол апп-ын хийх дуудлагыг өөрийн session-ээр хийнэ. Терминалаар claim хийхэд апп-ын эзэн ба тест хэрэглэгчид test сагсыг эхэлж, бусад хүн зөвхөн live-ийг авна.
curl -sS "$GEREGE/payments/claim" -H "Authorization: Bearer $GEREGE_SESSION" \
-H 'Content-Type: application/json' -d "{\"terminal\": \"$TERMINAL_CODE\"}" \
| jq '{id, status, merchant, terminal, sub_merchant}'
{ "id": "pi_3Fk9Lm2Qw8Er5Ty7Ui1Op4As", "status": "requires_confirmation",
"merchant": {"slug": "my-shop-test", "name": "Миний дэлгүүр", "icon_url": ""},
"terminal": {"label": "Тест машин", "location": "Оффис, 3 давхар"}, "sub_merchant": null }
Webhook: payment_intent.claimed. Машин «Утсаараа баталгаажуулна уу» гэж харуулна. Төлөх:
export ACCOUNT=$(curl -sS https://geregeapp.mn/api/v1/bank/me/accounts \
-H "Authorization: Bearer $GEREGE_SESSION" | jq -r '.accounts[0].id')
curl -sS -X POST "$GEREGE/payments/$PI/confirm" -H "Authorization: Bearer $GEREGE_SESSION" \
-H 'Content-Type: application/json' -H "Idempotency-Key: confirm-$PI" \
-d "{\"account_id\": \"$ACCOUNT\"}" | jq '{status}'
{"status": "requires_capture"} ба webhook payment_intent.requires_capture — машинд «гарга» гэх дохио.
6. Гарсан бол capture, гараагүй бол cancel¶
# бараа гарсан:
curl -sS -X POST "$GEREGE/payment-intents/$PI/capture" -u "$GEREGE_CLIENT_ID:$GEREGE_CLIENT_SECRET" | jq '{status}'
# эсвэл гараагүй:
curl -sS -X POST "$GEREGE/payment-intents/$PI/cancel" -u "$GEREGE_CLIENT_ID:$GEREGE_CLIENT_SECRET" | jq '{status}'
| Машины үр дүн | Таны дуудлага | Төлөв · webhook |
|---|---|---|
| Бүгд гарсан | capture |
succeeded · payment_intent.succeeded |
| Юу ч гараагүй | cancel |
canceled · payment_intent.canceled (барьцаа хүнд буцна — буцаалт биш) |
| Хэсэгчлэн | capture бүтэн + POST …/refunds {"amount": <гараагүйн үнэ>} |
succeeded → partially_refunded (дүнтэй хэсэгчилсэн capture «удахгүй») |
| Хариу ирээгүй (offline) | — | capture_within өнгөрөхөд expired · payment_intent.expired, failure_code: "authorization_expired", барьцаа өөрөө суллагдана |
Хүн уншуулаад явчихвал баталгаажаагүй claim 90 с-д дуусч, дараагийн хүн авна; эсвэл таны сервер
POST /payment-intents/{id}/unclaim хийнэ. Нэг хүн нэг дор 3-аас олон баталгаажаагүй claim барихгүй
(429 too_many_open_claims).
7. Нийтийн харагдац¶
Sticker-ийн хаягийг компьютер дээр нээсэн хүнд үзүүлэх мэдээлэл (session-гүй, хувийн мэдээлэлгүй):
{ "object": "terminal", "merchant": {"name": "Миний дэлгүүр", "icon_url": ""},
"terminal": {"code": "7k2m9x4q3p", "label": "Тест машин", "location": "Оффис, 3 давхар"},
"pending": null }
pending нь зөвхөн live нээлттэй сагс (test сагс нийтэд хэзээ ч гарахгүй). Тайлбар, reference, хэн claim хийсэн —
энд хэзээ ч байхгүй.
8. Дараа нь¶
- Олон эзэмшигчтэй машинууд (эзэмшигч бүрт тусдаа тооцоо): Худалдагч, дэд худалдагч, терминал.
- Бүрэн API, Node/Go жишээ: Gerege App-аар төлөх.
- Барьцааны хугацааг яаж сонгох: Төлбөрийн амьдралын мөчлөг.