XPXMPaymentv1.1.0

Self-hosted QRIS gateway with automated bank notification reconciliation.

XMPayment bridges DANA Bisnis push notifications captured by a dedicated Android device into a persistent Node.js backend — no bank API access, no per-transaction fees, no serverless time limits.

Unique nominal engine

Each invoice gets a 1–999 anti-collision suffix with automatic 4-digit overflow, so a bank notification alone identifies the payer.

Dynamic EMVCo QRIS

Static merchant payloads are mutated per transaction (tag 01 → 12, tag 54 injected) with a recomputed CRC16-CCITT checksum.

Idempotent ingestion

SHA-256 hashing over a one-minute bucket collapses duplicate Android notifications without ever double-crediting a wallet.

Wallet ledger + payouts

Every balance mutation writes a paired ledger entry. Payouts move funds to a locked balance until the Super Admin settles them.

Heartbeat kill switch

No ping from the Android bridge for 45 minutes flips the gateway to MAINTENANCE and refuses new live invoices.

Persistent WhatsApp bot

zapo-js pairing credentials are stored on disk, so reboots never invalidate the KYC verification session.

Create an invoice

POST /api/v1/invoices

curl -X POST $BASE/api/v1/invoices \
  -H "Authorization: Bearer xmp_test_…" \
  -H "Content-Type: application/json" \
  -d '{ "baseAmount": 50000 }'

Returns a dynamic QRIS payload and a checkout URL. The customer transfers the exact unique nominal, e.g. Rp 50,023.

Reconcile automatically

POST /api/internal/webhook-macrodroid

curl -X POST $BASE/api/internal/webhook-macrodroid \
  -H "x-macrodroid-secret: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "text": "DANA: Berhasil menerima uang sebesar Rp50.023" }'

The wallet is credited inside a single transaction; the merchant webhook fires afterwards.