NUBAN account resolution
NGN account numbers (NUBAN — Nigerian Uniform Bank Account Number) can be looked up against any Nigerian bank to retrieve the bank-of-record holder name. Swappr handles this automatically on every NGN payout, but you can also call the lookup yourself for confirmation flows.
Why it matters
NGN account numbers are 10 digits, and the same number could exist at multiple banks. The pair (account_number, bank_code) uniquely identifies an account. When you submit a payout, we always verify the recipient at the bank rail and overwrite any name you supplied with the bank-of-record value — the bank is the source of truth, not the input.
This protects against:
- Customer typos in account numbers
- Phishing scams where the wrong account is impersonated as the right person
- Fraud where merchant supplies a clean name but routes money elsewhere
Pre-payout confirmation
Use the name enquiry endpoint to confirm the recipient BEFORE submitting the payout — particularly useful when your end-user types account details and you want to show “You’re paying: X” before they click Send.
import { randomUUID } from 'crypto';
async function confirmRecipient(accountNumber: string, bankCode: string) {
const res = await fetch('https://api.swappr.me/v1/name-enquiry', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SWAPPR_API_KEY}`,
'Idempotency-Key': randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
account_number: accountNumber,
bank_code: bankCode,
currency: 'NGN',
}),
});
if (res.status === 422) {
return { ok: false, error: 'unresolvable' };
}
if (!res.ok) {
return { ok: false, error: 'provider_error' };
}
const data = await res.json();
return { ok: true, name: data.resolved_name, source: data.source };
}
// In your UI flow
const result = await confirmRecipient('0690000032', '044');
if (result.ok) {
showConfirmation(`You're sending money to ${result.name}. Confirm?`);
} else if (result.error === 'unresolvable') {
showError('Could not verify this account. Check the details.');
}How the cascade works
When you call name-enquiry (or send a payout), Swappr walks a routing cascade:
- Beneficiary cache — if you’ve previously paid this
(merchant, account, bank)successfully, we return the cached name instantly. - Provider cascade — eligible providers ordered by capability. We try each in order until one returns a successful resolve OR all are exhausted.
Live env runs the full cascade; sandbox uses a single configured resolver (Technest picks the highest-quota rail to keep integration tests unblocked). For details, see Name enquiry.
Bank codes
Pass the CBN 3-digit code, NOT the NIBSS NIP code. Some upstream rails want NIP codes natively — Swappr handles the translation server-side, you always pass CBN.
Get the bank list from GET /v1/banks?currency=NGN. Cache locally for hours.
const banks = await fetch('https://api.swappr.me/v1/banks?currency=NGN', {
headers: { 'Authorization': `Bearer ${API_KEY}` },
}).then(r => r.json());
console.log(banks.data); // [{code: '044', name: 'Access Bank', slug: 'access-bank', kind: 'dmb'}, ...]Common errors
recipient_unresolvable
Every eligible provider returned “unresolvable” for the account. Most commonly:
- Wrong bank code (e.g. supplied 044 for an account that’s actually at 058)
- Account closed
- Typo in account number (one digit off)
Show the user a friendly “Check the account details” prompt + let them retry.
provider_error
Every upstream rail errored simultaneously (rare — usually transient). Retry with the same idempotency key after a few seconds.
Caching considerations
The source field in the response tells you where the name came from:
beneficiary_cache— already saved + verified for THIS merchant. Free, instant.provider— live upstream lookup. Counts toward your rail quotas.
If the same end-user pays the same recipient repeatedly, save the beneficiary via POST /v1/beneficiaries and subsequent payouts to that account use the cache automatically.