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

@piotr-graczyk-dev/react-native-pay

v0.0.4

Published

Pay for iOS and Android with React Native Pay

Downloads

10

Readme

react-native-pay

A unified React Native payment module supporting both Apple Pay (iOS) and Google Pay (Android) with a consistent API across platforms.

Built with Nitro Modules for high-performance native integration.

Features

  • Unified API - Same interface for both Apple Pay and Google Pay
  • One Hook Does Everything - Simple usePaymentCheckout() hook for complete payment flow
  • Native UI Components - Platform-specific payment buttons
  • Type-Safe - Full TypeScript support with comprehensive type definitions
  • Configurable - Dynamic environment and gateway configuration
  • Built-in Cart - Shopping cart functionality included
  • Modern Architecture - Built with Nitro Modules for optimal performance
  • Expo Compatible - Config plugins for easy integration with Expo

Installation

npm install react-native-pay
# or
yarn add react-native-pay
# or
bun add react-native-pay

iOS Setup

Add Apple Pay capability to your app and configure merchant identifiers in your Expo config:

// app.json or app.config.js
{
  "plugins": [
    [
      "react-native-pay",
      {
        "merchantIdentifier": "merchant.com.yourcompany.app"
      }
    ]
  ]
}

Android Setup

Enable Google Pay in your Expo config:

// app.json or app.config.js
{
  "plugins": [
    [
      "react-native-pay",
      {
        "enableGooglePay": true
      }
    ]
  ]
}

Usage

Using the Hook (Recommended)

One hook does everything - availability checking, cart management, and payment processing:

import {
  usePaymentCheckout,
  ApplePayButton,
  GooglePayButton,
} from 'react-native-pay'
import { Platform, View, Text, Button, ActivityIndicator } from 'react-native'

function CheckoutScreen() {
  const {
    // Payment availability
    canMakePayments,

    // Cart management
    items,
    total,
    addItem,
    addItems,
    removeItem,

    // Payment processing
    startPayment,
    isProcessing,
    error,
  } = usePaymentCheckout({
    merchantIdentifier: 'merchant.com.yourcompany.app',
    currencyCode: 'USD',
    countryCode: 'US',
  })

  // Add single item
  const handleAddCoffee = () => addItem('Coffee', 4.99)

  // Add multiple items at once
  const handleAddFullOrder = () => addItems([
    { label: 'Coffee', amount: 4.99 },
    { label: 'Sandwich', amount: 8.99 },
    { label: 'Tax', amount: 1.20 }
  ])

  const handlePay = async () => {
    const result = await startPayment()
    if (result?.success) {
      // Send result.token to your server
      console.log('Payment successful:', result.transactionId)
    }
  }

  if (!canMakePayments) {
    return <Text>Payment not available</Text>
  }

  return (
    <View>
      <Button title="Add Coffee $4.99" onPress={handleAddCoffee} />
      <Button title="Add Full Order" onPress={handleAddFullOrder} />

      {items.map((item, i) => (
        <View key={i}>
          <Text>{item.label}: ${item.amount}</Text>
          <Button title="Remove" onPress={() => removeItem(i)} />
        </View>
      ))}

      <Text>Total: ${total.toFixed(2)}</Text>

      {error && <Text style={{ color: 'red' }}>{error.message}</Text>}

      {isProcessing ? (
        <ActivityIndicator />
      ) : (
        Platform.OS === 'ios' ? (
          <ApplePayButton onPress={handlePay} buttonType="buy" buttonStyle="black" />
        ) : (
          <GooglePayButton onPress={handlePay} buttonType="buy" theme="dark" />
        )
      )}
    </View>
  )
}

Basic Payment Flow (Without Hooks)

import {
  HybridPaymentHandler,
  ApplePayButton,
  GooglePayButton,
  createPaymentRequest,
} from 'react-native-pay'
import { Platform } from 'react-native'

