Integrate with Interswitch APIs for payment processing, transfers, bill payments, and collections across Nigeria and Africa. Use this skill when building payment platforms, fintech solutions, merchant networks, or payment collection systems. Trigger on requests mentioning: Interswitch, Quickteller Business, payment switches, bank transfers, bill payments, payment collections, or merchant payment routing.
⚠️ Product scope: Interswitch operates a multi-product ecosystem — Quickteller Business, WebPay, ISW Pay, Passport, and Open Banking APIs. This skill covers the Quickteller Business / WebPay merchant payment collection and disbursement APIs. Other products have separate documentation and credentials at developer.interswitchgroup.com.
⚠️ Partnership access required. Interswitch is not self-service. Apply at developer.interswitchgroup.com or via an Interswitch sales contact. Allow 1–3 weeks for onboarding. Sandbox access is granted separately from production.
⚠️ Verify HMAC signature format during onboarding. The signature formula documented here (Base64(HMAC-SHA256(clientId:timestamp:nonce:targetUrl, clientSecret))) follows available documentation but may vary by product version. Confirm the exact concatenation order using test tools in your Interswitch developer dashboard before going live.
ℹ️ Developer portal updated (2024–2025). Interswitch has significantly updated their portal. Some legacy endpoint paths may have been deprecated. If an endpoint returns 404, check developer.interswitchgroup.com for the current path.
Interswitch is Africa's largest payments switching and settlement infrastructure provider, operating a network connecting 3,000+ merchants, all major Nigerian banks, mobile operators, and utility service providers. The platform enables developers to build scalable payment solutions with unified APIs for transfers, collections, bill payments, and transaction management.
You're building a payment platform that needs to serve Nigeria's financial ecosystem with:
Interswitch abstracts away the complexity of Nigeria's fragmented banking infrastructure, providing a single integration point for accessing the entire financial network. This makes it ideal for fintech apps, enterprise payment systems, marketplaces, and e-commerce platforms.
Interswitch uses OAuth 2.0 client credentials flow combined with signature-based security headers.
Use your Client ID and Secret Key (provided in the Interswitch Developer Console) to request an access token via OAuth 2.0.
Endpoint: POST /passport/oauth/token (Sandbox) or POST https://api-gateway.interswitchng.com/passport/oauth/token (Production)
Headers:
Authorization: Basic base64(client_id:secret_key)
Content-Type: application/x-www-form-urlencoded
Body:
grant_type=client_credentials
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write"
}
Important: Tokens expire after 1 hour. Implement token caching and refresh logic before expiry.
All subsequent API requests must include the access token in the Authorization header:
Authorization: Bearer {access_token}
X-Access-Signature: {signature}
Timestamp: {unix_timestamp}
Nonce: {random_nonce}
SignatureMethod: SHA256
Store credentials securely in environment variables:
INTERSWITCH_CLIENT_ID=your_client_id
INTERSWITCH_SECRET_KEY=your_secret_key
INTERSWITCH_MERCHANT_CODE=your_merchant_code
https://sandbox.interswitchng.comhttps://api-gateway.interswitchng.com and https://live.interswitchng.comAuthenticate separately for sandbox and production using different credentials.
Transfer funds to any Nigerian bank account using NUBAN (11-digit Nigerian Uniform Bank Account Number).
Endpoint: POST /api/v2/quickteller/payments/transfers
Headers:
Authorization: Bearer {access_token}
X-Access-Signature: {signature}
Content-Type: application/json
Timestamp: {unix_timestamp}
Nonce: {random_nonce}
SignatureMethod: SHA256
Request Body:
{
"amount": 100000,
"currency": "NGN",
"beneficiary": {
"name": "Chinedu Adeyemi",
"bankCode": "058",
"accountNumber": "0123456789"
},
"narration": "Payment for services rendered",
"reference": "TRF-2025-001",
"transactionRef": "REF-2025-001"
}
Response (Success):
{
"responseCode": "00",
"responseMessage": "Transfer initiated successfully",
"data": {
"transactionId": "TXN_12345abcde",
"reference": "TRF-2025-001",
"amount": 100000,
"currency": "NGN",
"status": "Processing",
"timestamp": "2026-02-24T14:30:00Z",
"beneficiary": {
"accountNumber": "0123456789",
"bankCode": "058",
"name": "Chinedu Adeyemi"
}
}
}
Important Notes:
reference and transactionRef must be globally unique per transaction.Poll the status of a submitted transfer transaction.
Endpoint: GET /api/v2/quickteller/payments/transfers/status
Query Parameters:
reference=TRF-2025-001
Response:
{
"responseCode": "00",
"responseMessage": "Transfer status retrieved",
"data": {
"reference": "TRF-2025-001",
"transactionId": "TXN_12345abcde",
"amount": 100000,
"currency": "NGN",
"status": "Completed",
"completedAt": "2026-02-24T14:31:00Z",
"beneficiaryAccount": "0123456789",
"beneficiaryBank": "Guaranty Trust Bank",
"beneficiaryAccountName": "Chinedu Adeyemi"
}
}
Status Values:
Pending - Transfer submitted, awaiting processingProcessing - Transfer in progressCompleted - Transfer succeededFailed - Transfer failed; check error detailsValidate a bank account before initiating a transfer. Returns the registered account holder name.
Endpoint: GET /api/v2/quickteller/banks/account/verify
Query Parameters:
bankCode=058
accountNumber=0123456789
Response (Success):
{
"responseCode": "00",
"responseMessage": "Account verified",
"data": {
"accountName": "Chinedu Adeyemi",
"accountNumber": "0123456789",
"bankCode": "058",
"bankName": "Guaranty Trust Bank"
}
}
Response (Failed):
{
"responseCode": "05",
"responseMessage": "Account validation failed - invalid account",
"data": null
}
Important Notes:
accountName against expected recipient name.Retrieve all banks and their CBN codes supported by Interswitch for transfers.
Endpoint: GET /api/v2/quickteller/banks
Response:
{
"responseCode": "00",
"responseMessage": "Banks retrieved successfully",
"data": [
{
"bankCode": "033",
"bankName": "United Bank for Africa (UBA)",
"bankSlug": "uba",
"isActive": true
},
{
"bankCode": "058",
"bankName": "Guaranty Trust Bank",
"bankSlug": "gtb",
"isActive": true
},
{
"bankCode": "044",
"bankName": "Access Bank",
"bankSlug": "access-bank",
"isActive": true
},
{
"bankCode": "050",
"bankName": "Ecobank",
"bankSlug": "ecobank",
"isActive": true
}
]
}
Important Notes:
isActive: true.Create a payment collection session. Direct customer to the checkout URL to complete payment via card, bank transfer, or USSD.
Endpoint: POST /collections/api/v1/pay
Headers:
Authorization: Bearer {access_token}
Content-Type: application/json
Request Body:
{
"amount": 50000,
"customerName": "Amina Okafor",
"customerEmail": "[email protected]",
"customerMobile": "+2348012345678",
"narration": "Invoice INV-2025-001 payment",
"paymentReference": "PAY-2025-001",
"currency": "NGN",
"redirectUrl": "https://yoursite.com/payment/callback",
"merchantCode": "your_merchant_code",
"payItemId": "your_payitem_id"
}
Response:
{
"responseCode": "00",
"responseMessage": "Payment session initiated successfully",
"data": {
"checkoutUrl": "https://checkout.interswitch.com/pay/v3/abc123def456",
"sessionId": "SESSION_XYZ789",
"paymentReference": "PAY-2025-001",
"amount": 50000,
"currency": "NGN",
"status": "Initiated",
"expiresAt": "2026-02-25T14:30:00Z"
}
}
Important Notes:
paymentReference must be unique and never reused.checkoutUrl to complete payment.redirectUrl or you receive a webhook notification.Retrieve full transaction details to verify payment completion.
Endpoint: GET /collections/api/v1/gettransaction.json
Query Parameters:
transactionRef=PAY-2025-001
amount=50000
Response (Successful Payment):
{
"isSuccessful": true,
"message": "Transaction Successful",
"responseCode": "00",
"data": {
"transactionRef": "PAY-2025-001",
"amount": 50000,
"transactionStatus": "Paid",
"paymentMethod": "Card",
"paymentMethodDetails": {
"cardType": "Visa",
"cardLast4": "1234",
"cardBrand": "VISA"
},
"datePaid": "2026-02-24T15:45:00Z",
"customerEmail": "[email protected]",
"customerName": "Amina Okafor",
"transactionHash": "hash_abc123def456"
}
}
Response (Failed Payment):
{
"isSuccessful": false,
"message": "Transaction Failed",
"responseCode": "01",
"data": {
"transactionRef": "PAY-2025-001",
"amount": 50000,
"transactionStatus": "Failed",
"failureReason": "Card declined by issuer"
}
}
Important Notes:
amount in response matches your expected amount (prevents amount manipulation).transactionStatus: "Paid" for successful payments.Retrieve available billers for bill payment services (electricity, water, government services, etc.).
Endpoint: GET /quickteller/bills/billers
Query Parameters (Optional):
categoryId=1 (Optional: filter by category)
pageSize=100
pageNumber=1
Response:
{
"responseCode": "00",
"responseMessage": "Billers retrieved successfully",
"data": {
"billers": [
{
"billerId": "407",
"billerName": "AEDC (Abuja Distribution Company)",
"billerCode": "AEDC",
"categoryId": "1",
"categoryName": "Electricity",
"customerFieldName": "Meter Number",
"logo": "https://s3.amazonaws.com/aedc-logo.png",
"surcharge": 0,
"isActive": true
},
{
"billerId": "415",
"billerName": "IKEDC (Ikeja Distribution Company)",
"billerCode": "IKEDC",
"categoryId": "1",
"categoryName": "Electricity",
"customerFieldName": "Meter Number",
"logo": "https://s3.amazonaws.com/ikedc-logo.png",
"surcharge": 0,
"isActive": true
}
],
"totalCount": 150,
"pageSize": 100,
"pageNumber": 1
}
}
Important Notes:
billerId in bill payment requests.Process a bill payment to a biller.
Endpoint: POST /quickteller/bills/pay
Request Body:
{
"billerId": "407",
"amount": 10000,
"currency": "NGN",
"customerRef": "METER123456",
"phoneNumber": "+2348012345678",
"email": "[email protected]",
"reference": "BILL-2025-001"
}
Response:
{
"responseCode": "00",
"responseMessage": "Bill payment processed successfully",
"data": {
"transactionId": "BILL_TXN_12345",
"reference": "BILL-2025-001",
"billerId": "407",
"billerName": "AEDC",
"amount": 10000,
"status": "Processing",
"timestamp": "2026-02-24T16:00:00Z"
}
}
Purchase airtime or data bundles for mobile networks.
Endpoint: POST /quickteller/airtime/recharge
Request Body:
{
"phoneNumber": "+2348012345678",
"amount": 1000,
"networkCode": "1",
"reference": "AIRTIME-2025-001",
"serviceType": "Airtime"
}
Response:
{
"responseCode": "00",
"responseMessage": "Airtime purchase successful",
"data": {
"transactionId": "AIRTIME_TXN_12345",
"phoneNumber": "+2348012345678",
"amount": 1000,
"networkName": "MTN",
"status": "Completed",
"reference": "AIRTIME-2025-001"
}
}
Network Codes:
1 - MTN2 - Airtel3 - GLO4 - 9MobileInterswitch sends real-time webhook notifications for transaction events. Always verify webhook signatures before processing.
All webhooks are signed with HmacSHA512 using your secret key. Verify before processing:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secretKey) {
const hash = crypto
.createHmac('sha512', secretKey)
.update(JSON.stringify(payload))
.digest('hex');
return hash === signature;
}
// Express.js example
app.post('/webhooks/interswitch', (req, res) => {
const signature = req.headers['x-interswitch-signature'];
const payload = req.body;
if (!verifyWebhookSignature(payload, signature, process.env.INTERSWITCH_SECRET_KEY)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
handleWebhookEvent(payload);
// Return 200 to acknowledge receipt
res.status(200).json({ success: true });
});
Event: Transaction Completed
{
"eventId": "evt_abc123def456",
"eventType": "TRANSACTION.COMPLETED",
"timestamp": "2026-02-24T16:30:00Z",
"data": {
"transactionRef": "PAY-2025-001",
"paymentReference": "PAY-2025-001",
"amount": 50000,
"currency": "NGN",
"responseCode": "00",
"responseMessage": "Transaction successful",
"transactionStatus": "Paid",
"customerEmail": "[email protected]",
"paymentMethod": "Card",
"merchantCode": "MX123",
"dateCompleted": "2026-02-24T16:30:00Z"
}
}
Event: Transaction Failed
{
"eventId": "evt_xyz789abc123",
"eventType": "TRANSACTION.FAILED",
"timestamp": "2026-02-24T16:35:00Z",
"data": {
"transactionRef": "PAY-2025-002",
"paymentReference": "PAY-2025-002",
"amount": 75000,
"currency": "NGN",
"responseCode": "05",
"responseMessage": "Transaction failed",
"failureReason": "Card declined by issuer",
"customerEmail": "[email protected]",
"merchantCode": "MX123"
}
}
Event: Transfer Completed
{
"eventId": "evt_transfer_123",
"eventType": "TRANSFER.COMPLETED",
"timestamp": "2026-02-24T16:45:00Z",
"data": {
"reference": "TRF-2025-001",
"transactionId": "TXN_12345abcde",
"amount": 100000,
"currency": "NGN",
"status": "Completed",
"beneficiary": {
"accountNumber": "0123456789",
"bankCode": "058",
"bankName": "Guaranty Trust Bank"
}
}
}
Set your webhook URL in the Interswitch Dashboard under Integration Settings:
https://yoursite.com/webhooks/interswitchCollect payments from customers via Interswitch checkout:
1. POST /collections/api/v1/pay
↓ Response with checkoutUrl and sessionId
2. Redirect customer to checkoutUrl
↓ Customer completes payment
3. Listen for webhook TRANSACTION.COMPLETED
↓ OR
Poll GET /collections/api/v1/gettransaction.json
↓ Verify transactionStatus: "Paid"
4. Fulfill order/service
5. Confirm to customer
Implementation Checklist:
paymentReference for each sessionsessionId for reconciliationTransfer funds to customer or vendor accounts:
1. Collect destination bank details from user
2. GET /api/v2/quickteller/banks/account/verify
↓ Verify accountName matches expected recipient
3. Prompt user to confirm ("Send ₦500 to Chinedu Adeyemi?")
4. POST /api/v2/quickteller/payments/transfers
↓ Store transactionId and reference
5. Listen for webhook TRANSFER.COMPLETED
↓ OR
Poll GET /api/v2/quickteller/payments/transfers/status
↓ Check status transitions (Processing → Completed/Failed)
6. Update user dashboard with final status
7. Send confirmation notification
Security Considerations:
Build a bill payment aggregator:
1. GET /quickteller/bills/billers (cache daily)
2. Display billers grouped by category
3. User selects biller and enters meter/account number
4. POST /collections/api/v1/pay with billerId and amount
5. Redirect to checkout OR auto-deduct if enabled
6. Webhook notifies of payment completion
7. Auto-submit payment to biller using Interswitch's backend integration
8. Update customer's service (electricity restored, balance updated, etc.)
Optimization Tips:
Set up subscription billing:
1. Initialize first payment via /collections/api/v1/pay
2. Store card reference or customer token from successful payment
3. On subscription renewal date:
POST /collections/api/v1/pay with stored card reference
4. Webhook notifies of payment success/failure
5. If failed, retry 3 times over 7 days
6. Send notification to customer
7. Resume/suspend service based on payment status
All Interswitch API responses include a responseCode field. Always check this first:
| Code | Meaning | Action |
|---|---|---|
00 | Success | Proceed with transaction |
01 | Invalid credentials / Unauthorized | Check API keys and token expiry |
02 | Invalid request / Bad format | Validate request body against schema |
03 | Transaction not found | Verify transaction reference |
04 | Insufficient funds | Retry or inform customer to add funds |
05 | Account validation failed | Confirm account details with user |
06 | Duplicate transaction | Use unique references; check for previous attempt |
07 | Daily limit exceeded | Inform customer of transaction limits |
09 | Parameter/data missing | Check all required fields are provided |
13 | Merchant not configured | Verify merchant code in dashboard |
99 | Server error / Timeout | Retry with exponential backoff |
{
"responseCode": "05",
"responseMessage": "Account validation failed - account not found",
"data": {
"errorDetails": "The specified account number does not exist",
"suggestedAction": "Verify account number and bank code"
}
}
Implement exponential backoff for retryable errors (99 and some 04 responses):
async function retryWithBackoff(fn, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries || !isRetryable(error)) {
throw error;
}
const delay = Math.pow(2, attempt - 1) * 1000; // 1s, 2s, 4s
await sleep(delay);
}
}
}
function isRetryable(error) {
const retryableCodes = ['99', '04'];
return retryableCodes.includes(error.responseCode);
}
1. Amount Units (Kobo, Not Naira)
500 instead of 50000const naira = 500;
const kobo = naira * 100; // 50000
2. Bank Code Validation
/api/v2/quickteller/banks list3. Unique References (Critical)
REF-${Date.now()}-${randomId()}4. Account Verification Before Transfer
/api/v2/quickteller/banks/account/verify before transferaccountName against user's expected recipient5. Token Management
6. Webhook Security
7. Response Code Checking (Always!)
responseCode: "00" before processing any response8. Sandbox vs Production Differences
9. Polling vs Webhooks
10. Customer Name Verification
Scenario: "Insufficient funds" error during transfer
Scenario: "Duplicate transaction" error
Scenario: Account verification returns not found
/api/v2/quickteller/banksScenario: Webhook not received but payment succeeded
Official Documentation:
Sandbox Testing:
5555555555554444 (Visa)Security:
Community & Support:
Before going live with Interswitch: