PayGrid · paygrid.mn

Танилцуулга / QR Switch

QR Switch — MNQR profile

EMVCo MPQR + CPQR-аар verbatim adopt + Mongol-аар "MNQR" profile. Tag 81 mn.paygrid:// pay_uri-аар Deeplink ≡ QR ≡ NFC architectural unity. UPI / PIX / PromptPay / DuitNow / VietQR pattern-аас сурсан.

1. Яагаад QR Switch хэрэгтэй вэ

Mongol-ын одоогийн QR landscape

  • QPay (Hi Payment Solutions) — closed-loop, EMVCo MPQR-аар ч QPay-ын merchant-уудаар л; T+1 acquirer-аар settlement
  • Bank-аар бие даасан QR-ууд (Khan QR, Golomt QR, Most QR) — bank тус тусдаа онбоординг; cross-bank ажиллахгүй; fragmented
  • Switch / NPS — QR-аар суурилсан гүйлгээ дэмждэггүй

Gap

  • Universal QR байхгүй: нэг QR-аар бүх wallet/bank app-аас scan хийж pay
  • IBAN-based routing байхгүй: direct A2A settlement
  • Cross-PSP merchant acceptance байхгүй: bank-аар тус тусдаа гэрээ

PayGrid QR Switch-аар нэмэх value

  • Universal MNQR: нэг QR-аар бүх wallet/bank-аас pay
  • Direct IBAN A2A routing — Berlin Group NextGenPSD2 backbone-аар
  • Cross-PSP merchant: мерчант нэг PSP-аас бүртгэгдсэн ч бүх PSP-аас pay
  • EMVCo verbatim conformance — interoperable globally
  • Deeplink ≡ QR ≡ NFC unity (architectural)
  • Static + Dynamic + CPQR гурвыг хослуулсан

2. Олон улсын analog

ОронQR SwitchOperatorCoverage
ЭнэтхэгUPI QR / BharatQRNPCIUniversal
СингапурSGQRABS-MASUniversal
ТайландPromptPay QRBoTUniversal
БразилPIX QRBCBUniversal
ИндонезQRISBank IndonesiaUniversal
МалайзDuitNow QRPayNetUniversal
ВьетнамVietQRNAPASUniversal
Монгол(QPay closed-loop одоо)
Монгол (PayGrid proposal)MNQRPayGrid LLCUniversal

3. Стандартууд

EMVCo QR Code Specification for Payment Systems:
   ─ Merchant-Presented Mode (MPQR) — мерчант QR харуулна, consumer scan
   ─ Consumer-Presented Mode (CPQR) — consumer QR харуулна, мерчант scan

Common features:
   ─ TLV (Tag-Length-Value) encoding
   ─ CRC-16/CCITT-FALSE checksum
   ─ UTF-8 string support
   ─ QR error correction Level M (15%)

Versions:
   ─ MPQR v1.1 (2018-аас)
   ─ CPQR v1.0 (2017-аас)
LayerStandard
QR encodingEMVCo MPQR v1.1 + CPQR v1.0
QR symbologyISO/IEC 18004
ChecksumCRC-16/CCITT-FALSE
CurrencyISO 4217 (MNT = 496)
Country codeISO 3166-1 (MN)
Merchant Category CodeISO 18245
SettlementISO 20022 pacs.008
URI schememn.paygrid://pay?...

4. EMVCo TLV layout (MNQR profile)

4.1 Static MPQR (sticker — no amount)

00 02 01            Payload Format Indicator (PFI) = "01"
01 02 11            Point of Initiation Method = "11" (static)
26 60               Merchant Account Information template (ID 26)
   00 12  mn.paygrid                       Globally Unique Identifier
   01 28  MN20910010000000XXXX             IBAN (creditor account)
   02 11  GWMNUBXX                         BIC (creditor agent)
   03 16  cafemonkey@gerege                Alias (optional)
