PayGrid · paygrid.mn

Танилцуулга / Settlement

Settlement model

PayGrid нь deferred net settlement (DNS) model-аар end-of-day batch-аар Mongolbank Switch (existing inter-bank rail)-аар settle хийнэ. Real-time gross settlement (RTGS) шинэ rail хэрэггүй — Switch-ыг reuse хийж, хосолсон bilateral nostro position-уудаар intraday-ыг handle хийнэ.

1. Тойм

Real-time leg (хэрэглэгчид)

Bank ↔ PayGrid ↔ PSP. PayGrid in-memory bilateral nostro position-уудаар. < 10 сек end-to-end (mock overhead-аар).

Batch leg (async)

Цаг тутамд + EOD-аар PayGrid net position-уудыг pair бүр-аар тооцож, DNS batch-аар Mongolbank Switch-руу submit. Switch-аас Mongolbank-аар RTGS-аар final settle.

2. DNS яагаад, RTGS биш

ArgumentDNS chosen
Existing infrastructureSwitch (NPS) аль хэдийн ажиллаж байгаа. Reuse.
Liquidity efficiencyNet settlement нь gross-аас far less prefunded liquidity шаардана.
CostSwitch tx нь хямд; net'd batch volume-ыг 80%-аар бууруулна.
Implementation complexityDNS барих нь simpler; RTGS message-by-message critical path байхгүй.
Mongol-аар realisticMongolbank PayGrid-ыг direct RTGS member-аар хурдан approve хийхгүй магадлалтай.
RegulatoryMongolbank PayGrid-ыг "оператор"-аар recognize-ыг хүлээх боломжтой.
Trade-off

Intraday credit risk — PayGrid participant balance-ыг EOD хүртэл back хийдэг. End-of-day settlement window — банкууд sufficient pre-fund-той байх ёстой.

Mitigations: Pre-funded nostro at Mongolbank (each participant); Hourly intraday batches; Settlement guarantor reserve fund (Phase 3+).

3. Bilateral nostro positions

PayGrid bilateral net position per participant pair-аар track хийнэ:

Bank1 ↔ Bank2:    Net amount Bank1 owes Bank2 (or vice versa)
Bank1 ↔ Wallet1:  Net amount Bank1 owes Wallet1
Bank2 ↔ Wallet2:  ...
Wallet1 ↔ Wallet2: ...

Storage нь current_positions materialized view from ledger_entries table:

CREATE MATERIALIZED VIEW current_positions AS
SELECT
    pair_a_bic, pair_b_bic, currency,
    SUM(CASE WHEN direction = 'DEBIT' THEN amount ELSE -amount END)
        AS net_amount,
    COUNT(*) AS tx_count,
    MAX(booked_at) AS last_booked
FROM ledger_entries
WHERE settled_in_batch IS NULL
GROUP BY pair_a_bic, pair_b_bic, currency;

-- Refresh every 60 seconds

4. Real-time leg sequence

  1. Wallet PSP initiates payment

    Хэтэвч → POST /v1/payments/sepa-credit-transfers хэрэглэгчийн Bank1 данснаас merchant-руу.

  2. paygrid-api validates

    FRM screen, route resolve, → Bank1 PISP API forward.

  3. Bank1 SCA via e-ID Mongolia

    PayGrid involved биш — bank ↔ rp.gerege.mn шууд.

  4. Bank1 debits debtor account

    Logical debit бичигдсэн.

  5. Bank1 → paygrid-clearing pacs.008

    SCA attestation in SplmtryData.

  6. paygrid-clearing

    (а) Validate pacs.008 schema, (б) Routing — creditor IBAN → creditor PSP, (в) INSERT INTO ledger_entries — Bank1 DEBIT, Wallet CREDIT, (г) Forward pacs.008 to Wallet PSP, (д) Wallet credits user wallet balance, (е) Wallet returns pacs.002 ACSC, (ё) paygrid-clearing → Bank1 pacs.002 ACSC, (ж) Bank1 → user-facing webhook.

  7. User sees "Payment confirmed"

    Total: < 10 sec.

5. Batch leg sequence (hourly cycle)

Hourly (every hour on the hour):
↓
paygrid-clearing:
   1. SELECT * FROM ledger_entries
      WHERE settled_in_batch IS NULL
      AND booked_at < NOW() - 1 minute   ← grace period
   2. Group by (pair_a_bic, pair_b_bic, currency)
   3. Calculate net amount per pair
   4. Build settlement_batch record:
      {
        batch_date: '2026-05-06',
        cycle: 14,                       ← 14:00 UTC+8
        tx_count: 1234,
        total_volume_minor: 45000000,
        positions: [
          { pair_a: 'KHANUBXX', pair_b: 'GWMNUBXX',
            amount: 1500000, direction: 'a_owes_b' },
          { pair_a: 'TDBMNUB',  pair_b: 'GWMNUBXX',
            amount:  800000, direction: 'b_owes_a' },
          ...
        ]
      }
   5. Submit to Mongolbank Switch (ISO 8583; Phase 1 mock)
   6. Switch debits/credits each participant's settle account
   7. Switch returns confirmation
   8. UPDATE ledger_entries SET settled_in_batch = <id>
   9. Webhook participants: settlement.batch_completed

