Skip to content

Tap-Payments/ApplePay-RN

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

ApplePay-RN

A comprehensive React Native bridge to Apple Pay integration that brings native iOS Apple Pay functionality to React Native apps. Simplifies secure payment processing with Apple Pay, including native callback handling and seamless TypeScript support.

Overview

ApplePay-RN provides a complete React Native wrapper around the native Apple Pay iOS framework. It enables React Native developers to integrate Apple Pay payments into their applications with minimal effort while maintaining full access to native payment capabilities.

Key Features:

  • ✅ Native Apple Pay integration for React Native
  • ✅ TypeScript support with full type definitions
  • ✅ Comprehensive callback system for payment events
  • ✅ Flexible configuration options matching native API
  • ✅ Support for multiple payment scenarios (one-time, recurring, deferred)
  • ✅ Automatic native module linking (autolinking)
  • ✅ Example app demonstrating best practices

Requirements

  • React Native: 0.78+
  • iOS: 16.0+ (minimum deployment target)
  • Xcode: 14.0+
  • CocoaPods: For iOS dependency management
  • Node.js: 14.0+
  • Yarn/npm: For JavaScript package management

Installation

1. Install the Package

Using npm:

npm install applepay-rn

Using yarn:

yarn add applepay-rn

2. Install Pod Dependencies

Navigate to the iOS directory and install CocoaPods dependencies:

cd ios
pod install
cd ..

Quick Start

1. Import the Component

import { TapApplePay, type ApplePayConfiguration } from 'applepay-rn';

2. Create Configuration

Define your payment configuration:

const configuration: ApplePayConfiguration = {
  // REQUIRED
  publicKey: "pk_test_******",
  scope: "AppleToken",
  merchant: {
    id: "**********"
  },
  
  // OPTIONAL
  interface: {
    locale: "en",
    theme: "light",
    edges: "curved",
    type: "buy"
  },
  
  // REQUIRED
  customer: {
    name: [
      {
        lang: "en",
        first: "John",
        last: "Smith",
        middle: "David"
      }
    ],
    contact: {
      email: "john.smith@example.com",
      phone: {
        countryCode: "+1",
        number: "5551234567"
      }
    }
  },
  
  // REQUIRED
  acceptance: {
    supportedBrands: ["visa", "masterCard"],
    supportedCards: ["credit", "debit"]
  },
  
  // REQUIRED
  transaction: {
    amount: "20.00",
    currency: "KWD"
  }
};

3. Use the Component

import React, { useCallback } from 'react';
import { View, StyleSheet } from 'react-native';
import { TapApplePay, type ApplePayConfiguration } from 'applepay-rn';

const App = () => {
  const handleReady = useCallback(() => {
    console.log('Apple Pay ready');
  }, []);

  const handleSuccess = useCallback((data: string) => {
    console.log('Payment successful:', data);
  }, []);

  const handleError = useCallback((error: string) => {
    console.log('Payment error:', error);
  }, []);

  const handleCancel = useCallback(() => {
    console.log('Payment canceled');
  }, []);

  return (
    <View style={styles.container}>
      <TapApplePay
        configuration={configuration}
        onReady={handleReady}
        onClick={() => console.log('Button clicked')}
        onSuccess={handleSuccess}
        onError={handleError}
        onCancel={handleCancel}
        onChargeCreated={(data) => console.log('Charge created:', data)}
        onOrderCreated={(data) => console.log('Order created:', data)}
        onMerchantValidation={(data) => console.log('Merchant validation:', data)}
        style={styles.applePayButton}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingHorizontal: 16,
  },
  applePayButton: {
    height: 100,
  },
});

export default App;

Configuration Parameters

Core Configuration

Parameter Description Required Type Example
publicKey Your Tap public API key for authentication String "pk_test_********"
scope Token scope type ('AppleToken' or 'TapToken') String "AppleToken"
merchant Merchant account information with ID Object { id: "********" }

Transaction Configuration (REQUIRED)