52 04 5814          Merchant Category Code = 5814 (Restaurants)
53 03 496           Currency = 496 (MNT)
58 02 MN            Country = MN
59 13 CAFE MONKEY   Merchant Name (max 25)
60 09 ULAANBAATAR   Merchant City (max 15)
62 11               Additional data field template
   01 09  REF202605                        Reference label
63 04 ABCD          CRC-16/CCITT-FALSE checksum

4.2 Dynamic MPQR (one-time, amount + nonce)

00 02 01            PFI
01 02 12            POI = "12" (dynamic)
26 60               Merchant Account Information template
   00 12  mn.paygrid
   01 28  MN20910010000000XXXX
   02 11  GWMNUBXX
52 04 5814          MCC
53 03 496           Currency
54 06 100000        Transaction Amount = 100,000 ₮
58 02 MN
59 13 CAFE MONKEY
60 09 ULAANBAATAR
62 27               Additional data field
   01 09  REF202605
   05 0E  ord-12345-abc                    Bill / order ID
   07 0A  GW2026XXXX                       Reference number
81 4F               PayGrid Tag 81 — pay_uri
   mn.paygrid://pay?pa=cafemonkey@gerege&pn=Cafe%20Monkey
   &am=100000&cu=MNT&tr=ord-12345-abc&nonce=ABCD1234
   &exp=1714660800&sig=...
63 04 ABCD          CRC checksum

4.3 CPQR (Consumer-Presented)

Гол ялгаа: CPQR нь нэг удаа dynamic, expire window богино (≤5 мин):

00 02 01             PFI
49 56                Consumer Account Information template (ID 49)
   00 12  mn.paygrid
   01 28  MN10080010100012345678            Debtor IBAN
   02 11  KHANUBXX                          Debtor agent BIC
   03 16  eddy@gerege                       Consumer alias
   04 12  <ephemeral-token>                One-time token
52 04 0000           MCC = generic
53 03 496            Currency
58 02 MN
62 17                Additional data
   05 0E  ref-2026-04-30-001
81 5C                pay_uri
   mn.paygrid://pay?pa=eddy@gerege&consumer&token=...&exp=...
63 04 ABCD           CRC

5. Tag 81 — pay_uri (PayGrid Mongol extension)

EMVCo нь Tag 80-99-аар RFU-merchant defined range. PayGrid Tag 81-ийг URI-аар сонгосон.

Tag 81: pay_uri (URI string)
Value:  mn.paygrid:// URI containing payment parameters

Why?
   1. URI-аар QR-аас гадна Universal Link / NFC NDEF / SMS-аар
      явуулах боломж
   2. App-to-app handoff (bank/wallet app handle URI-аар)
   3. Deeplink ≡ QR ≡ NFC architectural unity

Routing logic:
   def handle_qr(tlv):
       if tlv.has_tag(81):
           pay_uri = tlv.get_tag(81)
           if user.has_default_bank_app and prefers_bank_handoff:
               return route_to_bank_app(pay_uri)   # Universal Link
       # Default: PayGrid-аар IBAN-аас IBAN routing
       return route_via_paygrid(tlv)
Compatibility

Tag 81-ыг unaware EMVCo parser хэвшсэнээр (TLV-аар skip-аар) read-аар алдалгүй уншиж pass хийж чадна. Энэ нь vanilla EMVCo conformance-аас зөрчилгүй.

6. QR Switch ажиллах flow

6.1 MPQR scenario (хамгийн их volume)

  1. Cafe Monkey static QR sticker

    Онбоординг үед үүсгэгдсэн.

  2. Бат wallet app-аас scan хийнэ

  3. Wallet app TLV parse

    Extract: IBAN, BIC, MCC.

  4. Дүн оруулна

    "Cafe Monkey-руу төлөх — Дүн оруулна уу" → 25,000 ₮.

  5. Wallet → PayGrid: POST /v1/qr/resolve

    Response: iban, psp_bic, alias, kyc_level, merchant_name.

  6. Wallet → PayGrid: POST /v1/payments/sepa-credit-transfers

    с creditorAlias=cafemonkey@gerege.

  7. Standard PayGrid flow

    Wallet-ын bank PISP API → SCA via e-ID Mongolia → bank pacs.008 → PayGrid → Cafe Monkey's PSP credit.

  8. Bank webhook → Wallet → "Paid"

    Cafe Monkey notification (via PSP).

6.2 Dynamic MPQR (POS-аас generated)

POST /v1/qr/dynamic/create
{
  "creditor_iban": "MN20910010000000XXXX",
  "creditor_psp_bic": "GWMNUBXX",
  "amount_minor": 100000,
  "currency": "MNT",
  "merchant_category_code": "5814",
  "reference": "ord-12345-abc",
  "ttl_seconds": 300,
  "callback_url": "https://merchant.example.com/qr-callback/ord-12345"
}

Response:
{
  "qr_id": "qr_dyn_660f9510...",
  "qr_payload": "00020112...63048CD7",
  "qr_image_url": "https://api.paygrid.mn/qr/qr_dyn_660f9510.png",
  "expires_at": "2026-05-06T14:28:00Z",
  "pay_uri": "mn.paygrid://pay?...",
  "deeplink_universal": "https://api.paygrid.mn/p/qr_dyn_660f9510"
}

6.3 CPQR scenario (high-volume retail)

  1. User wallet app-аас "Pay" товч → CPQR generate
  2. POS scanner-аар QR уншина
  3. POS → PayGrid: /v1/qr/resolve + /v1/payments/sepa-credit-transfers
  4. User → bank app SCA (e-ID Mongolia)
  5. Settlement, webhook to POS

7. QR endpoint specs

POST /v1/qr/resolve

Request:
{
  "qr_payload": "00020101...63048CD7",
  "psu_ip_address": "203.0.113.42"
}

Response (200):
{
  "qr_type": "MPQR_STATIC",
  "creditor_iban": "MN20910010000000XXXX",
  "creditor_psp_bic": "GWMNUBXX",
  "creditor_alias": "cafemonkey@gerege",
  "creditor_name_display": "Cafe Monkey",
  "merchant_category_code": "5814",
  "merchant_city": "ULAANBAATAR",
  "kyc_level": "QUALIFIED",
  "verified_business": true,
  "amount_minor": null,            // null for static
  "currency": "MNT",
  "reference": "REF202605",
  "expires_at": null,
  "pay_uri": "mn.paygrid://pay?pa=cafemonkey@gerege&...",
  "frm_score": 0.05,
  "frm_warnings": []
}

Алдааны код

400 invalid_qr_formatTLV parse failure
400 invalid_qr_checksumCRC mismatch
404 unknown_creditorIBAN/alias not in registry
410 qr_expiredDynamic QR past expiry
422 qr_blockedSanctions match or revoked alias

Бусад endpoint

POST   /v1/qr/static/create     Generate static MPQR
POST   /v1/qr/dynamic/create    Generate one-time dynamic MPQR (POS)
POST   /v1/qr/cpqr/generate     Generate Consumer-Presented QR
GET    /v1/qr/{qr_id}/status    QR status
DELETE /v1/qr/{qr_id}           Cancel/revoke QR

8. Database schema (qr_codes)

CREATE TYPE qr_type AS ENUM (
    'MPQR_STATIC', 'MPQR_DYNAMIC', 'CPQR'
);

CREATE TYPE qr_status AS ENUM (
    'CREATED', 'SCANNED', 'PAID', 'EXPIRED', 'CANCELLED'
);

