@netappsng/react-native-pay
v0.3.0
Published
netapps payment sdk
Downloads
460
Readme
@netappsng/react-native-pay
NetAppsPay React Native SDK — accept card, bank transfer, USSD, PayAttitude and Tap to Pay (NFC) payments in your React Native app. Supports iOS and Android.
Installation
npm install @netappsng/react-native-pay
# or
yarn add @netappsng/react-native-payiOS
cd ios && pod installThe SDK uses the native NetAppsPaySDK which is resolved automatically via CocoaPods.
Android
The Android SDK is pulled from Maven Central automatically — no extra setup needed.
Make sure your project's android/build.gradle includes mavenCentral() in repositories (this is the default for new React Native projects).
Usage
import { presentPayment } from '@netappsng/react-native-pay';
import type { PaymentConfig } from '@netappsng/react-native-pay';
function handlePayment() {
const amountNaira = 100;
const amountKobo = Math.round(amountNaira * 100);
const config: PaymentConfig = {
publicKey: 'pk_live_xxxxxxxxxxxxxxxxxxxx',
amount: amountKobo, // ₦100.00 = 10000 kobo
currency: 'NGN',
email: '[email protected]',
fullName: 'John Doe',
phoneNumber: '08106720418',
narration: 'Dev Test Payment',
paymentChannels: ['card', 'transfer', 'ussd', 'payattitude', 'moniflow'],
defaultChannel: 'card',
address1: 'Customer Address',
metadata: { inputAmount: amountNaira, env: 'development' },
businessName: 'Demo Store',
showTransactionSummary: true,
};
const cleanup = presentPayment(config, {
onSuccess: (payload) => {
console.log('Payment successful!', payload.transactionRef);
// payload: { status, merchantRef, transactionRef, amount, currency, channel, message, timestamp }
},
onFailed: (payload) => {
console.log('Payment failed:', payload.message);
// payload: { status, amount, currency, message, timestamp, errorCode? }
},
onCancel: () => {
console.log('Payment cancelled');
},
onReady: () => {
console.log('Payment UI ready');
},
});
// Call cleanup() to remove event listeners when unmounting
// e.g. in useEffect: return cleanup;
}With React Hook
import React, { useCallback, useRef } from 'react';
import { Button } from 'react-native';
import { presentPayment } from '@netappsng/react-native-pay';
import type { PaymentConfig } from '@netappsng/react-native-pay';
export default function CheckoutScreen() {
const cleanupRef = useRef<(() => void) | null>(null);
const pay = useCallback(() => {
cleanupRef.current?.();
const config: PaymentConfig = {
publicKey: 'pk_live_xxxxxxxxxxxxxxxxxxxx',
amount: 10000, // ₦100.00
currency: 'NGN',
email: '[email protected]',
fullName: 'John Doe',
phoneNumber: '08106720418',
narration: 'Dev Test Payment',
paymentChannels: ['card', 'transfer', 'ussd', 'payattitude', 'moniflow'],
defaultChannel: 'card',
address1: 'Customer Address',
metadata: { env: 'development' },
businessName: 'Demo Store',
showTransactionSummary: true,
};
cleanupRef.current = presentPayment(config, {
onSuccess: (payload) => {
console.log('Ref:', payload.transactionRef);
cleanupRef.current?.();
},
onFailed: (payload) => {
alert(payload.message);
cleanupRef.current?.();
},
onCancel: () => {
console.log('Cancelled');
cleanupRef.current?.();
},
});
}, []);
return <Button title="Pay ₦100" onPress={pay} />;
}Configuration
Required Fields
| Field | Type | Description |
|-------|------|-------------|
| publicKey | string | Your NetAppsPay public key |
| amount | number | Amount in minor units (kobo/cents). ₦15.00 = 1500 |
| currency | 'NGN' \| 'USD' | Payment currency |
| email | string | Customer email |
| fullName | string | Customer full name |
| narration | string | Payment description |
| paymentChannels | PaymentChannel[] | Channels to display |
| defaultChannel | PaymentChannel | Initially selected channel |
Optional Fields
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| phoneNumber | string | — | Customer phone number |
| transactionRef | string | auto-generated | Custom transaction reference |
| address1 | string | 'Customer Address' | Customer address line 1 |
| address2 | string | — | Customer address line 2 |
| city | string | 'Lagos' | Customer city |
| postalCode | string | — | Customer postal code |
| locality | string | — | Country code (e.g. 'NG') |
| administrativeArea | string | — | State/province (e.g. 'Lagos') |
| chargeAllocation | 'CUSTOMER' \| 'MERCHANT' | 'CUSTOMER' | Who bears the transaction charge |
| businessName | string | — | Merchant display name |
| logoURL | string | — | Merchant logo URL |
| productName | string | — | Product name |
| metadata | Record<string, any> | — | Custom key-value metadata |
| cardHolderName | string | — | Pre-filled cardholder name |
| customerId | string | — | Your internal customer ID |
| enableSaveCard | boolean | false | Allow saving cards for future payments |
| showTransactionSummary | boolean | true | Show transaction summary |
Payment Channels
| Channel | Description |
|---------|-------------|
| 'card' | Card payment (Visa, Mastercard, Verve) |
| 'transfer' | Bank transfer |
| 'ussd' | USSD payment |
| 'payattitude' | PayAttitude (USSD push) |
| 'moniflow' | MoniFlow marketplace |
| 'tap_to_pay' | NFC Tap to Pay (Android only — requires setup, see below) |
Note:
tap_to_payis only available on Android. On iOS, this channel is silently ignored.
Callbacks
| Callback | Payload | Description |
|----------|---------|-------------|
| onSuccess | PaymentSuccessPayload | Payment completed successfully |
| onFailed | PaymentFailedPayload | Payment failed |
| onCancel | — | User dismissed the payment sheet |
| onReady | — | Payment sheet is fully loaded |
Tap to Pay (NFC) — Android Only
Tap to Pay lets customers pay by tapping their contactless card on the Android device. It requires an additional native taptopay module that is not included by default. Your app will compile and work normally without it — devices without NFC are unaffected.
Not supported on iOS. If you include
'tap_to_pay'inpaymentChannelson iOS, it is silently ignored.
Step 1 — Set minSdk to 28
The NFC contactless SDK requires Android API 28+. Open your React Native project's Android build file and set minSdkVersion:
// android/app/build.gradle
android {
defaultConfig {
minSdkVersion 28 // Required for NFC contactless SDK
}
}Step 2 — Add the taptopay module dependency
In your React Native project's Android build files, add the taptopay module alongside the payment SDK:
// android/app/build.gradle
dependencies {
// The core payment SDK (already added by the RN package)
implementation "ng.netapps:netappspay:1.1.0"
// Tap to Pay NFC plugin — add this line
implementation "ng.netapps:taptopay:1.0.0"
}Then sync your Gradle project (Android Studio will prompt you, or run cd android && ./gradlew sync).
Step 3 — Fix the manifest merger conflict
The POS SDK includes its own theme which conflicts with your app's theme. Add tools:replace="android:theme" to your <application> tag:
<!-- android/app/src/main/AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:theme="@style/AppTheme"
tools:replace="android:theme">
<!-- your activities -->
</application>
</manifest>If your manifest already has an
<application>tag with a theme, just addxmlns:tools="http://schemas.android.com/tools"to the<manifest>tag andtools:replace="android:theme"to the<application>tag.
Step 4 — Register the NFC provider in your Android app
Open your MainApplication.kt (or MainApplication.java) file — this is usually at:
android/app/src/main/java/com/yourapp/MainApplication.ktAdd the import and registration call inside onCreate:
// MainApplication.kt
import com.netappspay.sdk.taptopay.TapToPayRegistry
import com.netappspay.taptopay.NfcTapToPayProvider
class MainApplication : Application(), ReactApplication {
override fun onCreate() {
super.onCreate()
// Register NFC Tap to Pay provider — do this once on app start
TapToPayRegistry.register(NfcTapToPayProvider())
// ... rest of your onCreate
}
}Java version:
// MainApplication.java
import com.netappspay.sdk.taptopay.TapToPayRegistry;
import com.netappspay.taptopay.NfcTapToPayProvider;
public class MainApplication extends Application implements ReactApplication {
@Override
public void onCreate() {
super.onCreate();
// Register NFC Tap to Pay provider
TapToPayRegistry.INSTANCE.register(new NfcTapToPayProvider());
// ... rest of your onCreate
}
}That's all the native code you need. The taptopay module's AndroidManifest.xml automatically adds the NFC permission with android:required="false", so your app still installs on devices without NFC.
Step 5 — Include 'tap_to_pay' in your payment channels
Now in your React Native / TypeScript code, add 'tap_to_pay' to the paymentChannels array:
import { presentPayment } from '@netappsng/react-native-pay';
import type { PaymentConfig } from '@netappsng/react-native-pay';
const config: PaymentConfig = {
publicKey: 'pk_live_xxxxxxxxxxxxxxxxxxxx',
amount: 10000,
currency: 'NGN',
email: '[email protected]',
fullName: 'John Doe',
phoneNumber: '08106720418',
narration: 'POS Payment',
paymentChannels: ['card', 'transfer', 'tap_to_pay'],
defaultChannel: 'card',
businessName: 'Demo Store',
};
presentPayment(config, {
onSuccess: (payload) => {
console.log('Tap to Pay successful!', payload.transactionRef);
},
onFailed: (payload) => {
console.log('Payment failed:', payload.message);
},
onCancel: () => {
console.log('Cancelled');
},
});How it works
- When the payment sheet opens, the SDK checks if a Tap to Pay provider is registered via
TapToPayRegistry - If registered and the device has NFC hardware enabled, the "Tap to Pay" tab appears
- If no provider is registered or the device lacks NFC, the tab is automatically hidden — no errors, no crashes
- The user selects their Account Type and Device Type using the chip controls on the Tap to Pay screen
- The customer taps their contactless card on the device to complete payment
Account Type
The Tap to Pay screen presents a segmented chip control for account type selection:
| Chip | Value |
|------|-------|
| Default | DEFAULT_UNSPECIFIED — the issuer's default account |
| Savings | SAVINGS |
| Current | CURRENT |
| Credit | CREDIT |
Device Type
A second chip control lets the user choose how the NFC card is read:
| Chip | Description | |------|-------------| | Internal NFC | Uses the device's built-in NFC antenna (most common) | | External | Uses an external NFC reader connected to the device | | NFC Kit | Uses a third-party NFC kit module |
The selected device type is persisted automatically — the SDK remembers the user's last choice across sessions so they don't have to re-select each time.
Requirements
| Requirement | Value |
|---|---|
| Min Android SDK | 28 (Android 9.0) |
| NFC hardware | Required on the device (for Internal NFC) |
| taptopay module | Must be added as a dependency |
| Manifest fix | tools:replace="android:theme" on <application> |
| Provider registration | Must call TapToPayRegistry.register() before payment |
Unregister (optional)
If you need to disable Tap to Pay at runtime:
TapToPayRegistry.unregister()Native SDKs
This package bridges the native NetAppsPay SDKs:
- iOS: NetAppsPaySDK (Swift Package)
- Android:
ng.netapps:netappspay:1.1.0(Maven Central)
License
MIT
