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

Webhook — тойм

Төлбөр амжилттай болох, барьцаа (hold) тавигдах, хүн QR уншуулах, буцаалт дуусах зэрэг үйл явдлыг Gerege таны серверт POST хүсэлтээр мэдэгдэнэ. Энэ хуудсыг уншаад та webhook endpoint-оо нэмж, secret-ээ хадгалж, хэсгийн бусад хуудсыг хаана хэрэглэхээ мэдэнэ.

  • Хугацаа: 10–15 минут (endpoint нэмэх + гарын үсэг шалгах handler).
  • Хэрэгтэй: хөгжүүлэгчийн консолд бүртгэлтэй апп (mini app эсвэл худалдагч), нийтийн интернетээс хүрэх https хаяг, secret-ийг хадгалах газар (environment variable, secret manager — репо биш).

Заавал

payments scope-той апп ба бүх худалдагч review-д илгээхээс өмнө, мөн батлагдах үед идэвхтэй live webhook endpoint-тэй байх ёстой — endpoint №1 (webhook URL) эсвэл бусад аль нэг; унтраасан, автоматаар унтарсан endpoint тооцогдохгүй. Submit нь ийм endpoint-гүй апп-ыг 400 not_ready (path webhook_url) гэж буцаана.

1. Хэсгийн хуудсууд

Хуудас Юу
Гарын үсэг шалгах Gerege-Signature толгой, алгоритм, Node/Go/Python/PHP код, тест вектор
Хүргэлт ба давталт Endpoint бүрийн хүргэлт, шууд оролдлого, retry хуваарь, автомат унтраалт, дараалал
Idempotent handler Давхардлыг арилгах, хурдан 2xx, объектыг дахин унших — жишээ код
Event-ийн лавлах 12 event тус бүр: хэзээ, data.object, жишээ payload
Events API GET /events — алдсан event-ээ татах, webhook-гүй тулгах

2. Endpoint

Event-ийг хүлээн авах хаягийг endpoint гэнэ. Апп-ын орчин бүрт (test, live) 5 хүртэл endpoint; endpoint бүр өөрийн URL, тайлбар (≤ 200), event-ийн шүүлтүүр, өөрийн secret, хүргэлтийн лог, төлөвтэй.

  • Endpoint №1 нь апп-ын анхны webhook_url — хоёр орчинд хоёуланд нь нэг URL, нэг secret (legacy: true). Консолын апп-ын «Webhook» хэсэг ба POST /api/v1/miniapp/dev/apps/{id}/webhook {"url"} нь үүнийг тохируулна. Review-д илгээхэд заавал.
  • Нэмэлт endpoint — консолоос (/dev/apps/{id}/webhook-endpoints, орчныг сонгоно) эсвэл таны серверээс /webhook-endpoints API-аар (тухайн түлхүүрийн орчинд, доор §6).
  • Эрх (консол, 1.13.0): бичилт бүр miniapp.develop; live endpoint-ийн URL, secret солих, устгах (endpoint №1 болон POST …/webhook — хоёр орчных тул) miniapp.keys.live ба сүүлийн 10 минутын нэвтрэлт (403 fresh_sign_in_required). Тайлбар, шүүлтүүр, унтраах нь step-up шаардахгүй. Шүүж болох event-ийн жагсаалт mn/en нэртэйгээ: GET /api/v1/miniapp/dev/webhook-event-types.
  • Шүүлтүүр event_types: хоосон = бүх event; эсвэл ≤ 20 төрөл (давхардалгүй, webhook.test-ээс бусад). Шүүлтүүр event үүсэх агшинд шалгагдана — дараа нь өөрчилсөн ч өмнөх event-ийн хүргэлт өөрчлөгдөхгүй.
  • Төлөв status: active (хүлээн авна), disabled (та унтраасан), auto_disabled (5 хоног амжилтгүй тул платформ унтраасан — Хүргэлт). Идэвхгүй endpoint-д шинэ event хуваарилагдахгүй.
  • URL нь https://, ≤ 2048 тэмдэгт. Хүргэх үед хаягийг DNS-ийн дараа шалгана: дотоод сүлжээ, loopback, link-local хаяг руу хэзээ ч илгээхгүй — production-д endpoint нийтийн IP-тэй байна. Локал машин дээр туршихдаа tunnel ашигла (Локал webhook).
  • Test endpoint зөвхөн test event, live endpoint зөвхөн live event авна. Endpoint №1 хоёр орчинд нэг URL тул тэнд ирсэн event-ийг livemode-оор ялга; test event-ээр бараа олгохгүй.

