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

@dingpay/react-native

v1.0.3

Published

DingPay in-app payments for React Native

Readme

@dingpay/react-native

Accept payments in your React Native app with DingPay. Users set up once in the Ding Wallet app, then pay anywhere with one tap. Secured with biometric authentication (Face ID / Touch ID / Fingerprint).

How it works

  1. User enables "In-App Checkout" in their Ding Wallet app
  2. Your app calls pay() with an amount
  3. DingPay shows a bottom sheet with the user's saved payment methods (cards, bank accounts, wallet)
  4. User taps Pay, confirms with Face ID or fingerprint
  5. Your app receives a success or failure callback

No sign-up flow. No card entry. No OTP. The user's payment methods are already in their Ding Wallet.

Installation

npm install @dingpay/react-native

Peer dependencies

npm install react-native-webview @react-native-async-storage/async-storage react-native-inappbrowser-reborn react-native-biometrics

Platform setup

DingPay uses a callback scheme to complete authentication. Choose a unique scheme for your app (e.g. your bundle ID) and configure it on both platforms. The same scheme must be passed to useDingPay().

iOS

Run pod install:

cd ios && pod install

Add your callback scheme and Face ID usage description to ios/<YourApp>/Info.plist. Place both entries inside the top-level <dict> tag:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>com.yourapp.dingpay</string>
        </array>
    </dict>
</array>

<key>NSFaceIDUsageDescription</key>
<string>Confirm your payment</string>

Android

Add an intent filter with your callback scheme to android/app/src/main/AndroidManifest.xml. Place it inside your main <activity> tag (the one with android.intent.action.MAIN):

<activity
  android:name=".MainActivity"
  ...>

    <!-- Existing launcher intent filter -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <!-- DingPay callback -->
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="com.yourapp.dingpay" />
    </intent-filter>

</activity>

Replace com.yourapp.dingpay with your own unique scheme on both platforms.

Quick start

import React from 'react';
import { View, Button, Alert } from 'react-native';
import { useDingPay } from '@dingpay/react-native';

export default function CheckoutScreen() {
  const { pay, dingPaySheet } = useDingPay({
    callbackScheme: 'com.yourapp.dingpay',
    apiKey: 'your_merchant_api_key',
  });

  const handlePay = () => {
    pay({
      amount: 5000,
      onSuccess: () => {
        Alert.alert('Payment successful');
      },
      onFailure: (message) => {
        Alert.alert('Payment failed', message);
      },
    });
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
      <Button title="Pay ₦5,000" onPress={handlePay} />
      {dingPaySheet}
    </View>
  );
}

Important: {dingPaySheet} must be included in your TSX. It is invisible until pay() is called. Place it at the root level of your component, not inside buttons or other interactive elements.

API

useDingPay(config)

React hook that returns { pay, dingPaySheet }.

config

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | callbackScheme | string | Yes | A unique URL scheme for your app (must match the scheme registered in Info.plist and AndroidManifest.xml) | | apiKey | string | Yes | Your merchant API key from the DingPay dashboard |

pay(options)

Opens the DingPay payment sheet.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | amount | number | Yes | Amount in Naira (e.g. 5000 for ₦5,000) | | metadata | Record<string, any> | No | Additional data to attach to the transaction | | onSuccess | () => void | No | Called when payment succeeds | | onFailure | (message: string) => void | No | Called when payment fails, with an error message | | onCancel | () => void | No | Called when the user dismisses the payment sheet |

dingPaySheet

TSX element that renders the payment bottom sheet. Include it at the root level of your component's return statement. It manages its own visibility internally.

return (
  <View>
    {/* your UI */}
    {dingPaySheet}
  </View>
);

clearDingPaySession()

Clears the locally cached session. Call this when the user logs out of your app.

import { clearDingPaySession } from '@dingpay/react-native';

const handleLogout = async () => {
  await clearDingPaySession();
};

Full example

import React, { useState } from 'react';
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  Alert,
  StyleSheet,
  KeyboardAvoidingView,
  Platform,
} from 'react-native';
import { useDingPay } from '@dingpay/react-native';

const MERCHANT_API_KEY = 'pk_live_xxxxxxxxxxxx';
const CALLBACK_SCHEME = 'com.myapp.dingpay';

