Skip to main content

Multi-Tenancy

Each tenant in Kora CBA gets a dedicated PostgreSQL database. The platform database stores the tenant registry, and the API gateway resolves every request to the correct tenant database at runtime.

Tenant Resolution

The gateway resolves the current tenant using:

PriorityMethodExample
1X-Tenant-ID headerX-Tenant-ID: demo_bank
2JWT tenant_id claimEmbedded in access token
3Subdomaindemobank.cba-platform.com

For API integrations, always send the X-Tenant-ID header explicitly.

Database Isolation

┌──────────────────────────────┐
│ Platform Database │
│ ┌────────────────────────┐ │
│ │ platform.tenants │ │
│ │ platform.api_keys │ │
│ │ platform.webhooks │ │
│ │ platform.audit_log │ │
│ └────────────────────────┘ │
└──────────────────────────────┘

┌─────────────────┐ ┌─────────────────┐
│ tenant_demo_bank│ │ tenant_acme_bank│
│ │ │ │
│ gl.accounts │ │ gl.accounts │
│ gl.journals │ │ gl.journals │
│ account.accounts│ │ account.accounts│
│ transaction.* │ │ transaction.* │
└─────────────────┘ └─────────────────┘
  • Platform database — Shared tenant registry, API keys, webhook subscriptions, and platform audit logs.
  • Tenant databases — Fully isolated. Each tenant has its own GL chart of accounts, customer records, account balances, and transactions.
  • Row-level security — PostgreSQL RLS policies enforce tenant boundaries within each database as an additional safety layer.

Tenant Object

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"code": "demo_bank",
"name": "Demo Bank Ltd",
"status": "active",
"config": {
"default_currency": "NGN",
"timezone": "Africa/Lagos",
"base_interest_rate": 2.5,
"reserve_requirement_ratio": 0.10,
"max_accounts_per_customer": 10,
"enable_overdraft": true,
"max_overdraft_percentage": 10.0,
"fee_rounding": "ROUND_HALF_UP",
"settlement_time_hours": 24
},
"branding": {
"logo_url": "https://cdn.korastratum.com/demo_bank/logo.png",
"primary_color": "#003366"
},
"feature_flags": {
"virtual_accounts": true,
"international_transfers": false,
"biometric_auth": false,
"islamic_banking": false,
"bill_payment": true,
"card_issuance": true,
"ussd_service": true,
"agent_banking": false,
"trade_finance": false,
"wealth_management": true
},
"regulatory_config": {
"reserve_requirement_ratio": 0.10,
"compliance_level": "tier1"
}
}

Tenant Configuration

Tenant-level settings control default behaviour across services:

SettingDescriptionDefault
default_currencyBase currency for the tenantNGN
timezoneTimezone for reporting and schedulesAfrica/Lagos
base_interest_rateDefault savings interest rate (%)2.5
reserve_requirement_ratioRequired reserve ratio0.10
max_accounts_per_customerMax accounts a single customer can hold10
enable_overdraftWhether overdraft is availabletrue
max_overdraft_percentageMax overdraft as % of balance10.0
fee_roundingRounding mode for fee calculationsROUND_HALF_UP
settlement_time_hoursInterbank settlement window24

Feature Flags

Feature flags enable or disable entire product modules per tenant:

FlagDescription
virtual_accountsVirtual/sub-account management
international_transfersSWIFT cross-border transfers
bill_paymentBill payment and airtime
card_issuanceDebit/credit card issuance
ussd_serviceUSSD banking channel
agent_bankingAgent banking network
islamic_bankingSharia-compliant products
trade_financeLetters of credit, trade finance
wealth_managementInvestment and portfolio management
biometric_authBiometric authentication

Requests to disabled features return 403 Forbidden.

Integration Configuration

Each tenant can configure third-party integration providers (e.g., NIP providers, SMS gateways, payment processors) at the tenant level.

Get Integration Config

GET /api/v1/platform/tenants/:id/integrations/:provider

Update Integration Config

PUT /api/v1/platform/tenants/:id/integrations/:provider
{
"provider": "interswitch",
"enabled": true,
"config": {
"client_id": "ISW-XXXXXX",
"base_url": "https://qa.interswitchng.com",
"timeout_ms": 30000,
"retry_count": 3
},
"is_primary": true
}
note

Integration credentials are encrypted at rest. The config object varies by provider — refer to each provider's setup guide for required fields. Changes take effect immediately for all new requests.

Next Steps