// Check if payment service is available
const status = HybridPaymentHandler.payServiceStatus()
console.log('Can make payments:', status.canMakePayments)

// Create a payment request
const paymentRequest = createPaymentRequest({
  merchantIdentifier: 'merchant.com.yourcompany.app',
  amount: 29.99,
  label: 'Coffee Subscription',
  countryCode: 'US',
  currencyCode: 'USD',
  // Google Pay specific (optional)
  googlePayEnvironment: 'TEST', // or 'PRODUCTION'
  googlePayGateway: 'stripe',
  googlePayGatewayMerchantId: 'your_gateway_merchant_id',
})

// Handle payment
const handlePayment = async () => {
  try {
    const result = await HybridPaymentHandler.startPayment(paymentRequest)

    if (result.success) {
      console.log('Payment successful:', result.transactionId)
      console.log('Payment token:', result.token)
      // Send token to your server for processing
    } else {
      console.error('Payment failed:', result.error)
    }
  } catch (error) {
    console.error('Payment error:', error)
  }
}

// Render platform-specific button
{Platform.OS === 'ios' ? (
  <ApplePayButton
    buttonType="buy"
    buttonStyle="black"
    onPress={handlePayment}
    style={{ width: '100%', height: 48 }}
  />
) : (
  <GooglePayButton
    buttonType="buy"
    theme="dark"
    radius={4}
    onPress={handlePayment}
    style={{ width: '100%', height: 48 }}
  />
)}

Payment Request Configuration

interface PaymentRequest {
  merchantIdentifier: string
  countryCode: string
  currencyCode: string
  paymentItems: PaymentItem[]
  merchantCapabilities: string[]
  supportedNetworks: string[]
  shippingType?: string
  shippingMethods?: PaymentItem[]
  billingContactRequired?: boolean
  shippingContactRequired?: boolean
  // Google Pay specific (Android only)
  googlePayEnvironment?: 'TEST' | 'PRODUCTION'
  googlePayGateway?: string
  googlePayGatewayMerchantId?: string
}

Utility Helpers

The package includes helpful utilities for common operations:

import {
  createPaymentItem,
  calculateTotal,
  formatNetworkName,
} from 'react-native-pay'

// Create payment items
const item1 = createPaymentItem('Subscription', 29.99, 'final')
const item2 = createPaymentItem('Tax', 2.4, 'final')

// Calculate total
const total = calculateTotal([item1, item2]) // 32.39

// Format network names
formatNetworkName('visa') // "Visa"
formatNetworkName('amex') // "American Express"

API Reference

React Hook

usePaymentCheckout(config)

All-in-one hook for payment checkout flow.

Configuration:

{
  merchantIdentifier: string
  countryCode?: string              // Default: 'US'
  currencyCode?: string              // Default: 'USD'
  supportedNetworks?: string[]       // Default: ['visa', 'mastercard', 'amex', 'discover']
  merchantCapabilities?: string[]    // Default: ['3DS']
  googlePayEnvironment?: 'TEST' | 'PRODUCTION'
  googlePayGateway?: string
  googlePayGatewayMerchantId?: string
}

Returns:

{
  // Payment availability
  canMakePayments: boolean
  canSetupCards: boolean
  isCheckingStatus: boolean

  // Cart management
  items: PaymentItem[]
  total: number
  addItem: (label: string, amount: number, type?: 'final' | 'pending') => void
  addItems: (items: Array<{ label, amount, type? }>) => void  // Add multiple at once
  removeItem: (index: number) => void
  updateItem: (index: number, updates: Partial<PaymentItem>) => void
  clearItems: () => void

  // Payment processing
  startPayment: () => Promise<PaymentResult | null>
  isProcessing: boolean
  result: PaymentResult | null
  error: Error | null

  // Utilities
  reset: () => void
  paymentRequest: PaymentRequest  // Full request object
}

Example:

