Overview
What is a Tenant?
A tenant represents a business entity (merchant, fintech, or enterprise) that uses the platform. Each tenant has isolated data, users, accounts, and configurations. Platform administrators manage tenants through dedicated endpoints.
Tenant Architecture
| Component | Description | Example |
|---|---|---|
| Tenant | Top-level business entity with isolated resources | Acme Payments Ltd |
| Partner | Owner/contact information for the tenant | John Doe (john@acme.com) |
| Users | People who access the tenant's dashboard | Admin, Finance, Support staff |
| Accounts | Ledger accounts (wallets) belonging to tenant's customers | Customer wallets, merchant wallets |
| Entitlements | Feature flags controlling what the tenant can do | POS access, virtual accounts, payouts |
| API Keys | Programmatic access credentials for integrations | Server-to-server API calls |
| Webhooks | Event notification endpoints | Transaction completed, KYC approved |
Tenant Lifecycle States
| Status | Description | Allowed Actions |
|---|---|---|
| active | Tenant is fully operational | All operations allowed |
| suspended | Temporarily disabled, data preserved | Read-only, cannot process transactions |
| inactive | Permanently disabled | Read-only, pending deletion |
Tenant Tiers
Tenants are classified into tiers that may affect rate limits, support levels, and available features.
| Tier | Description | Typical Use Case |
|---|---|---|
| free | Trial or basic tier with limited features | Startups, evaluation |
| paid | Standard commercial tier | Growing businesses |
| enterprise | Premium tier with enhanced support | Large organizations, banks |
API Base Path
/api/v1/admin/tenantsRequired Permission
All tenant management endpoints require platform admin authentication with appropriate permissions.
| Operation | Required Permission |
|---|---|
| List/View tenants | view_tenants |
| Create/Update tenants | manage_tenants |
| Manage entitlements | manage_tenant_entitlements |
| Manage users | manage_tenant_users |
| Manage API keys | manage_tenant_api_keys |
| Manage webhooks | manage_tenant_webhooks |
Tenant Lifecycle
Create Tenant
/api/v1/admin/tenantsCreates a new tenant with partner information. This initializes the tenant's isolated environment and creates default configurations.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- The created tenant object
{
"id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Payments Ltd",
"status": "active",
"default_currency": "NGN",
"is_active": true,
"metadata": {},
"created_at": "2024-01-15T09:00:00Z",
"updated_at": "2024-01-15T09:00:00Z",
"partner": {
"id": "prt_f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "John Doe",
"email": "john@acmepayments.com",
"tier": "paid",
"is_active": true
}
}Request Payload
{
"name": "Acme Payments Ltd",
"status": "active",
"default_currency": "NGN",
"is_active": true,
"metadata": {
"industry": "fintech",
"onboarding_source": "sales_team",
"contract_id": "CNT-2024-001"
},
"partner": {
"name": "John Doe",
"email": "john@acmepayments.com",
"tier": "paid"
}
}List Tenants
/api/v1/admin/tenantsRetrieves a paginated list of all tenants with optional filtering.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Paginated list of tenants
{
"tenants": [
{
"id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Payments Ltd",
"status": "active",
"default_currency": "NGN",
"is_active": true,
"created_at": "2024-01-15T09:00:00Z",
"partner": {
"name": "John Doe",
"email": "john@acmepayments.com",
"tier": "paid"
}
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total_count": 125
}
}Get Tenant
/api/v1/admin/tenants/{tenantID}Retrieves detailed information about a specific tenant.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Complete tenant object with all details
{
"id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Payments Ltd",
"status": "active",
"default_currency": "NGN",
"is_active": true,
"metadata": {
"industry": "fintech"
},
"created_at": "2024-01-15T09:00:00Z",
"updated_at": "2024-01-20T14:30:00Z",
"partner": {
"id": "prt_f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "John Doe",
"email": "john@acmepayments.com",
"tier": "paid",
"is_active": true
}
}Update Tenant
/api/v1/admin/tenants/{tenantID}Updates tenant details. All fields are optional; only provided fields are updated.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Updated tenant object
{
"id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Payments International",
"status": "active",
"updated_at": "2024-01-25T10:00:00Z"
}Request Payload (Update)
{
"name": "Acme Payments International",
"metadata": {
"industry": "fintech",
"region": "west_africa"
},
"partner": {
"tier": "enterprise"
}
}Update Tenant Status
/api/v1/admin/tenants/{tenantID}/statusChanges the tenant's operational status. Use this to suspend or reactivate tenants.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Updated tenant with new status
{
"id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Payments Ltd",
"status": "suspended",
"is_active": false,
"updated_at": "2024-01-25T10:00:00Z"
}Request Payload (Status Change)
{
"status": "suspended",
"is_active": false
}Status Change Effects
| From | To | Effect |
|---|---|---|
| active | suspended | Blocks all transactions, users can still login (read-only) |
| suspended | active | Restores full functionality |
| active | inactive | Permanently disables tenant (data retained) |
| suspended | inactive | Marks for eventual deletion |
| inactive | active | Reactivates tenant (if within retention period) |
Tenant Users & Invites
User Roles
Tenant users are assigned roles that control their access level within the tenant's dashboard.
| Role | Description | Typical Access |
|---|---|---|
| owner | Primary account owner | Full access, billing, delete tenant |
| admin | Administrator | Full access except billing/deletion |
| operator | Day-to-day operations | Transactions, accounts, KYC |
| finance | Financial operations | Transactions, reports, settlements |
| support | Customer support | View accounts, view transactions |
| viewer | Read-only access | View dashboards and reports |
| member | Basic access | Limited view access |
User Statuses
| Status | Description |
|---|---|
| invited | Invitation sent, pending acceptance |
| active | User has accepted and can access |
| suspended | Temporarily blocked from access |
| revoked | Access permanently removed |
Invite User
/api/v1/admin/tenants/{tenantID}/invitationsSends an invitation email to a new user to join the tenant. The user will receive a link to set up their account.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Created user invitation
{
"user": {
"id": "usr_a8b9c0d1-e2f3-4a5b-6c7d-8e9f0a1b2c3d",
"tenant_id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"email": "jane@acmepayments.com",
"full_name": "Jane Smith",
"role": "admin",
"status": "invited",
"invited_at": "2024-01-20T10:00:00Z"
},
"invitation_expires_at": "2024-01-27T10:00:00Z"
}Request Payload (Invite User)
{
"email": "jane@acmepayments.com",
"full_name": "Jane Smith",
"role": "admin",
"metadata": {
"department": "operations",
"employee_id": "EMP-001"
}
}List Tenant Users
/api/v1/admin/tenants/{tenantID}/usersRetrieves all users associated with a tenant.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Paginated list of tenant users
{
"users": [
{
"id": "usr_a8b9c0d1-e2f3-4a5b-6c7d-8e9f0a1b2c3d",
"email": "jane@acmepayments.com",
"full_name": "Jane Smith",
"role": "admin",
"status": "active",
"last_login_at": "2024-01-25T08:30:00Z"
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total_count": 12
}
}Get Tenant User
/api/v1/admin/tenants/{tenantID}/users/{userID}Retrieves detailed information about a specific tenant user.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- User details
{
"id": "usr_a8b9c0d1-e2f3-4a5b-6c7d-8e9f0a1b2c3d",
"tenant_id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"email": "jane@acmepayments.com",
"full_name": "Jane Smith",
"role": "admin",
"status": "active",
"metadata": {
"department": "operations"
},
"invited_at": "2024-01-10T10:00:00Z",
"accepted_at": "2024-01-10T14:30:00Z",
"last_login_at": "2024-01-25T08:30:00Z"
}Update Tenant User
/api/v1/admin/tenants/{tenantID}/users/{userID}Updates a tenant user's role, status, or metadata.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Updated user object
{
"id": "usr_a8b9c0d1-e2f3-4a5b-6c7d-8e9f0a1b2c3d",
"role": "finance",
"status": "active",
"updated_at": "2024-01-25T10:00:00Z"
}Request Payload (Update User)
{
"role": "finance",
"metadata": {
"department": "finance",
"promoted_from": "operator"
}
}Resend User Invite
/api/v1/admin/tenants/{tenantID}/users/{userID}/resend-inviteResends the invitation email to a user who hasn't accepted yet. Generates a new invitation token.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- New invitation details
{
"user_id": "usr_a8b9c0d1-e2f3-4a5b-6c7d-8e9f0a1b2c3d",
"invitation_expires_at": "2024-02-01T10:00:00Z",
"message": "Invitation resent successfully"
}Tenant API Keys
API Key Concepts
API keys allow tenants to integrate programmatically with the platform. Keys have scopes that control what operations they can perform.
| Concept | Description |
|---|---|
| Key ID | Public identifier for the key (can be shared/logged) |
| Full Key | Secret key shown ONLY at creation time (store securely) |
| Scopes | Permissions granted to the key |
| Rate Limits | Requests allowed per minute/day |
| Expiration | Optional expiry date for time-limited access |
Available Scopes
| Scope | Description |
|---|---|
| accounts:read | View account information |
| accounts:write | Create and update accounts |
| transactions:read | View transaction history |
| transactions:write | Initiate transactions |
| virtual_accounts:read | View virtual accounts |
| virtual_accounts:write | Create virtual accounts |
| kyc:read | View KYC submissions |
| kyc:write | Submit KYC data |
| pos:read | View POS terminals and transactions |
| pos:write | Manage POS operations |
| webhooks:manage | Manage webhook endpoints |
Create API Key
/api/v1/admin/tenants/{tenantID}/api-keysCreates a new API key for the tenant. The full key is returned ONLY in this response - store it securely.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Created key with full secret (shown only once)
{
"full_key": "wc_prod_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"key": {
"key_id": "key_550e8400-e29b-41d4-a716-446655440000",
"scopes": [
"accounts:read",
"transactions:read"
],
"rate_limit_per_min": 100,
"rate_limit_per_day": 10000,
"hash_version": 1,
"is_active": true,
"created_at": "2024-01-20T10:00:00Z",
"expires_at": "2025-01-20T10:00:00Z"
}
}Request Payload (Create Key)
{
"prefix": "prod",
"scopes": [
"accounts:read",
"accounts:write",
"transactions:read",
"transactions:write",
"virtual_accounts:read",
"virtual_accounts:write"
],
"rate_limit_per_min": 200,
"rate_limit_per_day": 50000,
"expires_at": "2025-12-31T23:59:59Z"
}List API Keys
/api/v1/admin/tenants/{tenantID}/api-keysRetrieves all API keys for a tenant. Keys are returned without the secret portion.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- List of API keys
{
"keys": [
{
"key_id": "key_550e8400-e29b-41d4-a716-446655440000",
"scopes": [
"accounts:read",
"transactions:read"
],
"rate_limit_per_min": 100,
"rate_limit_per_day": 10000,
"is_active": true,
"last_used_at": "2024-01-25T14:30:00Z",
"created_at": "2024-01-20T10:00:00Z"
}
]
}Get API Key
/api/v1/admin/tenants/{tenantID}/api-keys/{keyID}Retrieves details of a specific API key.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- API key details
{
"key_id": "key_550e8400-e29b-41d4-a716-446655440000",
"scopes": [
"accounts:read",
"transactions:read"
],
"rate_limit_per_min": 100,
"rate_limit_per_day": 10000,
"hash_version": 1,
"is_active": true,
"last_used_at": "2024-01-25T14:30:00Z",
"created_at": "2024-01-20T10:00:00Z",
"expires_at": "2025-01-20T10:00:00Z"
}Update API Key
/api/v1/admin/tenants/{tenantID}/api-keys/{keyID}Updates rate limits, expiration, or active status of an API key. Scopes cannot be modified after creation.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Updated API key
{
"key_id": "key_550e8400-e29b-41d4-a716-446655440000",
"rate_limit_per_min": 500,
"is_active": true,
"updated_at": "2024-01-25T10:00:00Z"
}Request Payload (Update Key)
{
"rate_limit_per_min": 500,
"rate_limit_per_day": 100000,
"expires_at": "2026-12-31T23:59:59Z"
}Deactivate Key Example
{
"is_active": false
}Tenant Accounts
Account Management
Platform admins can view and manage ledger accounts (wallets) belonging to a tenant's customers. This includes blocking, unblocking, and closing accounts.
Account Statuses
| Status | Description | Can Transact |
|---|---|---|
| active | Normal operational state | Yes |
| frozen | Temporarily blocked (compliance, fraud) | No |
| closed | Permanently closed | No |
Wallet Types
| Type | Description |
|---|---|
| customer | Individual customer wallet |
| business | Business/corporate wallet |
| merchant | Merchant settlement wallet |
| agent | Agent float wallet |
| float | Platform float/operational wallet |
List Tenant Accounts
/api/v1/admin/tenants/{tenantID}/accountsRetrieves paginated list of all accounts belonging to a tenant's customers.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Paginated list of accounts
{
"accounts": [
{
"id": "acc_550e8400-e29b-41d4-a716-446655440000",
"account_code": "WLT-001234567",
"account_name": "John Doe",
"wallet_type": "customer",
"status": "active",
"currency": "NGN",
"balance": 150000,
"available_balance": 145000,
"kyc_tier": "tier2",
"created_at": "2024-01-10T10:00:00Z"
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total_count": 1250
}
}Block Account
/api/v1/admin/tenants/{tenantID}/accounts/{accountID}/blockBlocks an account, preventing any transactions. Use for compliance or fraud investigations.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Account status change confirmation with affected child accounts
{
"account": {
"id": "acc_550e8400-e29b-41d4-a716-446655440000",
"status": "frozen",
"post_no_debit": true,
"post_no_credit": true,
"updated_at": "2024-01-25T10:00:00Z"
},
"child_accounts": []
}Request Payload (Block)
{
"reason": "Suspicious activity detected - multiple failed transactions from different locations",
"source": "fraud_detection",
"block_debits": true,
"block_credits": true,
"metadata": {
"ticket_id": "FRAUD-2024-001",
"detected_by": "automated_system"
}
}Unblock Account
/api/v1/admin/tenants/{tenantID}/accounts/{accountID}/unblockRemoves the block from an account, restoring normal operations.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Account status change confirmation with affected child accounts
{
"account": {
"id": "acc_550e8400-e29b-41d4-a716-446655440000",
"status": "active",
"post_no_debit": false,
"post_no_credit": false,
"updated_at": "2024-01-26T15:00:00Z"
},
"child_accounts": []
}Request Payload (Unblock)
{
"reason": "Investigation completed - legitimate activity confirmed",
"source": "compliance_cleared",
"unblock_debits": true,
"unblock_credits": true,
"metadata": {
"ticket_id": "FRAUD-2024-001",
"cleared_by": "compliance_officer",
"resolution": "false_positive"
}
}Close Account
/api/v1/admin/tenants/{tenantID}/accounts/{accountID}/closePermanently closes an account. The account must have zero balance. This action cannot be undone.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Closed account confirmation
{
"id": "acc_550e8400-e29b-41d4-a716-446655440000",
"status": "closed",
"account_code": "WLT-001234567",
"account_name": "John Doe",
"updated_at": "2024-01-27T10:00:00Z"
}Request Payload (Close)
{
"reason": "Customer requested account closure - all funds have been withdrawn",
"confirmation": "CLOSE_ACCOUNT",
"source": "customer_request",
"metadata": {
"support_ticket": "SUP-2024-001",
"requested_by": "customer_email@example.com"
}
}Entitlements
Understanding Entitlements
Entitlements are feature flags that control what capabilities a tenant has access to. They are organized by category and can include optional configuration parameters.
Entitlement Categories
| Category | Entitlements | Description |
|---|---|---|
| Identity | identity.read | Access to identity/customer profiles |
| Accounts | accounts.read, accounts.write, accounts.manage | Ledger account operations |
| Balances | balances.read | View account balances |
| Transactions | transactions.read, transactions.write | Transaction history and initiation |
| Reservations | reservations.read, reservations.write | Balance reservation management |
| Limits | limits.read, limits.evaluate | Transaction limit configuration |
| Statements | statements.read, statements.export, statements.email | Account statement generation |
| KYC | kyc.submit, kyc.read | Know Your Customer operations |
| Virtual Accounts | virtual_accounts.read, virtual_accounts.issue_static, virtual_accounts.issue_dynamic, virtual_accounts.sessions.read | Virtual account management |
| Payouts | payouts.write | Funds transfer/payout operations |
| Webhooks | webhooks.manage | Webhook endpoint configuration |
| POS | pos.profiles.read/write, pos.terminals.read/manage, pos.transactions.read/write, pos.processor_transactions.write, pos.settlements.read, pos.metrics.read | Point of Sale operations |
| Cards | cards.nfc.read, cards.nfc.manage, cards.nfc.assignments.manage, cards.nfc.limits.manage | NFC card management |
| Liquidity | liquidity.read | Liquidity monitoring |
Get Entitlements
/api/v1/admin/tenants/{tenantID}/entitlementsRetrieves all entitlements for a tenant with their current enabled/disabled status.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Tenant entitlements map
{
"tenant_id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"entitlements": {
"accounts.read": {
"enabled": true
},
"accounts.write": {
"enabled": true
},
"transactions.read": {
"enabled": true
},
"pos.terminals.manage": {
"enabled": true,
"config": {
"max_terminals": 100
}
},
"virtual_accounts.issue_static": {
"enabled": false
}
}
}Update Entitlements
/api/v1/admin/tenants/{tenantID}/entitlementsUpdates tenant entitlements. Only provided entitlements are modified; others remain unchanged.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Updated entitlements
{
"tenant_id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"entitlements": {
"pos.terminals.manage": {
"enabled": true,
"config": {
"max_terminals": 500
}
},
"virtual_accounts.issue_static": {
"enabled": true
}
}
}Request Payload (Update Entitlements)
{
"entitlements": {
"pos.terminals.manage": {
"enabled": true,
"config": {
"max_terminals": 500
}
},
"pos.transactions.write": {
"enabled": true
},
"virtual_accounts.issue_static": {
"enabled": true
},
"virtual_accounts.issue_dynamic": {
"enabled": true,
"config": {
"max_daily_issuance": 1000
}
},
"payouts.write": {
"enabled": true
}
}
}Common Entitlement Configurations
| Entitlement | Config Key | Type | Description |
|---|---|---|---|
| pos.terminals.manage | max_terminals | integer | Maximum POS terminals allowed |
| virtual_accounts.issue_dynamic | max_daily_issuance | integer | Maximum VAs per day |
| transactions.write | max_single_transaction | number | Maximum single transaction amount |
| payouts.write | allowed_destinations | array | Permitted payout banks/channels |
Tenant Fees
Fee Structure
Fees are rules that determine charges for various transaction types. Each fee rule specifies the channel, calculation method, and who pays/receives the fee.
Fee Channels
| Channel | Description |
|---|---|
| va_wallet_funding | Virtual account to wallet funding |
| va_payment | Virtual account payment |
| va_pos_payment | Virtual account POS payment |
| funds_transfer | Bank transfer/payout |
| pos_card_present | POS card transaction |
| pos_nfc_card | NFC card tap payment |
| nin_lookup | NIN verification lookup |
| bvn_lookup | BVN verification lookup |
Fee Payers
| Payer | Description |
|---|---|
| platform | Platform absorbs the fee |
| merchant | Merchant pays the fee |
| customer | Customer pays the fee |
| tenant | Tenant pays the fee |
| processor | Processor pays the fee |
Get Tenant Fees
/api/v1/admin/tenants/{tenantID}/feesRetrieves all fee rules configured for a tenant.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- List of fee rules
{
"fees": [
{
"id": "fee_550e8400-e29b-41d4-a716-446655440000",
"tenant_id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"channel": "pos_card_present",
"currency": "NGN",
"flat_amount": 5000,
"percentage_rate": 0.015,
"who_pays": "merchant",
"who_gets_paid": "platform",
"effective_from": "2024-01-01T00:00:00Z",
"created_at": "2024-01-01T00:00:00Z"
}
]
}Update Tenant Fees
/api/v1/admin/tenants/{tenantID}/feesReplaces all fee rules for a tenant. This is a full replacement - include all rules you want to keep.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Updated fee rules
{
"fees": [
{
"id": "fee_new_550e8400",
"channel": "pos_card_present",
"currency": "NGN",
"flat_amount": 5000,
"percentage_rate": 0.012,
"who_pays": "merchant",
"effective_from": "2024-02-01T00:00:00Z"
}
]
}Request Payload (Update Fees)
{
"rules": [
{
"channel": "pos_card_present",
"currency": "NGN",
"flat_amount": 5000,
"percentage_rate": 0.012,
"who_pays": "merchant",
"who_gets_paid": "platform",
"effective_from": "2024-02-01T00:00:00Z"
},
{
"channel": "funds_transfer",
"currency": "NGN",
"flat_amount": 2500,
"percentage_rate": 0,
"min_amount": 10000,
"max_amount": 50000000,
"who_pays": "customer",
"who_gets_paid": "platform",
"effective_from": "2024-02-01T00:00:00Z"
},
{
"channel": "va_wallet_funding",
"currency": "NGN",
"flat_amount": 0,
"percentage_rate": 0.005,
"who_pays": "customer",
"who_gets_paid": "platform",
"effective_from": "2024-02-01T00:00:00Z"
}
]
}Transaction Limits
Limit Structure
Transaction limits control the maximum amounts users can transact based on their KYC tier. Limits are defined per direction (inbound/outbound) and time window (daily/monthly).
KYC Tiers
| Tier | Description | Typical Limits |
|---|---|---|
| tier1 | Basic verification (phone only) | Low limits, suitable for basic use |
| tier2 | Standard verification (ID + photo) | Medium limits for regular users |
| tier3 | Full verification (address proof) | High limits for premium users |
Limit Parameters
| Parameter | Description |
|---|---|
| direction | inbound (deposits) or outbound (withdrawals/payments) |
| window | daily or monthly accumulation period |
| amount | Maximum cumulative amount in the window |
| max_balance | Maximum account balance allowed (optional) |
Get Tenant Limits
/api/v1/admin/tenants/{tenantID}/limitsRetrieves all transaction limits configured for a tenant.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- List of transaction limits by KYC tier
{
"limits": [
{
"tenant_id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"kyc_level": "tier1",
"direction": "inbound",
"window": "daily",
"amount": 50000,
"max_balance": 200000,
"updated_at": "2024-01-15T10:00:00Z"
},
{
"tenant_id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"kyc_level": "tier2",
"direction": "inbound",
"window": "daily",
"amount": 500000,
"max_balance": 2000000,
"updated_at": "2024-01-15T10:00:00Z"
}
]
}Update Tenant Limits
/api/v1/admin/tenants/{tenantID}/limitsUpdates transaction limits for a tenant. Replaces all limits with the provided configuration.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Updated limits
{
"limits": [
{
"kyc_level": "tier1",
"direction": "inbound",
"window": "daily",
"amount": 100000,
"updated_at": "2024-01-25T10:00:00Z"
}
]
}Request Payload (Update Limits)
{
"limits": [
{
"kyc_level": "tier1",
"direction": "inbound",
"window": "daily",
"amount": 100000,
"max_balance": 300000
},
{
"kyc_level": "tier1",
"direction": "outbound",
"window": "daily",
"amount": 50000
},
{
"kyc_level": "tier2",
"direction": "inbound",
"window": "daily",
"amount": 1000000,
"max_balance": 5000000
},
{
"kyc_level": "tier2",
"direction": "outbound",
"window": "daily",
"amount": 500000
},
{
"kyc_level": "tier3",
"direction": "inbound",
"window": "daily",
"amount": 10000000,
"max_balance": 50000000
},
{
"kyc_level": "tier3",
"direction": "outbound",
"window": "daily",
"amount": 5000000
}
]
}Tenant Webhooks
Webhook System
Webhooks allow tenants to receive real-time notifications when events occur. Platform admins can manage webhook endpoints on behalf of tenants.
Available Events
| Event | Description |
|---|---|
| account.created | New account created |
| account.updated | Account details modified |
| account.blocked | Account was blocked |
| account.unblocked | Account was unblocked |
| account.closed | Account was permanently closed |
| transaction.completed | Transaction successfully processed |
| transaction.failed | Transaction failed |
| transaction.reversed | Transaction was reversed |
| kyc.submitted | KYC application submitted |
| kyc.approved | KYC application approved |
| kyc.rejected | KYC application rejected |
| virtual_account.created | Virtual account created |
| virtual_account.expired | Virtual account expired |
| pos.transaction.completed | POS transaction completed |
| pos.settlement.completed | POS settlement batch completed |
Create Webhook Endpoint
/api/v1/admin/tenants/{tenantID}/webhooks/endpointsCreates a new webhook endpoint for the tenant. A signing secret is automatically generated.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Created webhook endpoint with signing secret
{
"id": "wh_550e8400-e29b-41d4-a716-446655440000",
"url": "https://api.acme.com/webhooks/walletcore",
"events": [
"transaction.completed",
"transaction.failed"
],
"description": "Production transaction events",
"is_active": true,
"secret_masked": "wh_sec_****abcd",
"signing_secret": "wh_sec_a1b2c3d4e5f6g7h8i9j0",
"created_at": "2024-01-20T10:00:00Z"
}Request Payload (Create Webhook)
{
"url": "https://api.acme.com/webhooks/walletcore",
"events": [
"transaction.completed",
"transaction.failed",
"transaction.reversed",
"account.created",
"kyc.approved",
"kyc.rejected"
],
"description": "Production webhook for all critical events"
}List Webhook Endpoints
/api/v1/admin/tenants/{tenantID}/webhooks/endpointsRetrieves all webhook endpoints for a tenant.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- List of webhook endpoints
{
"endpoints": [
{
"id": "wh_550e8400-e29b-41d4-a716-446655440000",
"url": "https://api.acme.com/webhooks/walletcore",
"events": [
"transaction.completed",
"transaction.failed"
],
"is_active": true,
"secret_masked": "wh_sec_****abcd",
"created_at": "2024-01-20T10:00:00Z"
}
]
}Get Webhook Endpoint
/api/v1/admin/tenants/{tenantID}/webhooks/endpoints/{id}Retrieves details of a specific webhook endpoint.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Webhook endpoint details
{
"id": "wh_550e8400-e29b-41d4-a716-446655440000",
"url": "https://api.acme.com/webhooks/walletcore",
"events": [
"transaction.completed",
"transaction.failed"
],
"description": "Production transaction events",
"is_active": true,
"secret_masked": "wh_sec_****abcd",
"created_at": "2024-01-20T10:00:00Z"
}Update Webhook Endpoint
/api/v1/admin/tenants/{tenantID}/webhooks/endpoints/{id}Updates a webhook endpoint. Can modify URL, events, description, or rotate the signing secret.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Updated webhook endpoint (includes new secret if rotated)
{
"id": "wh_550e8400-e29b-41d4-a716-446655440000",
"url": "https://api.acme.com/webhooks/v2/walletcore",
"events": [
"transaction.completed",
"transaction.failed",
"kyc.approved"
],
"is_active": true,
"signing_secret": "wh_sec_new_secret_here"
}Request Payload (Update Webhook)
{
"url": "https://api.acme.com/webhooks/v2/walletcore",
"events": [
"transaction.completed",
"transaction.failed",
"kyc.approved",
"kyc.rejected"
],
"rotate_secret": true
}Delete Webhook Endpoint
/api/v1/admin/tenants/{tenantID}/webhooks/endpoints/{id}Permanently deletes a webhook endpoint.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Empty response with 204 No Content
Get Webhook Stats
/api/v1/admin/tenants/{tenantID}/webhooks/endpoints/{id}/statsRetrieves delivery statistics for a webhook endpoint.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Webhook delivery statistics
{
"total_deliveries": 15420,
"success_count": 15350,
"failure_count": 70,
"success_rate": 99.55,
"avg_response_time_ms": 145,
"last_success": "2024-01-25T14:30:00Z",
"last_failure": "2024-01-24T08:15:00Z"
}Test Webhook Endpoint
/api/v1/admin/tenants/{tenantID}/webhooks/endpoints/{id}/testSends a test event to the webhook endpoint to verify connectivity.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Content-Type | string | Yes | application/json |
Response- Test delivery result
{
"test_event_id": "evt_550e8400-e29b-41d4-a716-446655440000",
"delivered": true,
"http_status": 200,
"response_time_ms": 125,
"message": "Webhook test event delivered successfully"
}Request Payload (Test Webhook)
{
"event_type": "transaction.completed"
}KYC & Liquidity
KYC Summary
View aggregate KYC statistics for a tenant's customers.
Get KYC Summary
/api/v1/admin/tenants/{tenantID}/kyc/summaryRetrieves KYC application counts by status for the tenant.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- KYC status summary
{
"tenant_id": "tnt_550e8400-e29b-41d4-a716-446655440000",
"counts": {
"pending": 45,
"approved": 1250,
"rejected": 23
},
"updated_at": "2024-01-25T10:00:00Z"
}Liquidity Monitoring
Liquidity snapshots track the relationship between customer liabilities (what you owe customers) and available funds (what you have). This helps ensure you can honor all withdrawal requests.
Liquidity Metrics
| Metric | Description | Healthy Range |
|---|---|---|
| total_customer_liabilities | Sum of all customer balances | Baseline |
| total_available_liquidity | Funds available to cover liabilities | >= liabilities |
| liquidity_shortfall | Gap when liquidity < liabilities | Should be 0 |
| liquidity_surplus | Excess when liquidity > liabilities | Positive |
| coverage_ratio | Liquidity / Liabilities * 100 | >= 100% |
| buffer_percent | Extra cushion above requirements | 5-10% recommended |
Get Latest Liquidity Snapshot
/api/v1/admin/tenants/{tenantID}/liquidity/snapshots/latestRetrieves the most recent liquidity snapshot for each currency.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Latest liquidity snapshots by currency
{
"snapshots": [
{
"snapshot_id": "liq_550e8400-e29b-41d4-a716-446655440000",
"currency": "NGN",
"snapshot_at": "2024-01-25T10:00:00Z",
"total_customer_liabilities": 125000000,
"total_available_liquidity": 132500000,
"liquidity_shortfall": 0,
"liquidity_surplus": 7500000,
"coverage_ratio": 106,
"buffer_percent": 6,
"created_at": "2024-01-25T10:00:00Z"
}
]
}List Liquidity Snapshots
/api/v1/admin/tenants/{tenantID}/liquidity/snapshotsRetrieves historical liquidity snapshots with filtering and pagination.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Paginated liquidity snapshots
{
"snapshots": [
{
"snapshot_id": "liq_550e8400",
"currency": "NGN",
"snapshot_at": "2024-01-25T10:00:00Z",
"coverage_ratio": 106
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total_count": 720
}
}Get Liquidity Snapshot Detail
/api/v1/admin/tenants/{tenantID}/liquidity/snapshots/{snapshotID}Retrieves detailed breakdown of a specific liquidity snapshot.
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {admin_access_token} |
Response- Detailed liquidity snapshot with breakdown
{
"snapshot": {
"snapshot_id": "liq_550e8400-e29b-41d4-a716-446655440000",
"currency": "NGN",
"snapshot_at": "2024-01-25T10:00:00Z",
"total_customer_liabilities": 125000000,
"total_available_liquidity": 132500000,
"coverage_ratio": 106
},
"breakdown": {
"by_wallet_type": {
"customer": 85000000,
"business": 30000000,
"merchant": 10000000
}
}
}Best Practices
Tenant Onboarding Checklist
| Step | Action | Notes |
|---|---|---|
| 1 | Create tenant with partner details | Verify email address is correct |
| 2 | Configure entitlements | Start with minimal permissions, expand as needed |
| 3 | Set up transaction limits | Consider business type and expected volume |
| 4 | Configure fees | Align with commercial agreement |
| 5 | Invite initial users | Start with owner/admin roles |
| 6 | Create API keys | Production and test keys with appropriate scopes |
| 7 | Set up webhooks | Critical events: transactions, KYC |
| 8 | Verify integration | Test API calls and webhook delivery |
Security Recommendations
| Area | Recommendation |
|---|---|
| API Keys | Set expiration dates, use least-privilege scopes |
| Webhooks | Always validate signatures, use HTTPS only |
| User Access | Regular access reviews, revoke inactive users |
| Entitlements | Grant only necessary permissions |
| Account Operations | Document reasons for block/unblock actions |
Monitoring Alerts
Key metrics to monitor for tenant health.
| Metric | Warning Threshold | Action |
|---|---|---|
| Coverage ratio | < 105% | Review liquidity position |
| Webhook failure rate | > 5% | Check endpoint health |
| KYC rejection rate | > 20% | Review submission quality |
| API rate limit hits | > 100/day | Consider increasing limits |
| Blocked accounts | > 10/day | Investigate fraud patterns |