const transaction = {
  // REQUIRED: Transaction amount as string
  amount: "20.00",
  
  // REQUIRED: ISO 4217 currency code (e.g., KWD, USD, AED)
  currency: "KWD",
  
  // OPTIONAL: Coupon code for discount
  couponCode: "SAVE10",
  
  // OPTIONAL: Shipping options for the transaction
  shipping: [
    {
      // REQUIRED: Shipping method label
      label: "Standard Shipping",
      // REQUIRED: Shipping description
      detail: "5–7 business days",
      // REQUIRED: Shipping cost
      amount: "1.00",
      // REQUIRED: Unique identifier
      identifier: "std"
    }
  ],
  
  // OPTIONAL: Line items breakdown
  items: [
    {
      // REQUIRED: Item type ('final' or 'pending')
      type: "final",
      // REQUIRED: Item label/description
      label: "Product Order",
      // REQUIRED: Item amount
      amount: "20.00",
      // REQUIRED: Payment timing ('immediate', 'recurring', 'deferred', 'automaticReload')
      paymentTiming: "immediate"
    }
  ]
};

Customer Configuration (REQUIRED)

const customer = {
  // OPTION 1: Use customer ID (if customer already exists in system)
  // id: "cust_123",
  
  // OPTION 2: Provide customer details
  name: [
    {
      // REQUIRED: Language code ('en', 'ar', 'fr')
      lang: "en",
      // REQUIRED: First name
      first: "John",
      // REQUIRED: Last name
      last: "Smith",
      // OPTIONAL: Middle name
      middle: "David"
    }
  ],
  
  // REQUIRED: At least email OR phone (or both)
  contact: {
    // OPTIONAL: Email address (required if phone not provided)
    email: "john.smith@example.com",
    
    // OPTIONAL: Phone number (required if email not provided)
    phone: {
      // REQUIRED IF PHONE PROVIDED: Country code with + prefix
      countryCode: "+1",
      // REQUIRED IF PHONE PROVIDED: Phone number
      number: "5551234567"
    }
  }
};

Interface Configuration (OPTIONAL)

const interfaceConfig = {
  // OPTIONAL: Display language ('en' or 'ar', defaults to 'en')
  locale: "en",
  
  // OPTIONAL: Theme mode ('light', 'dark', or 'dynamic', defaults to 'light')
  theme: "light",
  
  // OPTIONAL: Button edges style ('curved' or 'flat', defaults to 'curved')
  edges: "curved",
  
  // OPTIONAL: Button type ('book', 'buy', 'check-out', 'pay', 'plain', 'subscribe')
  type: "buy"
};

Acceptance Configuration (REQUIRED)

const acceptance = {
  // REQUIRED: Supported card brands/networks
  // Options: 'amex', 'mada', 'masterCard', 'visa', 'chinaUnionPay', 'discover', 'electron', 'jcb', 'maestro'
  supportedBrands: ["visa", "masterCard"],
  
  // REQUIRED: Supported card types
  // Options: 'credit', 'debit'
  supportedCards: ["credit", "debit"],
  
  // OPTIONAL: Supported regions for payments
  // Options: 'LOCAL' (within country), 'REGIONAL' (regional area), 'GLOBAL' (worldwide)
  supportedRegions: ["LOCAL", "REGIONAL"],
  
  // OPTIONAL: Supported countries (ISO 3166-1 alpha-2 codes)
  supportedCountries: ["AE", "KW", "SA", "QA", "BH", "OM", "EG", "JO", "LB"]
};

Features Configuration (OPTIONAL)

const features = {
  // OPTIONAL: Allow coupon code entry (defaults to false)
  supportsCouponCode: true,
  
  // OPTIONAL: Shipping contact fields to collect from user
  // Options: "name" (customer name), "phone" (phone number), "email" (email address)
  // Can be empty array [] to not collect any fields
  shippingContactFields: ["name", "phone", "email"]
};

Component Props

TapApplePay Props

interface TapApplePayProps {
  // Payment configuration object (required)
  configuration: ApplePayConfiguration;
  
  // View style props (optional)
  style?: StyleProp<ViewStyle>;
  
  // Callback when Apple Pay view is ready
  onReady?: () => void;
  
  // Callback when user clicks the Apple Pay button
  onClick?: () => void;
  
  // Callback when payment succeeds
  onSuccess?: (data: string) => void;
  
  // Callback when charge is created
  onChargeCreated?: (data: string) => void;
  
  // Callback when order is created
  onOrderCreated?: (data: string) => void;
  
  // Callback when user cancels payment
  onCancel?: () => void;
  
  // Callback when payment fails
  onError?: (error: string) => void;
  
  // Callback for merchant validation
  onMerchantValidation?: (data: string) => void;
}

Callback Responses

onSuccess Response Example