const checkout = usePaymentCheckout({
  merchantIdentifier: 'merchant.com.example',
  currencyCode: 'USD',
  countryCode: 'US',
})

// Add single item
checkout.addItem('Product', 29.99)

// Add multiple items at once
checkout.addItems([
  { label: 'Product', amount: 29.99 },
  { label: 'Shipping', amount: 5.0 },
  { label: 'Tax', amount: 2.8, type: 'final' },
])

// Check total
console.log(checkout.total) // 37.79

// Process payment
const result = await checkout.startPayment()
if (result?.success) {
  // Handle success
}

HybridPaymentHandler

payServiceStatus(): PayServiceStatus

Returns the current payment service availability.

const status = HybridPaymentHandler.payServiceStatus()
console.log(status.canMakePayments) // boolean
console.log(status.canSetupCards) // boolean

startPayment(request: PaymentRequest): Promise<PaymentResult>

Initiates a payment request.

const result = await HybridPaymentHandler.startPayment(paymentRequest)

canMakePayments(usingNetworks: string[]): boolean

Checks if the device can make payments using specific networks.

const canPay = HybridPaymentHandler.canMakePayments(['visa', 'mastercard'])

Button Components

ApplePayButton (iOS)

<ApplePayButton
  buttonType="buy" | "setup" | "book" | "donate" | "order" | "continue" | ...
  buttonStyle="white" | "black" | "whiteOutline" | "automatic"
  onPress={() => handlePayment()}
  style={styles.button}
/>

GooglePayButton (Android)

<GooglePayButton
  buttonType="buy" | "book" | "checkout" | "donate" | "order" | "pay" | "subscribe" | "plain"
  theme="dark" | "light"
  radius={4} // optional corner radius
  onPress={() => handlePayment()}
  style={styles.button}
/>

Architecture

Package Structure

package/
├── android/                          # Android implementation
│   └── src/main/java/com/.../pay/
│       ├── Constants.kt              # Shared constants
│       ├── GooglePayButtonFactory.kt # Button creation utility
│       ├── GooglePayRequestBuilder.kt # Payment request builder
│       ├── HybridGooglePayButton.kt  # Button component
│       ├── HybridPaymentHandler.kt   # Payment handler
│       ├── NitroPayPackage.kt        # RN package
│       └── PaymentMapper.kt          # Data mapper
├── ios/                              # iOS implementation
│   ├── ApplePayButtonFactory.swift   # Button creation utility
│   ├── HybridApplePayButton.swift    # Button component
│   ├── HybridPaymentHandler.swift    # Payment handler
│   └── PassKitTypeMapper.swift       # Type converter
├── src/                              # TypeScript/JavaScript
│   ├── specs/                        # Nitro type specs
│   │   ├── ApplePayButton.nitro.ts
│   │   ├── GooglePayButton.nitro.ts
│   │   └── PaymentHandler.nitro.ts
│   ├── types/                        # Type definitions
│   │   ├── Contact.ts
│   │   └── Payment.ts
│   ├── utils/                        # Utility helpers
│   │   └── paymentHelpers.ts
│   ├── plugin/                       # Expo config plugins
│   │   ├── withApplePay.ts
│   │   └── withGooglePay.ts
│   └── index.ts                      # Public API
└── nitrogen/                         # Generated code (auto-generated)

Design Principles

  1. Separation of Concerns: Each component has a single, well-defined responsibility
  2. Factory Pattern: Button and request creation abstracted into factory classes
  3. Type Safety: Comprehensive TypeScript definitions with runtime validation
  4. Code Reusability: Shared utilities and helpers reduce duplication
  5. Platform Consistency: Unified API abstracts platform differences

Contributing

Contributions are welcome! Please ensure:

  • Code follows existing patterns and style
  • All TypeScript types are properly defined
  • Native code is properly documented
  • Tests pass (when available)

License

MIT

Credits

Built with Nitro Modules by Margelo