End-of-day reconciliation (00:00 UTC+8)

  1. Generate participant statements (per-PSP balance, tx count, volume, fee)
  2. Reconcile with Switch
  3. Generate regulatory report (FIU SAR, large tx)
  4. Auto-email participants with statements
  5. Email Mongolbank with daily summary
  6. Archive day's ledger_entries (cold storage)

6. Failure handling

Real-time leg failures

ScenarioHandling
Creditor PSP unavailableRetry with exponential backoff (max 4ц). After timeout: pacs.004 (Payment Return).
Bank pacs.008 invalidReject; pacs.002 RJCT to bank.
paygrid-clearing crashIdempotency-key replay; pgsql txn rollback.
Network partitionBank holds payment in PDNG state until reachable.

Batch leg failures

ScenarioHandling
Switch unreachableRetry batch; alert ops.
Switch rejects batchPause batch, alert participant; ad-hoc top-up + retry.
Reconciliation mismatchFreeze new payments; investigate; manual correction with audit trail.
PSP failure (bankrupt)Switch holds PSP's batch; PayGrid liability fund covers (Phase 3+).

7. Pre-funding requirements

Bank participants

  • Хадгалж байгаа Mongolbank settlement данс (existing)
  • Add buffer for PayGrid net positions (~5× peak intraday)

Wallet/EMI participants

  • Phase 2: Wallet uses sponsor bank's settlement account; sponsor bank reserves portion for Wallet's PayGrid positions
  • Phase 3+: Wallet has own Mongolbank account (after EMI license upgrade)
Pre-funding amount calculation:
   pre_fund >= MAX(daily_outflow_p99) * 1.5

Refilling:
   Auto low-balance alert when balance < 1.5× average daily outflow
   Participant pre-funds before next batch

8. Liability framework

ScenarioLiability
User-initiated disputePSP (debtor side)
Fraud (compromised user account)Bank or Wallet — depending on which authenticated
Sanctions screening missPayGrid + originating PSP (joint)
Settlement risk (PSP fails)PayGrid liability fund (Phase 3+)
Switch failureMongolbank
HSM failurePayGrid (operational)
Reversed payment (pacs.004)Originating PSP must absorb

9. Special Return Mechanism (PIX-style 24ц)

After settlement (T+0):
   Window: 24 цаг

If creditor PSP detects fraud / unauthorized:
   Initiate pacs.004 (Payment Return) to PayGrid
   PayGrid validates + forwards to debtor PSP
   Debtor PSP credits user account
   Bilateral position rebalanced

Beyond 24ц:
   Manual dispute via PayGrid arbitration

10. Metrics + KPIs

SLO:
   Real-time leg p95 < 10 сек
   Real-time leg p99 < 30 сек
   Batch leg success > 99.5%
   Reconciliation accuracy 100%
   Pre-funding utilization < 50%

Dashboards:
   Per-participant nostro position
   Volume per hour / day
   Failure rate per PSP pair
   FRM score distribution
   Settlement latency histogram

11. Mongolbank Switch integration

Phase 1 — mock

// paygrid-switch-client (Go lib)
func SubmitBatch(ctx context.Context, batch *SettlementBatch) error {
    log.Info("Mock Switch batch submitted", "batch_id", batch.ID)
    return nil
}

Phase 2-3 — real Switch

ISO 8583 messages-аар Mongolbank-аас allocated leased line / VPN. Тодорхой message types Mongolbank engagement-аар TBD. Магадлалтай:

  • Network management (sign-on, sign-off, echo)
  • Settlement instruction
  • Settlement confirmation
  • Reconciliation report

Implementation reference: github.com/moov-io/iso8583 зэрэг Go library-ууд.

Phase 4+ — Direct Mongolbank RTGS membership

  • PayGrid-ыг Mongolbank RTGS member болгох
  • Real-time gross settlement бүх tx-аар
  • Intraday credit risk бүтэн арилна
  • Шаардлагатай: Mongolbank rule changes, PayGrid capital adequacy, operational resilience proven

Эх сурвалж: PLAN/08-SETTLEMENT.md, PLAN/06-DATA-MODEL.md. Дараагийн хуудас: e-ID Mongolia →