Bank Integration Guide
Join the OpenWave network as a payment partner. Once registered, your customers can pay and receive payments from any merchant or user in the ecosystem.
What a Bank Needs to Provide
OpenWave is a routing layer — it doesn't replace your core banking system. The gateway calls your core to:
- Verify customer identity (OTP or SCA)
- Debit the sending account
- Credit the destination account (if it's your bank)
- Query account details for Open Banking
You expose a bank core callback API that the gateway calls. The spec defines exactly what this interface must look like.
Step 1 — Register with a Gateway
Contact the gateway operator (or run your own — see Gateway Operators).
You'll need to provide:
- Bank handle (e.g.
andalus) — globally unique short identifier - Display name
- Country (
LY) - Core API base URL (your callback server)
- Settlement IBAN (where net settlements are credited/debited)
- Contact email
The gateway issues you a Bank API Key (owbk_...). Store it securely — it's shown once.
Step 2 — Implement the Core Callback Interface
The gateway calls your core at the core_base_url you registered. All endpoints receive X-OpenWave-Internal-Key for authentication. You must implement all of the following:
| Endpoint | Method | Called when |
|---|---|---|
/send-otp | POST | Customer selects OTP auth |
/verify-otp | POST | Customer submits OTP code |
/send-push | POST | Customer selects push auth |
/execute-transaction | POST | OTP/push verified — debit + route funds |
/notify-credit | POST | Cross-bank credit arrives (non-blocking) |
/ob/accounts | POST | Open Banking AISP account list |
/ob/balances | POST | Open Banking AISP balance query |
/ob/transactions | POST | Open Banking AISP transaction history |
/ob/payment-orders | POST | Open Banking PISP payment initiation |
Bank-agnostic routing
The gateway has one generic HTTP client for all banks. There is no bank-specific code in the gateway — your core_base_url is the sole routing target.
Send OTP Challenge
POST {core_base_url}/send-otp
X-OpenWave-Internal-Key: <shared-secret>
{
"session_id": "ops_01HZGV...",
"payer_iban": "LY83002700100099900001"
}Your bank receives the payer IBAN, extracts the account number, looks up the customer in your CBS, and sends the OTP via SMS/email. Return:
{ "otp_token": "<reference>", "phone_masked": "091****12", "expires_in_seconds": 300 }CBS customer IDs never leave your bank
The gateway passes only the IBAN — it never stores or transmits CBS-internal customer IDs. Your bank derives the customer from the IBAN internally. This is by design.
Verify OTP
POST {core_base_url}/verify-otp
X-OpenWave-Internal-Key: <shared-secret>
{ "session_id": "ops_01HZGV...", "otp_token": "<reference>", "otp_code": "123456" }Return { "verified": true } or a 401.
Execute Transaction
Called once after OTP/push auth is confirmed. Handles both same-bank and cross-bank routing:
POST {core_base_url}/execute-transaction
X-OpenWave-Internal-Key: <shared-secret>
{
"session_id": "ops_01HZGV...",
"merchant_name": "My Store",
"merchant_reference": "order_1042",
"debtor_iban": "LY83002700100099900001",
"creditor_iban": "LY83002700200099900002",
"creditor_bank_handle": "bank-b",
"creditor_bank_lypay_code": "002",
"amount": 50000,
"currency": "LYD",
"description": "Order #1042",
"route_type": "SAME_BANK"
}route_type is either SAME_BANK (atomic CBS book transfer) or LYPAY_INITIATE (debtor bank initiates a CBL LyPay transfer). Return:
{ "transfer_ref": "TRF-20260424-001", "route_used": "SAME_BANK", "lypay_ref": null }Notify Credit (cross-bank, non-blocking)
When a cross-bank payment credits the merchant's bank, the gateway calls the creditor bank to inform it:
POST {core_base_url}/notify-credit
X-OpenWave-Internal-Key: <shared-secret>
{
"session_id": "ops_01HZGV...",
"creditor_iban": "LY83002700200099900002",
"amount": 50000,
"currency": "LYD",
"transfer_ref": "TRF-20260424-001"
}Get Accounts (for Open Banking AISP)
POST {core_base_url}/ob/accounts
X-OpenWave-Internal-Key: <shared-secret>
{ "customer_id": "CUST-001", "consent_id": "con_01HZGV..." }Returns list of accounts with IBAN, account name, currency, and type.
Get Balances (for Open Banking AISP)
POST {core_base_url}/ob/balances
X-OpenWave-Internal-Key: <shared-secret>
{ "customer_id": "CUST-001", "iban": "LY83...", "consent_id": "con_01HZGV..." }Get Transactions (for Open Banking AISP)
POST {core_base_url}/ob/transactions
X-OpenWave-Internal-Key: <shared-secret>
{ "customer_id": "CUST-001", "iban": "LY83...", "from_date": "2026-01-01",
"to_date": "2026-04-30", "page": 1, "limit": 50, "consent_id": "con_01HZGV..." }Step 3 — Enroll Your Customers' Aliases
When a customer chooses their NPT handle in your app, your backend calls the Identity Registry:
POST /v1/identity/claim
X-OpenWave-Bank-Key: owbk_<your-bank-handle>_...
{
"npt_handle": "mtellesy",
"iban": "LY83002700100099900001",
"customer_display_name": "Mohamed T.",
"bank_customer_ref": "CUST-001"
}If the handle is taken, the registry returns 409 Conflict.
Step 4 — Advertise Your Capabilities
Let TPPs know what Open Banking features you support:
PATCH /banks/{handle}
X-OpenWave-Bank-Key: owbk_andalus_...
{
"ob_enabled": true,
"ob_scopes_supported": ["accounts:read", "balances:read", "transactions:read", "payments:write"],
"sca_exemption_limit": 5000,
"max_consent_expiry_days": 365
}Step 5 — Handle Settlements
The gateway batches net settlement amounts and calls your core once per settlement cycle (configurable: hourly, daily, etc.).
A settlement is a net credit or debit to your settlement_account_iban. The gateway handles individual customer debits and credits — settlement reconciles the net position between banks.
LyPay & NAD Integration
To participate in cross-bank OpenWave payments, your bank must be connected to CBL's National Payment Infrastructure:
NAD — National Alias Directory
NAD is the CBL-operated alias registry. Your bank must:
- Enroll your customers in NAD when they activate their alias (NPT handle) — this maps alias → IBAN + institution code
- Keep NAD in sync — deactivate entries when accounts are closed or aliases are released
- Expose the enrollment callback so the gateway can trigger NAD enrollment via your bank's OpenWave interface
POST /openwave/callbacks/v1/alias/enroll
{
"alias": "mtellesy",
"account_iban": "LY83002700100099900001",
"customer_ref": "CUST-001"
}LyPay — Outbound (Sending)
When your customer pays a merchant at another bank:
- Gateway instructs your bank to debit the customer
- Your bank CBS debits, then initiates a LyPay transfer to the creditor IBAN
- LyPay routes to the merchant's bank
- You receive a LyPay
debit notice(your RRN) — store this for reconciliation
LyPay — Inbound (Receiving)
When your merchant customer receives a payment from another bank:
- CBL LyPay delivers a credit instruction to your bank
- Your CBS credits the merchant's account
- Your bank (or the gateway) fires the credit confirmation back to the gateway
- The gateway updates the session to
COMPLETEDand firespayment.completedto the merchant
Credit confirmation is mandatory
The gateway will not fire payment.completed to the merchant until it receives credit confirmation from your bank. Implement the credit callback promptly — delays here delay merchant fulfillment.
POST /openwave/callbacks/v1/payment/credit-confirmed
{
"payment_reference": "LYPAY-REF-001",
"session_id": "ops_01HZGV...",
"creditor_iban": "LY83002700100099900001",
"amount": 50000,
"currency": "LYD",
"rrn": "20260424-000123"
}Security Requirements
| Requirement | Detail |
|---|---|
| All callback endpoints must be HTTPS | TLS 1.2+ required |
Validate X-OpenWave-Internal-Key on every callback | Reject requests without valid key |
| Idempotency | Use the reference field to deduplicate — the gateway may retry on timeout |
| Response time | Core callbacks should respond within 10 seconds |
| Retry policy | Gateway retries with exponential backoff on 5xx responses |
Rotate Your Bank Key
If your key is compromised:
POST /banks/{handle}/rotate-key
X-OpenWave-Bank-Key: owbk_<your-bank-handle>_...New key is returned once. Update your systems immediately.