Gateway Operator Guide
Any organisation can run an OpenWave-compliant gateway. This page covers what compliance means and how to get started.
What is a Compliant Gateway?
A gateway is compliant if it:
- Implements all endpoints defined in
openwave-payments-v1.yamlandopenwave-open-banking-v1.0.yaml - Follows the authentication model specified (API keys, OAuth 2.0 + PKCE for OB)
- Delivers webhooks with correct
X-OpenWave-SignatureHMAC signing - Enforces the amount convention (integers, minor units)
- Exposes
/banks/{handle}/capabilitiesfor Open Banking capability discovery - Integrates with the OpenWave Identity Registry for NPT alias resolution
Reference Implementation
Astro (by Neptune Fintech) is the reference gateway implementation:
- Built with Kotlin + Spring Boot 3
- Source:
neptune-fintech/neptune-astro(private during beta) - Runs on any JVM-compatible host
Running Your Own Gateway
Minimum Requirements
| Component | Requirement |
|---|---|
| Runtime | JVM 21+ (Kotlin/Java) or equivalent in your stack |
| Database | PostgreSQL 14+ |
| Cache | Redis (for session state and OTP TTLs) |
| TLS | All endpoints must be HTTPS in production |
| Webhooks | Async delivery with retry queue (Redis Streams or equivalent) |
Architecture Overview
┌─────────────────────────────┐
Merchant ──────────►│ │
│ OpenWave Gateway │──────► Bank Core A
TPP ───────────────►│ │──────► Bank Core B
│ - Payment sessions │──────► Bank Core C
Customer ──────────►│ - OB consent + tokens │
│ - NPT alias resolution │──────► Identity Registry
│ - Webhook delivery │
│ - Settlement batching │──────► Settlement Layer
└─────────────────────────────┘Connecting to the Identity Registry
To resolve NPT aliases and register bank handles, your gateway must connect to the OpenWave Identity Registry:
Production: https://registry.openwave.lySettlement
OpenWave does not prescribe a settlement mechanism — this is a bilateral agreement between banks and the gateway operator. Common approaches:
- Net settlement via RTGS — gateway calculates net positions per bank cycle and submits to central bank
- Gross settlement — each payment triggers an immediate interbank transfer
- Prefunded model — banks maintain a balance at the gateway; depleted by outgoing payments
Interoperability Between Gateways
Two compliant gateways can interoperate:
Gateway A (merchant on G-A) ──┐
├──► [Identity Registry: resolve alias]
Gateway B (payer's bank) ──┘ ──► routed to Bank B via Gateway BProtocol:
- Gateway A resolves the NPT alias → gets
{ iban, bank_handle } - Gateway A looks up which gateway Bank B is connected to
- Gateway A calls Gateway B's payment initiation endpoint using standard OpenWave API
- Gateway B debits the customer and delivers the settlement
This requires a cross-gateway routing table — maintained via the Identity Registry's bank phonebook (GET /v1/banks).
CBL Infrastructure Dependencies
If operating in Libya, your gateway must integrate with CBL's National Payment Infrastructure to enable cross-bank payments.
NAD Integration
Your gateway calls NAD (National Alias Directory) to resolve alias/phone/NID → IBAN + bank code before routing any LyPay transfer.
alias "mtellesy" → NAD lookup → { iban: "LY83...", institution: { code: "ABCD" } }The Nexus reference implementation uses UniversalLookupService which queries NAD via the NadIndividualHandler / NadMerchantHandler strategy pattern. Cache NAD responses (short TTL: 60 seconds) to reduce latency.
LyPay Outbound
When the gateway instructs a bank to debit a customer for a cross-bank payment:
- Bank CBS debits customer
- Bank sends LyPay transfer instruction to CBL
- CBL routes to creditor bank
- Creditor bank credits merchant
Your gateway does not need to call LyPay directly — the debtor bank handles the LyPay instruction. You instruct the bank via the standard debit core callback.
LyPay Inbound Callback
CBL LyPay (or the creditor bank) sends a credit notification to your gateway when funds land. You must:
- Register a webhook endpoint with CBL LyPay for your gateway
- Handle the
credit_noticepayload - Find the matching session by
payment_reference - Update session status to
COMPLETED - Fire
payment.completedwebhook to the merchant
// Pattern from Nexus LyPayTransactionNotificationService
when (statusCode) {
"03" -> { // completed — credit confirmed
session.status = COMPLETED
webhookService.fire("payment.completed", session)
}
"04", "05" -> { // declined / failed
session.status = FAILED
webhookService.fire("payment.failed", session)
}
}Idempotency is critical
CBL LyPay may send duplicate callbacks on retry. Use the payment_reference as an idempotency key — process each reference only once.
Settlement Model with LyPay
LyPay handles the actual money movement between banks. Your gateway tracks the logical state of each payment session. Settlement reconciliation options:
| Model | Description |
|---|---|
| Real-time (gross) | Each payment triggers one LyPay transfer; no net settlement needed |
| Net batch | Gateway batches obligations; single LyPay transfer per bank per cycle |
| Prefunded | Banks maintain escrow balance at gateway; LyPay only for rebalancing |
The reference Astro implementation uses real-time gross settlement — each confirmed payment maps to one LyPay transfer.
Compliance Checklist
- [ ] All spec endpoints implemented with correct HTTP methods and status codes
- [ ]
api_versionfield included in all webhook payloads - [ ] PKCE S256 enforced — plain method rejected
- [ ] Webhook HMAC signing with SHA-256
- [ ]
X-Consent-Idvalidated on all Open Banking data/payment calls - [ ] Token storage: SHA-256 hash only — raw access token never persisted
- [ ] Access token TTL ≤ 15 minutes
- [ ] Refresh token single-use rotation enforced
- [ ]
DELETE /ob/consents/{id}immediately invalidates all associated tokens - [ ] Amount convention: integers in minor units validated and enforced
- [ ]
/banks/{handle}/capabilitiesendpoint publicly accessible - [ ] Identity Registry connected for alias resolution