Endpoint үүсгэх (консол):

POST /api/v1/miniapp/dev/apps/{id}/webhook-endpoints
Content-Type: application/json

{"environment": "live", "url": "https://api.example.mn/webhooks/gerege",
 "description": "ERP", "event_types": ["payment_intent.succeeded", "refund.succeeded"]}
{"endpoint": {"id": "we_…", "object": "webhook_endpoint", "environment": "live", "livemode": true,
  "url": "https://api.example.mn/webhooks/gerege", "description": "ERP",
  "event_types": ["payment_intent.succeeded", "refund.succeeded"], "status": "active", "disabled_reason": null,
  "legacy": false, "previous_secret_until": null, "failing_since": null, "last_success_at": null,
  "created_at": "…", "updated_at": "…"},
 "webhook_secret": "whsec_…", "notice": "Энэ secret-ийг дахин харуулахгүй — одоо хадгална уу"}

webhook_secret (whsec_…) зөвхөн энэ хариунд нэг удаа харагдана (Cache-Control: no-store). Платформ түүнийг битүүмжилж хадгалдаг — алдвал солино (§5). Жагсаалт (GET …/webhook-endpoints[?environment=]) endpoint бүрийн сүүлийн 24 цагийн deliveries_24h {delivered, failing}-ийг нэмж харуулна. Endpoint-ийн алдааны кодууд — Алдааны код.

3. Хүсэлт ямар харагдах

POST /webhooks/gerege HTTP/1.1
Content-Type: application/json
User-Agent: GeregeApp-Webhooks/1
Gerege-Event-Id: evt_Vec0000000000000000000001
Gerege-Signature: t=1792659600,v1=aab41441cf937428aac0a577ff2e0236b4e487b82c8a725afd2b1791cc2c9821
OpenPay-Event-Id: evt_Vec0000000000000000000001
OpenPay-Signature: t=1792659600,v1=aab41441cf937428aac0a577ff2e0236b4e487b82c8a725afd2b1791cc2c9821

{"id":"evt_Vec0000000000000000000001","type":"payment_intent.succeeded","created_at":"2026-10-22T09:00:00Z",
 "livemode":true,"app":"esim","data":{"object":{"id":"pi_4fQ2mX8kLp0aZr7TbN3cVw9E","object":"payment_intent", …}}}

OpenPay-* толгойнууд нь OMAS стандартын нэрээр ижил утга — OMAS-д бичсэн backend өөрчлөлтгүй шалгана. data.object нь API-ийн хариутай яг ижил хэлбэр (жишээ нь GET /payment-intents/{id}-ийнх). Нэг event хэд хэдэн endpoint руу очвол body нь ижил, гарын үсэг нь endpoint бүрийн secret-ээр.

Таны хийх гурван зүйл:

  1. Гарын үсгийг шалга — түүхий body дээр, тухайн endpoint-ийн secret-ээр (Гарын үсэг шалгах).
  2. 10 секундэд 2xx буцаа, ажлыг queue-д хий; id-аар давхардлыг арилга (Idempotent handler).
  3. Бараа олгох, захиалга хаахаас өмнө объектыг API-аас дахин унш — webhook бол дохио, эцсийн үнэн нь API.

4. Event-ууд

Товч жагсаалт; event бүрийн нөхцөл, data.object, жишээ payload — Event-ийн лавлах.

type Хэзээ data.object
payment_intent.succeeded Төлбөр амжилттай (automatic: баталгаажуулсны дараа; manual: capture-ийн дараа) PaymentIntent
payment_intent.requires_capture Manual intent-ийн мөнгө барьцаалагдсан — capture эсвэл cancel хий PaymentIntent
payment_intent.canceled Цуцлагдсан; app intent-ийн хугацаа дуусахад ч (status: "expired") PaymentIntent
payment_intent.failed Баталгаажуулалт эсвэл capture амжилтгүй (failure_code) PaymentIntent
payment_intent.claimed Хүн claimless (qr/redirect/terminal) intent-ийг өөртөө авсан PaymentIntent
payment_intent.expired Claimless intent-ийн хугацаа дууссан PaymentIntent
refund.succeeded · refund.failed Буцаалт дууссан / татгалзсан Refund
app.status_changed Апп-ын status эсвэл review_status өөрчлөгдсөн AppStatus
consent.revoked Хүн апп-аа салгасан Consent
settlement.paid Тооцоо payout данс руу шилжсэн (үргэлж live) Settlement
webhook.test Консолоос тест илгээлт (үргэлж test) WebhookTest