CREATE TABLE qr_codes (
    qr_id              VARCHAR(40) PRIMARY KEY,
    type               qr_type NOT NULL,
    creditor_iban      VARCHAR(34),
    creditor_alias     VARCHAR(128),
    creditor_psp_bic   CHAR(11),
    debtor_iban        VARCHAR(34),
    debtor_psp_bic     CHAR(11),
    amount_minor       BIGINT,
    currency           CHAR(3) NOT NULL DEFAULT 'MNT',
    merchant_category  CHAR(4),
    reference          VARCHAR(50),
    qr_payload         TEXT NOT NULL,
    pay_uri            TEXT,
    status             qr_status NOT NULL DEFAULT 'CREATED',
    expires_at         TIMESTAMPTZ,
    callback_url       VARCHAR(500),
    payment_id         VARCHAR(40) REFERENCES payments(payment_id),
    scanned_at         TIMESTAMPTZ,
    paid_at            TIMESTAMPTZ,
    created_at         TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

9. QPay parity / migration path

Phase 1: Coexistence (2026 Q4 - 2027 Q1)

  • MNQR launched
  • QPay continues operating
  • Wallets accept BOTH QPay and MNQR formats
  • Merchants can choose

Phase 2: Convergence (2027 Q2-Q3)

  • QPay merchants get free MNQR conversion
  • Hi Payment Solutions optionally joins PayGrid as PSP-аар (so QPay merchants become MNQR-routed)
  • Cross-acceptance via aliasing

Phase 3: Sunset (2027 Q4+)

  • QPay-only QRs deprecated
  • All merchants on MNQR via their PSP
  • Single national QR standard

QPay → MNQR translation

QPay merchant IDPayGrid alias (qpay-merchant-12345@hipayment)
QPay invoice (one-time)Dynamic MPQR with TTL
QPay static QRStatic MPQR via API
QPay settlement (T+1)PayGrid DNS settlement (T+0 net)
QPay acquirer feePayGrid 0.3% capped

10. Security (QR-specific)

Anti-tampering

  • Static QR: CRC-16, optional pay_uri JWS by PSP, anti-sticker-swap (regular sweeps + verified business badge)
  • Dynamic QR: Nonce + expiry in pay_uri, server-side single-use state, replay detection (PAID status check)

Anti-phishing

  • pay_uri verifies against PayGrid DICT
  • Wallet app shows verified business badge for QUALIFIED merchants
  • Confirmation of Payee on resolve
  • Suspicious URL warning (TLD typo, near-miss alias)

Sanctions

  • /v1/qr/resolve calls FRM engine
  • If creditor on sanctions list: 422 + audit + alert ops
  • Daily refresh: re-screen all active QRs

Privacy

  • Static QR contains only: alias, IBAN (last-4 visible), MCC
  • Owner identity (full name) NOT in QR
  • Scan events anonymized after 30 хоног

11. Performance targets

QR resolve:           p50 < 100ms,  p95 < 300ms (cached)
QR generate (static): p50 < 200ms,  p95 < 500ms
QR generate (dynamic):p50 < 300ms,  p95 < 800ms
QR image render:      p50 < 100ms (PNG cached)
QR scan event log:    async (non-blocking)

Throughput:
   Phase 2:  50 QR resolves/sec sustained
   Phase 3: 500 QR resolves/sec

12. Deployment timeline

Phase 1.5:
   ─ EMVCo TLV encoder/decoder library
   ─ Static MPQR generation
   ─ /v1/qr/resolve endpoint
   ─ Sandbox testing with Wallet partners

Phase 2:
   ─ Dynamic MPQR
   ─ CPQR
   ─ QR scan analytics
   ─ FRM integration on resolve
   ─ MNQR profile published (Mongolbank consultation)

Phase 2.5:
   ─ QPay format compat layer
   ─ POS SDK with QR generation
   ─ Production launch

Phase 3:
   ─ QPay migration / coexistence
   ─ Cross-PSP merchant directory
   ─ QR analytics dashboard for PSPs

Эх сурвалж: PLAN/15-QR-SWITCH.md. Дараагийн хуудас: Phase plan →