react-nomba-checkout-sdk
v2.1.5
Published
Nomba checkout sdk for react apps.
Downloads
722
Readme
🚀 React Nomba Checkout SDK
The react-nomba-checkout-sdk is a lightweight React SDK designed to simplify payment processing and checkout integration using Nomba's secure and reliable infrastructure.
Built with ❤️ by Israel Itua
🗺️ How It Works
Here's the full journey from signup to your first successful payment:
1. Create a Nomba business account at dashboard.nomba.com
↓
2. Go to Developer > API Keys > Test tab (sandbox) or Live tab (production)
↓
3. Copy your Client ID and Account ID
↓
4. Install the SDK and pass your credentials + environment
↓
5. Test your integration in sandbox mode
↓
6. Switch environment to 'live' and go to production✅ Prerequisites
Before writing any code, you need a Nomba business account and your API credentials.
Step 1 — Create a Nomba Account
Sign up at dashboard.nomba.com. Complete your KYC verification to unlock full access.
Step 2 — Get Your API Credentials
- Log in to the Nomba dashboard
- In the left sidebar, click Developer
- Click API Keys
- Use the Test tab for sandbox credentials, Live tab for production
You will see three values:
| Dashboard Label | Description | Used as |
|----------------|-------------|---------|
| Client ID | Your public API key | clientId and order.customerId |
| Account ID | Your Nomba account identifier | accountId and order.accountId |
| Private Key | For backend/server use only | Not used in the SDK |
Note: The Client ID is your public key. The Private Key is for server-side use only — never expose it in your frontend code.
📦 Installation
You can install the SDK using npm or yarn:
npm install react-nomba-checkout-sdk
# or
yarn add react-nomba-checkout-sdk⚡ Quick Start (React)
Here's how to integrate the SDK into your React project:
import { useState } from 'react';
import {
useNombaCheckout,
InitializeNombaCheckout,
} from 'react-nomba-checkout-sdk';
import './App.css';
// Initialize Nomba Checkout on app load
InitializeNombaCheckout();
function App() {
const [isLoading, setIsLoading] = useState(false);
const handleCheckout = async () => {
setIsLoading(true);
const res = await useNombaCheckout({
accountId: 'your-account-id',
clientId: 'your-client-id',
order: {
callbackUrl: 'sample-url',
customerEmail: '[email protected]',
amount: '10.00',
currency: 'NGN',
orderMetaData: {
customMerchant: 'true',
},
splitRequest: {
splitType: 'PERCENTAGE',
splitList: [
{
accountId: 'your-account-id',
value: '65.45',
},
],
},
},
tokenizeCard: 'true',
onCreateOrder: (orderReference) => {
console.log('Function called after the order is created');
console.log({ orderReference });
setIsLoading(false);
},
onFailure: (err) => {
console.log('Function called if error occurs while creating order.');
console.log(err);
setIsLoading(false);
},
onClose: () => {
console.log('Function called when modal is closed.');
setIsLoading(false);
},
onPaymentSuccess: (successResponse) => {
console.log('Function called on payment success.');
console.log({ successResponse });
},
});
};
return (
<>
<h1>Pay with Nomba</h1>
<button onClick={handleCheckout}>
{isLoading ? 'Please wait...' : 'Pay with Nomba Checkout'}
</button>
</>
);
}
export default App;🔥 Next.js Integration (App Router)
For Next.js 13+ with App Router, follow this setup to ensure proper client-side rendering:
Step 1: Create the Checkout Component
Create components/NombaCheckoutButton.tsx:
'use client';
import { useState, useEffect } from 'react';
import {
useNombaCheckout,
InitializeNombaCheckout,
} from 'react-nomba-checkout-sdk';
export default function NombaCheckoutButton() {
const [isLoading, setIsLoading] = useState(false);
const [isInitialized, setIsInitialized] = useState(false);
useEffect(() => {
InitializeNombaCheckout();
setIsInitialized(true);
}, []);
const handleCheckout = async () => {
if (!isInitialized) {
console.log('SDK not initialized yet');
return;
}
setIsLoading(true);
const res = await useNombaCheckout({
accountId: 'your-account-id',
clientId: 'your-client-id',
order: {
callbackUrl: 'https://your-callback-url.com',
customerEmail: '[email protected]',
amount: '10.00',
currency: 'NGN',
orderMetaData: {
customMerchant: 'true',
},
splitRequest: {
splitType: 'PERCENTAGE',
splitList: [
{
accountId: 'your-account-id',
value: 65.45,
},
],
},
orderReference: 'your-order-reference',
customerId: '',
accountId: 'your-account-id',
},
tokenizeCard: true,
onCreateOrder: (orderReference) => {
console.log('Function called after the order is created');
console.log({ orderReference });
setIsLoading(false);
},
onFailure: (err) => {
console.log('Function called if error occurs while creating order.');
console.log(err);
setIsLoading(false);
},
onClose: () => {
console.log('Function called when modal is closed.');
setIsLoading(false);
return {};
},
onPaymentSuccess: (successResponse) => {
console.log('Function called on payment success.');
console.log({ successResponse });
return {};
},
});
};
return (
<>
<h1>Pay with Nomba</h1>
<button onClick={handleCheckout} disabled={!isInitialized}>
{isLoading ? 'Please wait...' : 'Pay with Nomba Checkout'}
</button>
</>
);
}Step 2: Use Dynamic Import in Your Page
Create or update your app/page.tsx:
'use client';
import dynamic from 'next/dynamic';
// Dynamically import the component with SSR disabled
const NombaCheckoutButton = dynamic(
() => import('@/components/NombaCheckoutButton'),
{ ssr: false }
);
export default function Home() {
return <NombaCheckoutButton />;
}Step 3: Configure Layout (Optional)
Update your app/layout.tsx if needed:
import type { Metadata } from 'next';
import { Geist, Geist_Mono } from 'next/font/google';
import './globals.css';
const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
});
const geistMono = Geist_Mono({
variable: '--font-geist-mono',
subsets: ['latin'],
});
export const metadata: Metadata = {
title: 'Nomba Checkout Integration',
description: 'Payment processing with Nomba',
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang='en'>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
suppressHydrationWarning
>
{children}
</body>
</html>
);
}⚠️ Important Next.js Notes
- Always use dynamic import with
ssr: false- The SDK requires browser APIs and must be rendered client-side only - Initialize SDK in useEffect - Ensures proper initialization after component mounts
- Use 'use client' directive - Required for components using browser-specific features
- Check initialization state - Prevent checkout calls before SDK is ready
🔍 API Reference
InitializeNombaCheckout()
Initializes the SDK. Call once when your app loads (or in useEffect for Next.js).
InitializeNombaCheckout();useNombaCheckout(options)
Launches the Nomba checkout modal.
Options
| Parameter | Type | Required | Description |
| ------------------ | -------------- | -------- | -------------------------------------------------- |
| accountId | string | Yes | Your Nomba account ID |
| clientId | string | Yes | Your Nomba client ID (public key) |
| environment | string | No | 'sandbox' for testing, 'live' for production (default: 'live') |
| order | object | Yes | Order details (see below) |
| tokenizeCard | boolean/string | No | Enable card tokenization |
| onCreateOrder | function | No | Callback after order creation |
| onFailure | function | No | Callback on error |
| onClose | function | No | Callback when modal closes |
| onPaymentSuccess | function | No | Callback on successful payment |
Order Object
| Field | Type | Required | Description |
| ---------------- | ------ | -------- | --------------------------- |
| callbackUrl | string | Yes | URL for payment callback |
| customerEmail | string | Yes | Customer's email address |
| amount | string | Yes | Payment amount |
| currency | string | Yes | Currency code (e.g., 'NGN') |
| orderReference | string | No | Your unique order reference |
| customerId | string | No | Same value as your top-level clientId |
| accountId | string | No | Same value as your top-level accountId |
| orderMetaData | object | No | Additional metadata |
| splitRequest | object | No | Payment split configuration |
| allowedPaymentMethods | string[] | No | Restrict available payment methods (e.g., ['Transfer', 'Card']) |
Split Request Object
| Field | Type | Required | Description |
| ----------- | ------ | -------- | ----------------------------- |
| splitType | string | Yes | 'PERCENTAGE' or 'FLAT' |
| splitList | array | Yes | Array of split configurations |
Split List Item
| Field | Type | Required | Description |
| ----------- | ------------- | -------- | --------------------------- |
| accountId | string | Yes | Account ID to receive split |
| value | number/string | Yes | Split amount or percentage |
Allowed Payment Methods
By default, all payment methods are available to the customer. You can restrict which payment methods are shown in the checkout modal by passing the allowedPaymentMethods array inside the order object.
Available values:
| Value | Description |
| ------------ | -------------------------- |
| 'Transfer' | Bank transfer |
| 'Card' | Debit/credit card |
| 'USSD' | USSD payment |
| 'QR' | QR code payment |
Example — Allow only bank transfer:
order: {
callbackUrl: 'https://yoursite.com/callback',
customerEmail: '[email protected]',
amount: '5000.00',
currency: 'NGN',
allowedPaymentMethods: ['Transfer'],
}Example — Allow transfer and card only:
order: {
callbackUrl: 'https://yoursite.com/callback',
customerEmail: '[email protected]',
amount: '5000.00',
currency: 'NGN',
allowedPaymentMethods: ['Transfer', 'Card'],
}Note: If
allowedPaymentMethodsis omitted or an empty array is passed, all payment methods will be available.
📝 Example with All Options
const res = await useNombaCheckout({
accountId: 'acc_123456',
clientId: 'client_123456',
order: {
callbackUrl: 'https://yoursite.com/payment/callback',
customerEmail: '[email protected]',
amount: '5000.00',
currency: 'NGN',
orderReference: 'ORDER-2024-001',
customerId: 'CUST-001',
accountId: 'acc_123456',
orderMetaData: {
customMerchant: 'true',
productName: 'Premium Plan',
},
splitRequest: {
splitType: 'PERCENTAGE',
splitList: [
{
accountId: 'acc_partner_1',
value: 20,
},
{
accountId: 'acc_partner_2',
value: 15,
},
],
},
allowedPaymentMethods: ['Transfer', 'Card'],
},
tokenizeCard: true,
onCreateOrder: (orderReference) => {
console.log('Order created:', orderReference);
},
onFailure: (error) => {
console.error('Payment failed:', error);
},
onClose: () => {
console.log('Checkout modal closed');
return {};
},
onPaymentSuccess: (response) => {
console.log('Payment successful:', response);
return {};
},
});🧪 Testing in Sandbox
Before going live, always test your integration using sandbox credentials. The sandbox environment simulates real payments without processing actual money.
How to Enable Sandbox Mode
Pass environment: 'sandbox' to useNombaCheckout. Use your Test tab credentials from the dashboard.
await useNombaCheckout({
accountId: 'your-test-account-id', // from Developer > API Keys > Test tab
clientId: 'your-test-client-id', // from Developer > API Keys > Test tab (Client ID)
environment: 'sandbox', // 'sandbox' | 'live'
order: {
customerId: 'your-test-client-id', // same as clientId
accountId: 'your-test-account-id', // same as accountId above
callbackUrl: 'https://yoursite.com/callback',
customerEmail: '[email protected]',
amount: '100.00',
currency: 'NGN',
},
onCreateOrder: (orderReference) => {
console.log('Order created:', orderReference);
},
onPaymentSuccess: (response) => {
console.log('Payment successful:', response);
return {};
},
onFailure: (err) => {
console.error('Payment failed:', err);
},
onClose: () => {
console.log('Modal closed');
return {};
},
});What Works in Sandbox
Card and Transfer can be tested end-to-end in sandbox today. Other payment methods (QR, USSD, Apple Pay, Google Pay, Installments, International Transfer) are coming soon to sandbox.
| Payment Method | Sandbox Status | Notes | | -------------- | -------------- | ----- | | Card (Nigerian) | ✅ Available | Use the test card numbers below | | Transfer | ✅ Available | Test virtual account auto-confirms — no real transfer needed | | QR, USSD, Apple Pay, Google Pay, Installments, International Transfer | 🔜 Coming soon | Available in production today; sandbox support on the way |
Tip: Restrict the checkout to the testable methods with
allowedPaymentMethods: ['Card', 'Transfer']while developing in sandbox.
Test Card Numbers
| Card number prefix | PIN required | Outcome |
| ------------------ | ------------ | ------- |
| 0000... / 1234... | No | Proceeds without PIN |
| 5555... / 4444... | Yes | PIN step shown |
Testing a Transfer
- Select Transfer in the checkout sidebar.
- The sandbox generates a test virtual account (account number, bank, and amount).
- No real money or bank transfer is needed — the inbound transfer auto-confirms after a few seconds and the checkout moves to the success state.
Going Live
When you're ready for production:
- Switch to the Live tab in Developer > API Keys on the dashboard
- Copy your live Client ID and Account ID
- Change
environment: 'sandbox'toenvironment: 'live' - Replace your test credentials with live credentials
await useNombaCheckout({
accountId: 'your-live-account-id',
clientId: 'your-live-client-id',
environment: 'live', // changed from 'sandbox'
order: { ... },
});Important: Never use sandbox credentials in production or live credentials during testing. The SDK will log a console warning if it detects
environment: 'sandbox'in a production build.
🔔 Webhooks — Confirming Payment on Your Server
Do not use
onPaymentSuccessfor order fulfillment. The frontend callback can be spoofed or missed (e.g. if the user closes the browser). Always confirm payment server-side via a webhook before marking an order as paid.
Step 1 — Set up your webhook endpoint (dashboard)
- Go to Settings → Developer → Webhook Setup
- Toggle Live / Test mode (top-right) to match your environment
- Click + Create Webhook
- Enter your Webhook URL (e.g.
https://yourapp.com/webhooks/nomba) - Optionally add a Signature Key — Nomba will sign each request with this; store it as a secret environment variable
- Select the events you want:
- Payment success / Payment failed / Payment reversal
- Payout success / Payout failed / Payout refund
- Order success
- Save
Step 2 — Receive and verify the webhook
// Express (Node.js)
import crypto from 'crypto';
import express from 'express';
const app = express();
function verifyNombaSignature(rawBody: string, header: string, secret: string): boolean {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}
app.post('/webhooks/nomba', express.raw({ type: 'application/json' }), async (req, res) => {
const sig = req.headers['x-nomba-signature'] as string;
if (!verifyNombaSignature(req.body.toString(), sig, process.env.NOMBA_WEBHOOK_SECRET!)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body.toString());
if (event.type === 'payment.success') {
await fulfillOrder(event.data.orderReference); // your fulfillment logic
}
res.json({ received: true });
});🛠️ Troubleshooting
Next.js Hydration Errors
- Ensure you're using
dynamicimport withssr: false - Add
suppressHydrationWarningto your body tag in layout.tsx
SDK Not Initialized
- In Next.js, initialize the SDK in
useEffect - Check that the button is disabled until
isInitializedis true
Modal Not Opening
- Verify that
InitializeNombaCheckout()was called beforeuseNombaCheckout() - Check browser console for errors
👤 Current Maintainer
Kelechi Uma
Frontend Engineer
GitHub
👥 Contributors
📄 License
MIT
🤝 Contributing
Contributions, issues, and feature requests are welcome!
