npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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-pay

iOS

cd ios && pod install

The 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_pay is 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' in paymentChannels on 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 add xmlns:tools="http://schemas.android.com/tools" to the <manifest> tag and tools: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.kt

Add 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

  1. When the payment sheet opens, the SDK checks if a Tap to Pay provider is registered via TapToPayRegistry
  2. If registered and the device has NFC hardware enabled, the "Tap to Pay" tab appears
  3. If no provider is registered or the device lacks NFC, the tab is automatically hidden — no errors, no crashes
  4. The user selects their Account Type and Device Type using the chip controls on the Tap to Pay screen
  5. 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