gov-pay
Жишээ / Tutorials

End-to-end интеграц

Нэхэмжлэл хайхаас эхлээд төлбөр баталгаажих хүртэлх бүрэн урсгалыг алхам алхмаар үзүүлэв.

Энэ заавар нь gov-pay channel API-г интеграцлах бүрэн урсгалыг 6 алхамаар харуулна: API key авах, нэхэмжлэл хайх, төлбөр үүсгэх, QR/deeplink харуулах, webhook бүртгэх, статус баталгаажуулах. Алхам бүрт curl жишээ дагалдана.

Энэ хуудсан дахь жишээнүүд Sandbox орчныг (https://sandbox-tts.qpay.mn/api/v1) ашиглана. Бүх зам /api/v1 угтвартай.

Бүх endpoint (зөвхөн /health/*-аас бусад) X-API-Key header шаардана. Key байхгүй/буруу бол 401, партнёр идэвхгүй бол 403 буцна. Дэлгэрэнгүйг Алдааны кодууд-оос үзнэ үү.

Алхам 1 — API key авах

Интеграц эхлүүлэхийн тулд gov-pay-тэй холбогдож партнёрын бүртгэл нээлгэн, Sandbox орчны X-API-Key авна. Энэ key-г бүх хүсэлтэд header болгон дамжуулна.

export GOVPAY_BASE="https://sandbox-tts.qpay.mn/api/v1"
export GOVPAY_KEY="<таны-api-key>"

Key зөв ажиллаж байгааг шалгахын тулд auth шаарддаггүй /health/live-ийг дуудна (энд key хэрэггүй):

curl "$GOVPAY_BASE/health/live"
# { "status": "...", "timestamp": "..." }

Rate limit нь API key тус бүрд: 5/сек, 60/мин, 1000/цаг. Хэтэрвэл 429 буцна.

Алхам 2 — Нэхэмжлэл хайх

GET /invoices нь ЯГ нэг шүүлтүүр шаардана: ttd (ТТД/регистр), vehicle (улсын дугаар), эсвэл taxRef. Хоёр шүүлтүүр зэрэг өгвөл, эсвэл нэг ч өгөхгүй бол 400 буцна.

curl -H "X-API-Key: $GOVPAY_KEY" \
  "$GOVPAY_BASE/invoices?ttd=12345678"

Хариу:

{
  "invoices": [
    {
      "id": "3f1c2b9a-7e44-4c8a-9b21-1f2e3d4c5b6a",
      "description": "Тээврийн хэрэгслийн албан татвар 2026",
      "amount": 45000,
      "status": "open",
      "dueDate": "2026-07-01",
      "issuedAt": "2026-06-01",
      "vehicleNo": "1234УБА",
      "payer": { "register": "АА12345678", "name": "Бат" },
      "payee": { "id": "mof-001", "name": "Татварын ерөнхий газар" },
      "year": 2026
    }
  ],
  "total": 45000
}

Хариун дахь total нь нэхэмжлэлийн дүнгийн НИЙЛБЭР (₮), тоо ширхэг БИШ. Дараагийн алхамд төлөх нэхэмжлэлийн id-г энэ жагсаалтаас авна.

Тодорхой нэхэмжлэлийг дэлгэрэнгүй харах хэрэгтэй бол:

# DB cache-аас (төрийн систем рүү дуудалтгүй, хурдан)
curl -H "X-API-Key: $GOVPAY_KEY" \
  "$GOVPAY_BASE/invoices/3f1c2b9a-7e44-4c8a-9b21-1f2e3d4c5b6a"

# Төрийн системээс ШИНЭЭР татах (хамгийн сүүлийн төлөв)
curl -H "X-API-Key: $GOVPAY_KEY" \
  "$GOVPAY_BASE/invoices/3f1c2b9a-7e44-4c8a-9b21-1f2e3d4c5b6a/refresh"

Алхам 3 — Төлбөр үүсгэх

POST /payments нь PUBLIC API-д ЯГ НЭГ нэхэмжлэлийг авна. Body нь { invoiceId, amount? } (массив биш). amount нь сонголттой; хэрэв алгасвал нэхэмжлэлийн бүрэн дүнг ашиглана.

Идемпотентность хангахын тулд X-Idempotency-Key header дамжуул. Энэ key болгож өөрийн хүсэлтийн UUID-г ашигла — сүлжээний алдаа/давталтын үед нэг л төлбөр үүснэ. Дэлгэрэнгүйг Төлбөр-өөс үзнэ үү.

curl -X POST -H "X-API-Key: $GOVPAY_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: 9b8c7d6e-5f4a-3b2c-1d0e-9f8a7b6c5d4e" \
  -d '{ "invoiceId": "3f1c2b9a-7e44-4c8a-9b21-1f2e3d4c5b6a" }' \
  "$GOVPAY_BASE/payments"

Амжилттай үед 201:

{
  "success": true,
  "id": "a1b2c3d4-0000-1111-2222-333344445555",
  "status": "submitted",
  "amount": 45000,
  "invoiceId": "3f1c2b9a-7e44-4c8a-9b21-1f2e3d4c5b6a",
  "invoiceIds": ["3f1c2b9a-7e44-4c8a-9b21-1f2e3d4c5b6a"],
  "qpay": {
    "qrText": "00020101...",
    "qrImage": "<base64-png>",
    "shortUrl": "https://...",
    "urls": [
      { "name": "Khan Bank", "description": "...", "logo": "https://...", "link": "khanbank://..." }
    ]
  }
}

Амжилтгүй бол 422:

{ "success": false, "refNum": "...", "message": "..." }

Төлбөрийн статус: pendingsubmittedconfirmed. submitted = төрийн системд илгээгдсэн, confirmed = MoF баталсан (төлөгдсөн). Эсвэл failed / canceled. canceled үед холбогдсон нэхэмжлэлүүд open руу буцна.

gov-pay нь EMVCo QR болон банкны deeplink-ийг СЕРВЕР талд бүрэн угсарч qpay объектоор буцаана. Партнёр өөрөө QR угсрах шаардлагагүй.

  • qpay.qrText — EMVCo QR-ийн түүхий текст (өөрийн QR renderer ашиглах бол).
  • qpay.qrImage — base64 PNG. Дэлгэцэнд харуулахдаа data: URI болгоно:
const img = document.createElement("img");
img.src = `data:image/png;base64,${payment.qpay.qrImage}`;
document.body.appendChild(img);
  • qpay.urls[] — банк/wallet тус бүрийн deeplink. Гар утасны апп дээр товч/жагсаалт болгон үзүүлнэ:
payment.qpay.urls.forEach((u) => {
  // u.name, u.description, u.logo, u.link
  renderBankButton({ label: u.name, icon: u.logo, href: u.link });
});

QR стандартыг (qpay — EMVCo tag 27, эсвэл govstd — tag 26) партнёрын qrStandard тохиргоо тодорхойлно. Үүнийг солихыг хүсвэл gov-pay-тэй холбогдоно уу.

Алхам 5 — Webhook бүртгэх ба payment.confirmed хүлээх

Хэрэглэгч банкны апп-аар төлснийг real-time мэдэхийн тулд webhook бүртгэнэ. url, secret, болон сонирхох events[]-ийг өгнө. Боломжит event: payment.submitted, payment.confirmed.

curl -X POST -H "X-API-Key: $GOVPAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://partner.example.com/govpay/webhook",
    "secret": "<таны-нууц-түлхүүр>",
    "events": ["payment.submitted", "payment.confirmed"]
  }' \
  "$GOVPAY_BASE/webhooks"

Хариу нь secret-ийг агуулсан WebhookDto болно. Энэ secret-ийг хадгал — хүргэгдсэн event бүрийн HMAC-SHA256 гарын үсгийг шалгахад ашиглана.

Хүргэлтийн үед gov-pay дараах header илгээнэ:

  • X-GovPay-Event — event-ийн нэр (ж: payment.confirmed).
  • X-GovPay-Signature — биеийн HMAC-SHA256, таны secret-ээр.

payment.confirmed event-ийн payload нь { id, amount }. Таны endpoint:

  • 5 секундын дотор хурдан 2xx буцаах ёстой.
  • idempotent байх ёстой — payment id-аар давхардлыг шүүнэ.
  • Гарын үсгийг заавал шалгана — Гарын үсэг шалгах-ийг үзнэ үү.

Webhook-ийн нарийвчилсан зааврыг Webhook тойм-оос үзнэ үү.

Алхам 6 — Статус баталгаажуулах

Webhook ирсэн (эсвэл санамсаргүй алдсан) тохиолдолд төлбөрийн төлөвийг GET /payments/{id}-аар эцэслэн баталгаажуулна. Энэ нь webhook-ийн найдвартай нөөц (reconciliation) болж өгнө.

curl -H "X-API-Key: $GOVPAY_KEY" \
  "$GOVPAY_BASE/payments/a1b2c3d4-0000-1111-2222-333344445555"
{
  "id": "a1b2c3d4-0000-1111-2222-333344445555",
  "status": "confirmed",
  "amount": 45000,
  "invoiceId": "3f1c2b9a-7e44-4c8a-9b21-1f2e3d4c5b6a",
  "invoiceIds": ["3f1c2b9a-7e44-4c8a-9b21-1f2e3d4c5b6a"],
  "paidAt": "2026-06-29T10:15:00Z"
}

status: "confirmed" бол төлбөр амжилттай төлөгдсөн гэсэн үг. Энэ үе шатанд хэрэглэгчид амжилтын дэлгэц харуулна.

Webhook-ийг үнэний эх сурвалж болгон ашиглаж, GET /payments/{id}-аар баталгаажуулна. Webhook болон API хоёрыг хослуулснаар нэг ч баталгаажилт алдагдахгүй.

Бүхэл урсгал

Дараагийн алхам