export default function PaymentScreen() {
  const [amount, setAmount] = useState('');
  const { pay, dingPaySheet } = useDingPay({
    callbackScheme: CALLBACK_SCHEME,
    apiKey: MERCHANT_API_KEY,
  });

  const handlePay = () => {
    const num = parseFloat(amount);
    if (!num || num <= 0) {
      Alert.alert('Enter a valid amount');
      return;
    }

    pay({
      amount: num,
      metadata: {
        orderId: 'order_12345',
        customerEmail: '[email protected]',
      },
      onSuccess: () => {
        Alert.alert('Success', 'Your payment was processed.');
        setAmount('');
      },
      onFailure: (message: string) => {
        Alert.alert('Payment Failed', message);
      },
      onCancel: () => {
        console.log('User cancelled');
      },
    });
  };

  return (
    <KeyboardAvoidingView
      style={styles.container}
      behavior={Platform.OS === 'ios' ? 'padding' : undefined}
    >
      <View style={styles.content}>
        <Text style={styles.title}>Checkout</Text>

        <TextInput
          style={styles.input}
          placeholder="Amount (NGN)"
          keyboardType="numeric"
          value={amount}
          onChangeText={setAmount}
        />

        <TouchableOpacity style={styles.button} onPress={handlePay}>
          <Text style={styles.buttonText}>Pay with DingPay</Text>
        </TouchableOpacity>
      </View>

      {dingPaySheet}
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#fff' },
  content: { flex: 1, justifyContent: 'center', padding: 24 },
  title: { fontSize: 24, fontWeight: '700', marginBottom: 24 },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 10,
    padding: 16,
    fontSize: 16,
    marginBottom: 16,
  },
  button: {
    backgroundColor: '#1a1a1a',
    borderRadius: 100,
    padding: 18,
    alignItems: 'center',
  },
  buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' },
});

Security

DingPay is built with multiple layers of security:

  • Biometric authentication: Every payment requires Face ID, Touch ID, or fingerprint confirmation before processing.
  • One-time sessions: Each checkout page creates a unique session that is burned after a single use. Intercepted session IDs cannot be replayed.
  • Server-side rendering: Payment assets and charge logic are handled entirely on the server. No sensitive data (card details, authorization codes) is ever exposed to the client.
  • Encrypted signatures: The user's payment session is encrypted and validated server-side on every request.
  • API key validation: Every SSO and checkout request is validated against your merchant API key.
  • No card entry: Users never enter card details in your app. Payment methods are managed securely in the Ding Wallet app.

Payment methods supported

  • Cards: Visa, Mastercard, Verve cards saved in Ding Wallet
  • Bank accounts: Direct debit mandates from Nigerian banks
  • Wallet: Ding Wallet balance

Requirements

  • React Native 0.60+
  • iOS 12+ / Android 5+
  • User must have the Ding Wallet app with "In-App Checkout" enabled

Troubleshooting

"In-app payments not enabled"

The user has not set up In-App Checkout in their Ding Wallet app. They need to open Ding Wallet and enable it in settings.

"Session expired. Please try again."

The cached session was invalidated. The SDK automatically clears it. The next payment attempt will re-authenticate.

Payment sheet not appearing

Make sure {dingPaySheet} is included at the root level of your component's TSX, not inside buttons or other interactive elements. It must be rendered before pay() is called.

Biometric prompt not showing

On iOS, ensure NSFaceIDUsageDescription is set in Info.plist. On devices without biometrics, payment proceeds without the prompt.

Android: SSO redirect not working

Ensure you added an intent filter with your callbackScheme to AndroidManifest.xml inside the main <activity> tag. The scheme in the manifest must exactly match the callbackScheme passed to useDingPay().

iOS: SSO redirect not working

Ensure you added your callbackScheme to the CFBundleURLSchemes array in Info.plist. The scheme must exactly match the callbackScheme passed to useDingPay().

iOS: App freezes after SSO

This is a known timing issue between the SSO browser closing and the payment sheet opening. The SDK handles this with an internal delay. If you still experience it, ensure you're on the latest version.

Android: "Continue with" prompt appears

This means another app on the device has registered the same URL scheme. Choose a unique scheme for your app, such as your bundle ID followed by .dingpay (e.g. com.chowdeck.dingpay).

License

MIT