@jimrising/easymerchantsdk-react-native
v2.4.8
Published
This guide provides instructions for integrating the EasyMerchant SDK into a React Native application for Android and iOS platforms. It supports two payment flows: `makePayment` (direct payment with API key and secret) and `makePaymentV2` (client token-ba
Readme
EasyMerchant SDK React Native Integration
This guide provides instructions for integrating the EasyMerchant SDK into a React Native application for Android and iOS platforms. It supports two payment flows: makePayment (direct payment with API key and secret) and makePaymentV2 (client token-based payment). The SDK enables card payments, ACH transfers, recurring payments, 3D Secure authentication, and customizable billing/additional fields with a unified configuration object.
Prerequisites
- Node.js and npm: Version 16 or higher.
- React Native Environment: Set up as per the official React Native documentation.
- Ruby: Version 3.2.8 or higher for iOS setup (required for CocoaPods).
- Xcode: Version 14 or higher for iOS development.
- Android Studio: For Android development, with Gradle configured.
- EasyMerchant SDK Credentials: Obtain API keys and secret keys for
sandboxorproductionenvironments (formakePayment), and access to the payment intent API for client token generation (formakePaymentV2).
Installation
1. Add the SDK to Your Project
Add the EasyMerchant SDK to your package.json under dependencies:
"dependencies": {
"@jimrising/easymerchantsdk-react-native": "^2.4.8"
}Or install it via npm:
npm install @jimrising/easymerchantsdk-react-native2. Android Configuration
- Open
android/build.gradleand add the following to theallprojects.repositoriessection:
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
maven {
url = uri("https://maven.pkg.github.com/jimrising/easymerchantsdk-react-native")
credentials {
username = properties.getProperty('GITHUB_USERNAME')
password = properties.getProperty('GITHUB_PASSWORD')
}
}
}
}- Define
GITHUB_USERNAMEandGITHUB_PASSWORDinandroid/gradle.properties:
GITHUB_USERNAME=your-github-username
GITHUB_PASSWORD=your-github-token- Sync your project with Gradle to apply changes.
3. iOS Configuration
- Update AppDelegate.swift
Modify ios/AppDelegate.swift to initialize the React Native bridge and set up the EasyMerchant SDK:
import UIKit
import easymerchantsdk
import React
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let jsCodeLocation: URL
#if DEBUG
jsCodeLocation = URL(string: "http://localhost:8081/index.bundle?platform=ios")!
#else
jsCodeLocation = Bundle.main.url(forResource: "main", withExtension: "jsbundle")!
#endif
let bridge = RCTBridge(
bundleURL: jsCodeLocation,
moduleProvider: nil,
launchOptions: launchOptions
)
guard let validBridge = bridge else {
fatalError("React Native bridge failed to initialize.")
}
let rootView = RCTRootView(
bridge: validBridge,
moduleName: "EasyMerchantTestApp", // Replace with your app's module name
initialProperties: nil
)
self.window = UIWindow(frame: UIScreen.main.bounds)
let rootViewController = UIViewController()
rootViewController.view = rootView
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
if let easyMerchantSdkPlugin = validBridge.module(for: EasyMerchantSdkPlugin.self) as? EasyMerchantSdkPlugin {
easyMerchantSdkPlugin.setViewController(rootViewController)
} else {
print("Failed to retrieve EasyMerchantSdkPlugin instance from React Native bridge.")
}
return true
}
}- Update Podfile
In ios/Podfile, add the EasyMerchant SDK pod:
platform :ios, '16.0'
pod 'easymerchantsdk', :path => '../node_modules/@jimrising/easymerchantsdk-react-native/ios'
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'- Install pod dependencies:
cd ios
pod install --repo-updateUsage
This section explains how to configure and process payments using makePayment (direct payment) and makePaymentV2 (client token-based payment). Each flow uses a specific configuration object, with makePaymentV2 requiring a clientToken instead of apiKey and secretKey.
1. Import Required Modules
import { NativeModules, Platform, Alert, NativeEventEmitter } from 'react-native';
const { RNEasymerchantsdk, EasyMerchantSdk } = NativeModules;2. Define Configurations
Configuration for makePayment
The makePayment flow requires apiKey and secretKey. Below is a sample configuration:
const configMakePayment = {
amount: '5.0', // String or number, must be positive
appearanceSettings: {
bodyBackgroundColor: '#121212', // String: hex color
borderRadius: '8', // String: border radius in pixels
containerBackgroundColor: '#1E1E1E', // String: hex color
fontFamily: '"Inter", sans-serif', // String: font family
fontSize: '16', // String: font size in pixels
fontWeight: 500, // Number: font weight
primaryButtonBackgroundColor: '#2563EB', // String: hex color
primaryButtonFontColor: '#FFFFFF', // String: hex color
primaryButtonHoverColor: '#1D4ED8', // String: hex color
primaryFontColor: '#FFFFFF', // String: hex color
secondaryButtonBackgroundColor: '#374151', // String: hex color
secondaryButtonFontColor: '#E5E7EB', // String: hex color
secondaryButtonHoverColor: '#4B5563', // String: hex color
secondaryFontColor: '#B0B0B0', // String: hex color
theme: 'light', // String: 'light' or 'dark'
},
apiKey: 'replace-with-api-key', // String: environment-specific API key
authenticatedACH: true, // Boolean: enable authenticated ACH
currency: 'usd', // String: currency code, e.g., 'usd'
email: '[email protected]', // String: customer email
environment: 'sandbox', // String: 'sandbox' or 'production'
fields: {
additional: [
{ name: 'phone_number', required: false, value: '+1-555-123-4567' },
{ name: 'description', required: true, value: 'Test payment for development purposes' }
],
billing: [
{ name: 'address', required: true, value: '123 Main Street, Suite 100' },
{ name: 'country', required: true, value: 'United States' },
{ name: 'state', required: true, value: 'California' },
{ name: 'city', required: false, value: 'San Francisco' },
{ name: 'postal_code', required: true, value: '94105' }
],
visibility: { additional: false, billing: false }, // Object: field visibility
},
grailPayParams: {
brandingName: 'Lyfecycle Payments', // String: branding name
finderSubtitle: 'Search for your bank', // String: bank finder subtitle
role: 'business', // String: GrailPay role
searchPlaceholder: 'Enter bank name', // String: search placeholder
timeout: 10, // Number: timeout in seconds
},
isEmail: true, // Boolean: allow email editing
is_recurring: false, // Boolean: enable recurring payments
metadata: {
metadataOne: 'metadataOne', // String: custom metadata
metadataTwo: 'metadataTwo' // String: custom metadata
},
name: 'John Doe', // String: customer name
numOfCycle: 2, // if is_recurring == true
paymentMethods: ['card', 'ach'], // Array: at least one method ('card', 'ach')
recurringIntervals: ['daily', 'weekly', 'monthly'], // if is_recurring == true
recurringStartDate: 'dd/MM/yyyy', // must be today // required if is_recurring == true
recurringStartDateType: 'fixed', // if is_recurring == true
saveAccount: true, // Boolean: save account details for ACH
saveCard: true, // Boolean: save card details
secretKey: 'replace-with-secret-key', // String: environment-specific secret key
secureAuthentication: true, // Boolean: enable 3D Secure
showDonate: false, // Boolean: show donation option
showReceipt: true, // Boolean: show receipt after payment
showSubmitButton: true, // Boolean: show submit button
showTotal: true, // Boolean: display total amount
submitButtonText: 'Submit', // String: payment button text
tokenOnly: false, // Boolean: true for tokenization, false for full payment
};
Configuration for makePaymentV2
The makePaymentV2 flow requires a clientToken and omits apiKey and secretKey. Below is a sample configuration:
const configMakePaymentV2 = {
appearanceSettings: {
bodyBackgroundColor: '#121212', // String: hex color
borderRadius: '8', // String: border radius in pixels
containerBackgroundColor: '#1E1E1E', // String: hex color
fontFamily: '"Inter", sans-serif', // String: font family
fontSize: '16', // String: font size in pixels
fontWeight: 500, // Number: font weight
primaryButtonBackgroundColor: '#2563EB', // String: hex color
primaryButtonFontColor: '#FFFFFF', // String: hex color
primaryButtonHoverColor: '#1D4ED8', // String: hex color
primaryFontColor: '#FFFFFF', // String: hex color
secondaryButtonBackgroundColor: '#374151', // String: hex color
secondaryButtonFontColor: '#E5E7EB', // String: hex color
secondaryButtonHoverColor: '#4B5563', // String: hex color
secondaryFontColor: '#B0B0B0', // String: hex color
theme: 'light', // String: 'light' or 'dark'
},
authenticatedACH: true, // Boolean: enable authenticated ACH
clientToken: 'replace-with-client-token', // String: client token from payment intent API
currency: 'usd', // String: currency code, e.g., 'usd'
email: '[email protected]', // String: customer email
environment: 'sandbox', // String: 'sandbox' or 'production'
fields: {
additional: [
{ name: 'phone_number', required: false, value: '+1-555-123-4567' },
{ name: 'description', required: true, value: 'Test payment for development purposes' }
],
billing: [
{ name: 'address', required: true, value: '123 Main Street, Suite 100' },
{ name: 'country', required: true, value: 'United States' },
{ name: 'state', required: true, value: 'California' },
{ name: 'city', required: false, value: 'San Francisco' },
{ name: 'postal_code', required: true, value: '94105' }
],
visibility: { additional: false, billing: false }, // Object: field visibility
},
grailPayParams: {
brandingName: 'Lyfecycle Payments', // String: branding name
finderSubtitle: 'Search for your bank', // String: bank finder subtitle
role: 'business', // String: GrailPay role
searchPlaceholder: 'Enter bank name', // String: search placeholder
timeout: 10, // Number: timeout in seconds
},
isEmail: true, // Boolean: allow email editing
metadata: {
metadataOne: 'metadataOne', // String: custom metadata
metadataTwo: 'metadataTwo', // String: custom metadata
},
name: 'John Doe', // String: customer name
paymentMethods: ['card', 'ach'], // Array: at least one method ('card', 'ach')
saveAccount: true, // Boolean: save account details for ACH
saveCard: true, // Boolean: save card details
secureAuthentication: true, // Boolean: enable 3D Secure
showDonate: false, // Boolean: show donation option
showReceipt: true, // Boolean: show receipt after payment
showSubmitButton: true, // Boolean: show submit button
showTotal: true, // Boolean: display total amount
submitButtonText: 'Submit', // String: payment button text
};Key Differences:
- makePayment: Requires
apiKeyandsecretKey, used for direct payment processing. - makePaymentV2: Requires
clientToken(obtained from the payment intent API) and omitsapiKeyandsecretKey. - Environment Initialization: Required for
makePaymenton iOS; not needed formakePaymentV2.
3. Initialize Environment (iOS Only, for makePayment)
For makePayment on iOS, configure the environment before processing payments:
const initializeEnvironment = async () => {
try {
await EasyMerchantSdk.setViewController();
await EasyMerchantSdk.configureEnvironment(configMakePayment.environment, configMakePayment.apiKey, configMakePayment.secretKey);
console.log(`iOS Environment configured: ${configMakePayment.environment}`);
} catch (error) {
console.error('iOS Initialization Error:', error);
Alert.alert('Error', `Failed to configure iOS environment: ${error.message}`);
}
};Note: This step is required only for makePayment on iOS. Android and makePaymentV2 do not require environment initialization.
4. Process Payments
Using makePayment (Direct Payment)
const handlePayment = async () => {
if (!configMakePayment.amount || isNaN(parseFloat(configMakePayment.amount)) || parseFloat(configMakePayment.amount) <= 0) {
Alert.alert('Error', 'Please set a valid amount');
return;
}
if (!configMakePayment.paymentMethods || configMakePayment.paymentMethods.length === 0) {
Alert.alert('Error', 'Please select at least one payment method');
return;
}
if (configMakePayment.is_recurring && (!configMakePayment.recurringIntervals || configMakePayment.recurringIntervals.length === 0)) {
Alert.alert('Error', 'Please select at least one interval for recurring payment');
return;
}
try {
if (Platform.OS === 'android') {
const response = await RNEasymerchantsdk.makePayment(configMakePayment);
const raw = response?.response ? JSON.parse(response.response) : {};
const parsedResponse = {
...raw,
billingInfo: raw.billingInfo ? JSON.parse(raw.billingInfo) : raw.billingInfo,
additional_info: raw.additional_info ? JSON.parse(raw.additional_info) : raw.additional_info
};
console.log('Android Payment Response:', parsedResponse);
Alert.alert('Success', 'Payment processed!');
} else {
await initializeEnvironment();
const configString = JSON.stringify(configMakePayment);
const result = await EasyMerchantSdk.makePayment(configString);
const refToken = result?.additionalInfo?.threeDSecureStatus?.data?.ref_token;
console.log('iOS Payment Response:', result);
if (refToken) console.log('Reference Token:', refToken);
Alert.alert('Success', 'Payment processed!');
}
} catch (error) {
console.error(`${Platform.OS === 'android' ? 'Android' : 'iOS'} Payment Error:`, error);
Alert.alert('Payment Error', error.message || 'Unknown error');
}
};Using makePaymentV2 (Client Token-Based)
const handlePaymentV2 = async () => {
if (!configMakePaymentV2.clientToken) {
Alert.alert('Error', 'Please provide a valid client token');
return;
}
if (!configMakePaymentV2.paymentMethods || configMakePaymentV2.paymentMethods.length === 0) {
Alert.alert('Error', 'Please select at least one payment method');
return;
}
if (configMakePaymentV2.is_recurring && (!configMakePaymentV2.recurringIntervals || configMakePaymentV2.recurringIntervals.length === 0)) {
Alert.alert('Error', 'Please select at least one interval for recurring payment');
return;
}
try {
if (Platform.OS === 'android') {
const response = await RNEasymerchantsdk.makePaymentV2(configMakePaymentV2);
const raw = response?.response ? JSON.parse(response.response) : {};
const parsedResponse = {
...raw,
billingInfo: raw.billingInfo ? JSON.parse(raw.billingInfo) : raw.billingInfo,
additional_info: raw.additional_info ? JSON.parse(raw.additional_info) : raw.additional_info
};
console.log('Android Payment V2 Response:', parsedResponse);
Alert.alert('Success', 'Payment V2 processed!');
} else {
const configString = JSON.stringify(configMakePaymentV2);
const result = await EasyMerchantSdk.makePaymentV2(configString);
const refToken = result?.additionalInfo?.threeDSecureStatus?.data?.ref_token;
console.log('iOS Payment V2 Response:', result);
if (refToken) console.log('Reference Token:', refToken);
Alert.alert('Success', 'Payment V2 processed!');
}
} catch (error) {
console.error(`${Platform.OS === 'android' ? 'Android' : 'iOS'} Payment V2 Error:`, error);
Alert.alert('Payment V2 Error', error.message || 'Unknown error');
}
};How It Works:
- makePayment: Uses
configMakePaymentwithapiKeyandsecretKey. Requires environment initialization on iOS. - makePaymentV2: Uses
configMakePaymentV2withclientToken. Does not require environment initialization. - Android: Pass the config object directly. Parse
billingInfoandadditional_infoif they are JSON strings. - iOS: Stringify the config (
JSON.stringify(config)) for both methods. Storeref_tokenfor 3D Secure transactions. - Validation: Ensures
amountis positive, at least one payment method is selected, and aclientTokenis provided formakePaymentV2. - Error Handling: Displays user-friendly alerts for errors.
5. Android Event Listeners
Set up event listeners for Android to handle payment success, status, and errors:
const setupAndroidEventListeners = () => {
if (Platform.OS !== 'android' || !RNEasymerchantsdk) {
console.warn('RNEasymerchantsdk not available or not Android.');
return () => {};
}
const easyMerchantEvents = new NativeEventEmitter(RNEasymerchantsdk);
const successSub = easyMerchantEvents.addListener('PaymentSuccess', (data) => {
const parsed = JSON.parse(data.response || '{}');
const result = {
...parsed,
billingInfo: parsed.billingInfo ? JSON.parse(parsed.billingInfo) : parsed.billingInfo,
additional_info: parsed.additional_info ? JSON.parse(parsed.additional_info) : parsed.additional_info
};
console.log('Payment Success:', result);
Alert.alert('Success', 'Payment processed!');
});
const statusSub = easyMerchantEvents.addListener('PaymentStatus', (data) => {
const parsed = JSON.parse(data.statusResponse || '{}');
console.log('Payment Status:', parsed);
Alert.alert('Status', JSON.stringify(parsed));
});
const statusErrorSub = easyMerchantEvents.addListener('PaymentStatusError', (data) => {
let parsedError = data.error;
try {
if (typeof parsedError === 'string') parsedError = JSON.parse(parsedError);
} catch (e) {}
console.error('Payment Status Error:', parsedError);
Alert.alert('Status Error', JSON.stringify(parsedError));
});
return () => {
successSub.remove();
statusSub.remove();
statusErrorSub.remove();
};
};Note: Call setupAndroidEventListeners() during app initialization and clean up listeners when done (returned function).
6. Check Payment Status (Android Only)
Check the status of a payment on Android:
const checkPaymentStatus = async () => {
if (Platform.OS !== 'android') {
Alert.alert('Error', 'Payment status check is Android-only');
return;
}
try {
const response = await RNEasymerchantsdk.checkPaymentStatus();
console.log('Payment Status:', response);
Alert.alert('Status', JSON.stringify(response));
} catch (error) {
console.error('Status Check Error:', error);
Alert.alert('Status Check Error', error.message || 'Unknown error');
}
};7. Payment Reference (iOS Only)
Retrieve payment reference details on iOS using a ref_token:
const checkPaymentReference = async (refToken) => {
if (Platform.OS !== 'ios') {
Alert.alert('Error', 'Payment reference is iOS-only');
return;
}
try {
const response = await EasyMerchantSdk.paymentReference(refToken);
console.log('Payment Reference:', response);
Alert.alert('Payment Reference', JSON.stringify(response));
} catch (error) {
console.error('Payment Reference Error:', error);
Alert.alert('Payment Reference Error', error.message || 'Unknown error');
}
};Notes
- Payment Methods: Use
['card', 'ach'](lowercase). - Recurring Payments: Set
is_recurring: trueand include at least one interval inrecurringIntervals. - Security: Store
apiKey,secretKey, andclientTokensecurely (e.g., in environment variables) and ensure they match theenvironment. - Optional Fields: Set
fields.billingandfields.additionalto[]if not needed. Usefields.visibilityto control display. - Theming: Customize
appearanceSettingsfor UI consistency. Ensure hex colors are valid. - GrailPay: Configure
grailPayParamsfor bank search UI (used with ACH payments). - Platform Differences:
- Android uses a direct object for
makePaymentandmakePaymentV2; iOS requires a JSON string. makePaymenton iOS requires environment initialization;makePaymentV2does not.- Android supports event listeners; iOS uses direct method responses.
- Android uses a direct object for
- Client Token: Required for
makePaymentV2. Obtain via the payment intent API (/api/v1/paymentintent).