{
  "id": "tok_4WUP3423199C4Vp18rY9y554",
  "created": 1697656174554,
  "object": "token",
  "type": "CARD",
  "card": {
    "id": "card_U8Wb34231992m7q185g9i558",
    "brand": "VISA",
    "last_four": "4242",
    "exp_month": 2,
    "exp_year": 44
  }
}

onError Response Example

{
  "error": "Payment processing failed"
}

Advanced Usage

Recurring Payments

For subscription or recurring payment scenarios:

const recurringConfig = {
  transaction: {
    items: [
      {
        type: "final",
        label: "Monthly Subscription",
        amount: "9.99",
        paymentTiming: "recurring",
        scheduledPayment: {
          recurringStartDate: new Date().toISOString(),
          recurringIntervalUnit: "month",
          recurringIntervalCount: 1
        }
      }
    ]
  }
};

Deferred Payments

For payments scheduled for a future date:

const deferredConfig = {
  transaction: {
    items: [
      {
        type: "final",
        label: "Product Order",
        amount: "20.00",
        paymentTiming: "deferred",
        scheduledPayment: {
          deferredPaymentDate: new Date(Date.now() + 86400000).toISOString()
        }
      }
    ]
  }
};

Multiple Shipping Options

const shippingConfig = {
  transaction: {
    shipping: [
      {
        label: "Standard",
        detail: "5–7 days",
        amount: "1.00",
        identifier: "std"
      },
      {
        label: "Express",
        detail: "2–3 days",
        amount: "5.00",
        identifier: "exp"
      }
    ]
  }
};

Error Handling

Always implement error handling in your callbacks:

const handleError = (errorData: string) => {
  try {
    const error = JSON.parse(errorData);
    if (error.error) {
      const { code, message } = error.error;
      console.error(`Error ${code}: ${message}`);
      // Handle error appropriately
    }
  } catch (e) {
    console.error('Failed to parse error:', errorData);
  }
};

Example Application

A complete example application is included in the example folder demonstrating:

  • Basic Apple Pay integration with configuration management
  • Multiple screens: MainScreen (overview), SimpleScreen (minimal example), SettingsScreen (dynamic configuration)
  • Real-time event logging and console output
  • Multiple payment scenarios (one-time, recurring, shipping options)
  • Error handling and success callbacks
  • Standalone example component (StandaloneSimpleExample) for quick copy-paste integration

Running the Example App

Navigate to the example directory and run:

yarn 
yarn example ios

Example Screens

  1. MainScreen - Main navigation and quick test
  2. SimpleScreen - Minimal implementation example
  3. SettingsScreen - Dynamic configuration editor
  4. StandaloneSimpleExample - Fully self-contained component (copy-paste ready)

Native Dependency

This library wraps the native ApplePay-iOS module. The native bridge handles:

  • Native Apple Pay sheet presentation
  • Payment processing
  • Merchant validation
  • Native callback bridging to React Native

For detailed native implementation, see: ApplePay-iOS

Security Considerations

Best Practices:

  • Never expose your secret keys in your app (only use public keys)
  • Always validate payment responses on your backend
  • Use HTTPS for all communication
  • Never log sensitive payment data
  • Keep dependencies updated for security patches
  • Use TypeScript for type-safe payment configurations

Troubleshooting

Apple Pay not appearing

  • Ensure you're testing on a physical iOS device with Apple Pay configured
  • Verify your merchant identifier is correct
  • Check that your app signing certificate is properly configured
  • Ensure Apple Pay is enabled in Xcode capabilities

Payment failures

  • Verify your Tap API keys are correct
  • Check that your public key corresponds to your merchant account
  • Ensure the device has Apple Pay set up
  • Verify the transaction amount is valid

Configuration errors

  • Validate all required fields are present in the configuration object
  • Check for typos in parameter keys (they are case-sensitive)
  • Ensure currency codes are valid ISO 4217 codes
  • Use TypeScript to catch configuration errors at compile time

Build issues

  • Run pod install in the ios directory after adding the package
  • Clear build cache: cd ios && rm -rf Pods && pod install
  • For autolinking issues, verify your React Native version is 0.60+

Support & Documentation

License

MIT License - See LICENSE file for details

Contributing

We welcome contributions! Please feel free to submit pull requests with bug fixes, feature additions, or documentation improvements.

Version History

0.0.3

  • Initial release
  • React Native bridge to Apple Pay iOS
  • TypeScript support
  • Comprehensive callback system
  • Example app

Built with ❤️ by Tap Payments

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors