react-native-nomba-checkout-sdk
v1.0.1
Published
Nomba Checkout SDK for React Native
Maintainers
Readme
🚀 React Native Nomba Checkout SDK
The react-native-nomba-checkout-sdk is a lightweight React Native SDK that brings Nomba's secure checkout into your iOS and Android apps. Drop in a hook and a component, and your users get the full hosted Nomba checkout — Card, Transfer, and more — inside a native sheet.
Built with ❤️ by Kelechi Uma
🗺️ 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 (+ react-native-webview) 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 app code.
📦 Installation
The SDK has a required peer dependency on react-native-webview (the checkout renders inside a WebView):
npm install react-native-nomba-checkout-sdk react-native-webview
# or
yarn add react-native-nomba-checkout-sdk react-native-webviewiOS
Install the native pods after adding the dependencies, then rebuild the app:
cd ios && pod install && cd ..
npx react-native run-iosAndroid
react-native-webview is autolinked (React Native 0.60+), so no manual native setup is required — just rebuild the app so the native module is included:
npx react-native run-androidInternet access is enabled by default on Android. If you've customized your
AndroidManifest.xml, make sure it still declares<uses-permission android:name="android.permission.INTERNET" />.
Expo
This SDK works with Expo via a development build (it relies on react-native-webview, a native module, so it won't run in Expo Go):
npx expo install react-native-webview
npx expo prebuild
npx expo run:ios # or: npx expo run:androidOptional — Native Apple Pay & Google Pay
To enable the native Apple Pay (iOS) and Google Pay (Android) sheets, install @stripe/stripe-react-native. The SDK detects it automatically and falls back gracefully if it isn't present:
npm install @stripe/stripe-react-native⚡ Quick Start
The integration is two pieces:
useNombaCheckout(config)— a hook that creates the order and gives youopenCheckout,isLoading, andcheckoutSheetProps.<NombaCheckoutSheet {...checkoutSheetProps} />— render it once; it manages its own visibility.
import {
SafeAreaView,
TouchableOpacity,
Text,
ActivityIndicator,
Alert,
StyleSheet,
} from 'react-native';
import {
useNombaCheckout,
NombaCheckoutSheet,
} from 'react-native-nomba-checkout-sdk';
export default function App() {
const { openCheckout, isLoading, checkoutSheetProps } = useNombaCheckout({
clientId: 'your-client-id',
accountId: 'your-account-id',
environment: 'sandbox', // 'sandbox' | 'live'
order: {
orderReference: `order-${Date.now()}`,
customerId: 'your-client-id', // same value as clientId
accountId: 'your-account-id', // same value as accountId above
customerEmail: '[email protected]',
amount: '5000.00', // amount in Naira (e.g. '5000.00' = ₦5,000)
currency: 'NGN',
callbackUrl: 'https://yourapp.com/payment/callback',
},
onCreateOrder: (data) => {
console.log('[Nomba] Order created:', data);
},
onPaymentSuccess: (details) => {
console.log('[Nomba] Payment successful:', details);
Alert.alert('Payment Successful', 'Your payment was processed successfully.');
},
onFailure: (error) => {
console.error('[Nomba] Payment failed:', error);
Alert.alert('Payment Failed', 'Something went wrong. Please try again.');
},
onClose: () => {
console.log('[Nomba] Checkout closed');
},
});
return (
<SafeAreaView style={styles.container}>
<TouchableOpacity
style={[styles.button, isLoading && styles.buttonDisabled]}
onPress={openCheckout}
disabled={isLoading}
>
{isLoading ? (
<ActivityIndicator color="#0A0A0A" />
) : (
<Text style={styles.buttonText}>Pay with Nomba</Text>
)}
</TouchableOpacity>
{/* Render once — it manages its own visibility */}
<NombaCheckoutSheet {...checkoutSheetProps} />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', padding: 24 },
button: {
backgroundColor: '#FFC629',
paddingVertical: 16,
borderRadius: 12,
alignItems: 'center',
},
buttonDisabled: { opacity: 0.65 },
buttonText: { fontSize: 16, fontWeight: '600', color: '#0A0A0A' },
});That's it — tapping the button creates the order, opens the Nomba checkout sheet, and fires your callbacks as the payment progresses.
🔍 API Reference
useNombaCheckout(config)
Creates the order and manages the checkout sheet's state. Returns:
| Property | Type | Description |
| -------------------- | --------------------- | ----------------------------------------------------------------- |
| openCheckout | () => Promise<void> | Creates the order on Nomba, then opens the checkout sheet |
| isLoading | boolean | true while the order is being created (before the sheet opens) |
| checkoutSheetProps | object | Spread directly onto <NombaCheckoutSheet /> |
Config Options
| Parameter | Type | Required | Description |
| ------------------ | ------------------------- | -------- | ------------------------------------------------------------------- |
| clientId | string | Yes | Your Nomba Client ID (public key) |
| accountId | string | Yes | Your Nomba Account ID |
| order | object | Yes | Order details (see below) |
| environment | 'sandbox' \| 'live' | No | 'sandbox' for testing, 'live' for production (default: 'live') |
| tokenizeCard | boolean | No | Enable card tokenization |
| onPaymentSuccess | (details) => void | Yes | Called when the payment succeeds |
| onCreateOrder | (data) => void | No | Called after the order is created |
| onFailure | (error) => void | No | Called if order creation fails |
| onClose | () => void | No | Called when the checkout sheet is closed |
Order Object
| Field | Type | Required | Description |
| ----------------------- | -------- | -------- | ----------------------------------------------------------------- |
| orderReference | string | Yes | Your unique order reference |
| customerId | string | Yes | Same value as your top-level clientId |
| accountId | string | Yes | Same value as your top-level accountId |
| customerEmail | string | Yes | Customer's email address |
| amount | string | Yes | Payment amount in Naira (e.g. '5000.00' = ₦5,000) |
| currency | string | Yes | Currency code (e.g. 'NGN') |
| callbackUrl | string | No | URL for payment callback |
| allowedPaymentMethods | string[] | No | Restrict available payment methods (e.g. ['Transfer', 'Card']) |
| orderMetaData | object | No | Additional metadata |
| splitRequest | object | No | Payment split configuration |
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 | Yes | Split amount or percentage |
<NombaCheckoutSheet />
The native checkout sheet — a full-screen modal hosting the Nomba checkout page. You don't construct its props by hand; just spread the checkoutSheetProps returned by useNombaCheckout:
<NombaCheckoutSheet {...checkoutSheetProps} />Render it once in your component tree. It is hidden until openCheckout() is called and closes itself when the payment completes or the user dismisses it.
Allowed Payment Methods
By default, all payment methods are available to the customer. You can restrict which methods appear by passing allowedPaymentMethods 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: {
orderReference: `order-${Date.now()}`,
customerId: 'your-client-id',
accountId: 'your-account-id',
customerEmail: '[email protected]',
amount: '5000.00',
currency: 'NGN',
allowedPaymentMethods: ['Transfer'],
}Note: If
allowedPaymentMethodsis omitted or an empty array is passed, all payment methods will be available.
📝 Example with All Options
const { openCheckout, isLoading, checkoutSheetProps } = useNombaCheckout({
clientId: 'client_123456',
accountId: 'acc_123456',
environment: 'sandbox',
tokenizeCard: true,
order: {
orderReference: 'ORDER-2024-001',
customerId: 'client_123456', // same as clientId
accountId: 'acc_123456', // same as accountId above
customerEmail: '[email protected]',
amount: '5000.00',
currency: 'NGN',
callbackUrl: 'https://yoursite.com/payment/callback',
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'],
},
onCreateOrder: (data) => console.log('Order created:', data),
onPaymentSuccess: (response) => console.log('Payment successful:', response),
onFailure: (error) => console.error('Payment failed:', error),
onClose: () => console.log('Checkout closed'),
});🧪 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.
useNombaCheckout({
clientId: 'your-test-client-id', // from Developer > API Keys > Test tab
accountId: 'your-test-account-id', // from Developer > API Keys > Test tab
environment: 'sandbox',
order: {
orderReference: `order-${Date.now()}`,
customerId: 'your-test-client-id', // same as clientId
accountId: 'your-test-account-id', // same as accountId above
customerEmail: '[email protected]',
amount: '100.00',
currency: 'NGN',
},
onPaymentSuccess: (response) => console.log('Payment successful:', response),
});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.
- 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
useNombaCheckout({
clientId: 'your-live-client-id',
accountId: 'your-live-account-id',
environment: 'live', // changed from 'sandbox'
order: { /* ... */ },
onPaymentSuccess: (response) => console.log('Payment successful:', response),
});Important: Never use sandbox credentials in production or live credentials during testing. The SDK logs 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 client callback can be missed (e.g. if the user backgrounds or kills the app). 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
Unable to resolve module react-native-webview
react-native-webview is a required peer dependency. Install it and reinstall pods:
npm install react-native-webview
cd ios && pod install && cd ..Checkout doesn't appear in Expo Go
This SDK uses native modules and requires an Expo development build — it does not run in Expo Go. Run npx expo prebuild then npx expo run:ios / npx expo run:android.
Apple Pay / Google Pay not showing
The native Pay sheets require the optional @stripe/stripe-react-native peer dependency. Install it (npm install @stripe/stripe-react-native) and rebuild the app.
Nothing happens when I tap the button
- Confirm
openCheckoutis wired to your button'sonPress - Check that
<NombaCheckoutSheet {...checkoutSheetProps} />is rendered in the tree - Watch your
onFailurecallback / console for order-creation errors (bad credentials, wrongenvironment)
👤 Author & Maintainer
Kelechi Uma Frontend Engineer GitHub
📄 License
MIT
🤝 Contributing
Contributions, issues, and feature requests are welcome!
