On-premise payment gateway for Indonesian organizations. Connects to multiple banks via Bank Indonesia SNAP API, exposes a single unified REST API to client applications.
Organizations with direct bank relationships (universities, government agencies, hospitals) currently either:
- Pay Rp 1,500-4,000 per transaction to SaaS gateways (Midtrans, Xendit, DOKU), or
- Maintain separate integrations per bank with no unified reconciliation
This gateway runs on the client's own infrastructure. Zero per-transaction middleman fees. Client owns their data.
graph TD
CLIENT["CLIENT APPLICATION<br/>(University SIS, Hospital HIS, ERP)"]
subgraph GATEWAY["SNAP PAYMENT GATEWAY"]
API["Payment API<br/>create / inquiry / cancel"]
NOTIF["Notification Handler<br/>bank callbacks → client webhooks"]
RECON["Reconciliation Engine<br/>matching, discrepancy detection, reports"]
SNAP["SNAP Client Layer<br/>OAuth 2.0 + mTLS, request signing, token management"]
BCA_ADAPTER["BCA Adapter"]
BNI_ADAPTER["BNI Adapter"]
MANDIRI_ADAPTER["Mandiri Adapter"]
BRI_ADAPTER["BRI Adapter"]
DASHBOARD["Admin Dashboard<br/>transactions, reconciliation, bank status"]
AUDIT["Audit Log"]
end
BCA["BCA"]
BNI["BNI"]
MANDIRI["Mandiri"]
BRI["BRI"]
CLIENT -- "Unified REST API" --> API
NOTIF -- "Webhook" --> CLIENT
API --> SNAP
NOTIF --> SNAP
RECON --> SNAP
SNAP --> BCA_ADAPTER
SNAP --> BNI_ADAPTER
SNAP --> MANDIRI_ADAPTER
SNAP --> BRI_ADAPTER
BCA_ADAPTER -- "SNAP API" --> BCA
BNI_ADAPTER -- "SNAP API" --> BNI
MANDIRI_ADAPTER -- "SNAP API" --> MANDIRI
BRI_ADAPTER -- "SNAP API" --> BRI
BCA -- "Callback" --> NOTIF
BNI -- "Callback" --> NOTIF
MANDIRI -- "Callback" --> NOTIF
BRI -- "Callback" --> NOTIF
Single REST API for all payment operations. Client applications never interact with bank APIs directly.
POST /api/v1/payments # Create payment (VA, QRIS)
GET /api/v1/payments/{id} # Check payment status
DELETE /api/v1/payments/{id} # Cancel/expire payment
GET /api/v1/payments?filter=... # List/search payments
POST /api/v1/settlements # Trigger reconciliation
GET /api/v1/settlements/{id} # Get settlement report
Create payment request:
{
"type": "VIRTUAL_ACCOUNT",
"bank": "BNI",
"amount": 5000000,
"customer_name": "Ahmad Rizki",
"description": "SPP Semester Genap 2026",
"reference_id": "INV-2026-00123",
"expiry_minutes": 1440
}Response:
{
"id": "pay_abc123",
"status": "PENDING",
"type": "VIRTUAL_ACCOUNT",
"bank": "BNI",
"va_number": "8810000012345678",
"amount": 5000000,
"expiry_at": "2026-03-18T10:00:00+07:00"
}Same structure regardless of payment channel (VA, QRIS) or bank.
Receives payment callbacks from banks, validates SNAP signatures, updates internal records, and forwards to the client application's webhook URL.
- Pulls settlement data from each bank via SNAP API or bank statement file
- Matches against internal payment records
- Flags discrepancies: paid at bank but not notified, amount mismatches, duplicate notifications
- Generates daily reconciliation reports
Implements the SNAP standard for outbound API calls to banks:
- Asymmetric signature (SHA256withRSA) for access token requests
- Symmetric signature (HMAC-SHA512) for API calls
- OAuth 2.0 token lifecycle: request, cache, refresh
- mTLS client certificate management
- Standardized request/response mapping
Per-bank configuration and quirk handling. SNAP standardizes the API shape, but banks differ in:
- Sandbox vs production endpoints
- Additional proprietary fields in
additionalInfo - Error code mappings
- VA number prefix/format rules
- Settlement file formats
Web UI for the client's finance/operations team:
- Transaction list with search and filter
- Real-time payment status
- Reconciliation status and discrepancy alerts
- Settlement reports (daily, monthly)
- Bank connection health
- Audit trail
This gateway acts as the Service User (SU) — it initiates calls to banks (Service Providers).
Gateway (SU) Bank (SP)
| |
|-- POST /access-token/b2b ---------->| X-SIGNATURE = RSA(clientId|timestamp)
|<------------ accessToken -----------| signed with our private key
| |
|-- POST /transfer-va/create-va ----->| X-SIGNATURE = HMAC-SHA512(
| Authorization: Bearer {token} | METHOD:URL:TOKEN:SHA256(BODY):TIMESTAMP,
|<------------ response --------------| clientSecret)
Each bank gets its own credential set: RSA key pair + client ID + client secret.
| Channel | Description | Bank Coverage |
|---|---|---|
| Virtual Account | Customer pays to a unique VA number | BNI, BCA |
| QRIS (MPM) | Merchant-presented QR code, customer scans | BNI or BRI |
| Channel | Description |
|---|---|
| Direct Debit | Scheduled/one-time pull from customer's account (BI-FAST) |
| Additional VA banks | Mandiri, BRI, BSI |
| E-wallet | OVO, GoPay, DANA, ShopeePay (separate integration per wallet) |
Phase 1 focuses on VA + QRIS because these are the most common channels for universities and government agencies, both covered by SNAP, and require no PCI DSS compliance.
| This Gateway (On-Premise) | Midtrans / Xendit / DOKU (SaaS) | |
|---|---|---|
| Deployment | Client's own infrastructure | Vendor's cloud |
| Per-transaction fee | None (client pays bank directly) | Rp 1,500–4,000+ per transaction |
| Bank relationship | Client signs PKS with each bank directly | Vendor holds the bank relationships |
| Data ownership | Client owns all transaction data | Data stored on vendor's infrastructure |
| Payment channels | VA, QRIS, Direct Debit (SNAP-covered channels) | VA, QRIS, credit card, e-wallets, convenience store, etc. |
| Credit card processing | Not supported (requires PCI DSS certification) | Supported (vendor is PCI DSS certified) |
| E-wallet aggregation | Not built-in (each wallet has its own non-SNAP API) | Supported (GoPay, OVO, DANA, ShopeePay) |
| Onboarding effort | Client must register with each bank individually | Single vendor registration |
| Ops responsibility | Client runs and monitors the gateway | Vendor handles uptime, NOC, incident response |
| Source code | Open source (Apache 2.0), fully auditable | Proprietary black box |
When this gateway makes sense: organizations that already have (or can establish) direct bank relationships, process enough volume that per-transaction fees add up, and have IT staff to run the infrastructure. Typical: universities, government agencies, hospitals, large enterprises.
When SaaS makes more sense: startups, e-commerce, or any organization that needs credit card / e-wallet coverage out of the box and doesn't want to manage infrastructure or bank relationships.
As of early 2026. Banks that have exposed SNAP-compliant APIs (as Service Providers):
| Bank | Developer Portal | Notes |
|---|---|---|
| BRI | developers.bri.co.id | VA, Direct Debit, Balance Inquiry, Bank Statement |
| BNI | digitalservices.bni.co.id | VA, SNAP documentation available |
| Mandiri | (via API portal) | SNAP migration in progress |
| BSI | (via API portal) | SNAP migration in progress |
| Bank | Developer Portal | Notes |
|---|---|---|
| BCA | developer.bca.co.id | VA, SNAP-based API alongside legacy |
| CIMB Niaga | (via API portal) | SNAP compliant |
| Permata (Bangkok Bank) | developers.permatabank.com | SNAP compliant |
| DBS Indonesia | (via API portal) | SNAP compliant |
| Nobu Bank | (via API portal) | SNAP compliant |
| Bank | Notes |
|---|---|
| Bank DKI | SNAP compliant |
| Bank Jambi | SNAP compliant |
Additional banks are migrating to SNAP ahead of the June 30, 2025 mandatory deadline set by Bank Indonesia. The adapter architecture of this gateway means adding a new bank is configuration + quirk handling, not a new integration from scratch.
The gateway is software. The legal relationship for SNAP is between the client organization (as Service User) and each bank (as Service Provider). The gateway vendor is not a party to these agreements.
- Legal entity — PT, yayasan, government agency, or other badan hukum with NPWP and business license (NIB/SIUP)
- Bank account — active account at each bank the client wants to connect to (settlement destination)
- Cooperation agreement (PKS) — signed with each bank's API/digital banking division. This is the standard bilateral agreement covering:
- API usage terms
- Transaction fees (if any — often waived for VA/QRIS for institutional clients)
- Settlement schedule
- SLA and dispute resolution
- RSA-2048 key pair — client generates the key pair; public key is registered with each bank during onboarding
- Client credentials — each bank issues a
clientIdandclientSecretafter PKS signing - mTLS certificate — some banks require client-side TLS certificates for production API calls
- Certification testing — the client must pass the bank's sandbox integration test suite before getting production credentials. This gateway's test suite (WireMock-based) prepares the client for this step.
| Step | Duration |
|---|---|
| Contact bank's API/digital banking team | 1-2 weeks |
| PKS negotiation and signing | 2-4 weeks |
| Sandbox credential issuance | 1-3 days after PKS |
| Integration development + testing | 2-4 weeks (mostly done — this gateway handles it) |
| Certification test with bank | 1-2 weeks |
| Production credential issuance | 1-2 weeks after passing certification |
| Total per bank | ~2-3 months |
The gateway eliminates the integration development step (already built), so the timeline is dominated by the administrative/legal process with each bank. Multiple banks can be onboarded in parallel.
| Layer | Technology | Version |
|---|---|---|
| Language | Java | 25 |
| Framework | Spring Boot | 4 |
| HTTP Client | Spring WebClient (reactive, non-blocking) | (included in Spring Boot) |
| Database | PostgreSQL | 18 |
| Migration | Flyway | latest |
| Security | Bouncy Castle (signatures), Spring Security (API auth) | latest |
| Frontend | Thymeleaf + Tailwind CSS + HTMX | latest |
| Container | Docker Compose | latest |
| Build | Maven | 3.9+ |
| Testing | JUnit 5, Testcontainers, WireMock (bank API stubs) | latest |
snap-payment-gateway/
├── docker-compose.yml
├── src/
│ ├── main/java/.../
│ │ ├── api/ # REST controllers (unified payment API)
│ │ ├── domain/ # Payment, Settlement, BankAccount entities
│ │ ├── snap/
│ │ │ ├── client/ # SNAP OAuth + signature implementation
│ │ │ ├── adapter/ # Bank-specific adapters (BCA, BNI, ...)
│ │ │ └── dto/ # SNAP request/response DTOs
│ │ ├── notification/ # Bank callback handler
│ │ ├── reconciliation/ # Matching engine, reports
│ │ ├── dashboard/ # Admin UI controllers
│ │ └── audit/ # Audit logging
│ └── main/resources/
│ ├── db/migration/ # Flyway SQL migrations
│ └── templates/ # Thymeleaf templates (dashboard)
├── pom.xml
└── docs/
├── api-reference.md
├── bank-adapter-guide.md # How to add a new bank adapter
└── deployment-guide.md
git clone https://github.com/artivisi/snap-payment-gateway.git
cd snap-payment-gateway
docker compose upAccess:
| Component | URL |
|---|---|
| Payment API | http://localhost:8080/api/v1 |
| Admin Dashboard | http://localhost:8080/dashboard |
| PostgreSQL | port 5432 |
Development mode uses WireMock stubs to simulate bank SNAP API responses. No real bank credentials required.
| Project | Role |
|---|---|
| payment-simulator | Educational tool. Teaches the bank-internal infrastructure (ISO 8583, switching, HSM) that sits underneath SNAP. |
| disbursement-platform | Outbound payments (payroll, scholarships, refunds). Complementary product — gateway collects money in, disbursement sends money out. |
| hsm-simulator | HSM cryptography simulator. Used in the payment-simulator, not directly by this gateway. |
This gateway is built live on camera as Part 2 of a multi-part YouTube series.
| Ep | Title | Build Target |
|---|---|---|
| 6 | SNAP API: Konsep dan Arsitektur | SNAP auth flow, signature schemes, project scaffolding |
| 7 | Project Setup dan SNAP Client | OAuth client, asymmetric/symmetric signatures, token management |
| 8 | Bank Adapter: BNI Virtual Account | First bank adapter, VA create/inquiry via SNAP sandbox |
| 9 | Bank Adapter: BCA Virtual Account | Second adapter, bank-specific quirks |
| 10 | Notification Handler | Receive bank callbacks, signature verification, webhook forwarding |
| 11 | QRIS Integration | QR code generation, QRIS MPM via SNAP |
| 12 | Reconciliation Engine | Bank statement matching, discrepancy detection |
| 13 | Admin Dashboard | Transaction list, reconciliation status, reports |
Each episode ends with working code against bank sandboxes. Production deployment (real bank credentials, security hardening, compliance) is the paid integration service.
Apache License 2.0