Мэдэхгүй type-д 2xx хариулж үл тоомсорло — minor хувилбар шинэ event нэмж болно.

5. Secret ба солих

Үйлдэл Юу болох
POST …/webhook-endpoints/{eid}/rotate-secret Тухайн endpoint-д шинэ secret (хариунд нэг удаа). Хуучин нь 24 цаг хамт гарын үсэг зурна: event бүрт хоёр v1 — эхэнд шинэ, дараа нь хуучин. Endpoint-ийн previous_secret_until хэзээ дуусахыг хэлнэ. Тэр хугацаанд шинэ secret-ээ deploy хий — нэг ч event алдагдахгүй.
Endpoint №1: url-тэй POST …/webhook (URL өөрчлөөгүй ч) №1-д шинэ secret, хуучин нь 24 цаг хамт (хоёр орчинд хоёуланд).
DELETE …/webhook-endpoints/{eid} · №1-д {"url": null} Endpoint, түүний secret устна; хүлээгдэж байсан хүргэлтүүд нь хамт устна. Event өөрөө Events API-д үлдэнэ.
  • URL, secret нь хүргэх агшинд уншигдана — өөрчлөлт хуучин event-ийн дараагийн retry-д ч хэрэгжинэ.
  • Шилжилтийн үед хүлээн авагч талд [шинэ, хуучин] хоёуланг нь зөвшөөр (SDK-ууд secret-ийн жагсаалт авна), deploy дууссаны дараа хуучныг хас. Endpoint тус бүрийн secret өөр — хоёр endpoint нэг handler-т ирдэг бол хоёуланг нь зөвшөөр.
  • Түдгэлзсэн (suspended) апп-ын endpoint-ийг өөрчлөх боломжгүй (409 suspended); review-д буй апп-ын endpoint №1-ийн URL, secret-ийг ч (409 locked_for_review).
  • Суулгацад secret битүүмжлэх түлхүүр тохируулаагүй бол 503 no_secret_key — secret хэзээ ч ил хадгалагдахгүй.
  • Өөрчлөлт бүр апп-ын audit-д бичигдэнэ; secret өөрөө хэзээ ч биш.

6. Таны серверээс удирдах — /webhook-endpoints

IaC, deploy script-ээс endpoint-оо тохируулахад: https://geregeapp.mn/api/v1/miniapp/webhook-endpoints, Basic (API түлхүүр), scope webhooks:write — энэ scope зөвхөн live түлхүүрт олгогддог; test түлхүүр 403 live_only авна (test endpoint-ийг консолоос). Түлхүүр зөвхөн өөрийн орчны endpoint-ийг харж, үүсгэнэ (environment-ийг орхи, эсвэл түлхүүрийнхтэй ижил; өөр бол 403 environment_mismatch).

Method Зам
GET · POST /webhook-endpoints {"data": [WebhookEndpoint], "next_cursor": null} · 201 {endpoint, webhook_secret, notice}
GET · PATCH · DELETE /webhook-endpoints/{eid} PATCH: url, description, event_types, status (active | disabled) · DELETE → 204
POST /webhook-endpoints/{eid}/rotate-secret 200 {endpoint, webhook_secret, notice}
POST /webhook-endpoints/{eid}/test Гарын үсэгтэй webhook.test-ийг тэр endpoint руу одоо илгээж үр дүнг хариулна (20/мин)

Консол ижил үйлдлүүдийг /dev/apps/{id}/webhook-endpoints… дор аль ч орчинд хийнэ. auto_disabled endpoint-ийг PATCH {"status": "active"}-ээр асаана (алдсан event-ээ Events API-аас татсаны дараа). Түлхүүр ба scope — Аюулгүй байдлын загвар, бүх route — API-ийн нийтлэг дүрэм.