Venmo - React Native SDK
@paysafe/paysafe-venmo is part of the Paysafe PH Mobile React Native SDK — a suite of packages designed to provide seamless payment integrations for React Native applications.
This package enables Venmo payments by bridging the existing Paysafe native SDK into the React Native environment. It allows developers to integrate Venmo checkout flows, handle payment results, and interact with Venmo from TypeScript, while leveraging the reliability and performance of Paysafe’s native SDK.
It resides within a monorepo alongside other React Native payment modules and uses React Native bridges to communicate with the underlying native Android SDK.
Prerequisites
API key
For information on obtaining your API key, refer to the React Native SDK Overview.
Using the Demo app
To test the Venmo integration using the Demo app, you must modify some arguments representing the API key and the account id associated with the Venmo payment method.
- open DemoAppExpo/android/app/src/main/java/com/DemoAppExpo/MainApplication.kt file
- pass a valid API key to setupPaysafeSdk method
- pass a valid accountId to initialize method
- start DemoAppExpo with npx expo run:android runner from DemoAppExpo directory
Testing in the TEST environment
To test the Venmo integration on Android in the TEST environment, you must configure the SDK using the "TEST" parameter. (Refer to the Setup section below for details.)
NOTE: Testing in the TEST environment requires the Venmo Test App, not the production version available on the Google Play Store. Using the production app will result in authorization failures.
The Venmo Test App does not require real credentials—any email and password will work.
The Android test app is available through PayPal's AppCenter. Please contact integrations@paysafe.com to obtain access.
Integrating the Venmo package
To integrate the Venmo package into your React Native application, install it via npm:
npm install @paysafe/paysafe-venmo@current-version
NOTE: Replace current-version with the correct version number from the GitHub version catalog.
Initialization
NOTE: You must call setupPaysafeSdk before initializing any components.
To process a Venmo payment request, PSVenmoContext must be initialized.
Initialize method signature
/**
Initializes the Venmo integration from native android code.
@param activity The component activity instance from which the venmo integration is initialized.
@param currencyCode The currency that customer use for Venmo integration.
@param accountId The Venmo account id that customer use for Venmo integration.
@param onInitSuccess An optional callback invoked when the PSVenmoContext is successfully initialized.
@param onInitFailure An optional callback invoked when initialization fails, providing the [Exception] that caused the failure.
*/
fun initialize(
activity: Activity? = null,
currencyCode: String,
accountId: String,
onInitSuccess: (() -> Unit)? = null,
onInitFailure: ((Exception) -> Unit)? = null
)
/**
Initializes the Venmo integration from native android code.
@param fragment The fragment instance from which the venmo integration is initialized.
@param currencyCode The currency that customer use for Venmo integration.
@param accountId The Venmo account id that customer use for Venmo integration.
@param onInitSuccess An optional callback invoked when the PSVenmoContext is successfully initialized.
@param onInitFailure An optional callback invoked when initialization fails, providing the [Exception] that caused the failure.
*/
fun initialize(
fragment: Fragment? = null,
currencyCode: String,
accountId: String,
onInitSuccess: (() -> Unit)? = null,
onInitFailure: ((Exception) -> Unit)? = null
)
/**
Initializes the Venmo integration from typescript code.
@param currencyCode The currency that customer use for Venmo integration.
@param accountId The Venmo account id that customer use for Venmo integration.
function initializeVenmo(currencyCode: string, accountId: string)
The initialize method uses currentActivity from reactApplicationContext.
This method will call the native Android SDK's initialize method and initialize PSVenmoContext on success.
| Parameter | Required | Type | Description |
|---|---|---|---|
| activity | false | Activity | The activity instance from which the Venmo integration is initialized. If not provided, currentActivity from reactApplicationContext will be used. |
| currencyCode | true | string | currencyCode accepts 3-letter abbreviations of the ISO standard currencies. |
| accountId | true | string | ID of the selected merchant account used to process the payment. If you are a merchant, this is required only if multiple accounts are configured for the same payment method and currency. If you are a partner using a shared API key, this field is mandatory. |
After the initialization process, an event will be sent for communication with JavaScript.
| case | event |
|---|---|
| onSuccess | VenmoInitializedSuccessful |
| onFailure | VenmoInitializationFailed |
Initialize exceptions
| Error code | Display message | Detailed message | Comments |
|---|---|---|---|
9061 | There was an error (9061), please contact our support. | Invalid account id for ${paymentMethod} | AccountId is present, but not configured for the required payment context. |
9101 | There was an error (9101), please contact our support. | Invalid accountId parameter | The SDK checks if the accountId string contains only numbers. |
9055 | There was an error (9055), please contact our support. | Invalid currency parameter | The SDK checks if the currency parameter has only 3 letters. This exception is thrown when the server responds with code 5001. |
9085 | There was an error (9085), please contact our support. | There are no available payment methods for this API key. |
|
9084 | There was an error (9084), please contact our support. | Failed to load available payment methods | Triggered by an internal server error during the payment methods API call. |
9073 | There was an error (9073), please contact our support. | Account not configured correctly. | Caused by an improperly created merchant account configuration:
|
Tokenization
The tokenize method returns an event containing a PaymentHandle result, which resolves to a single-use payment handle representing the customer's sensitive card data. This handle can be used with the Payments API to process payments. Single-use handles are valid for only 15 minutes and are not consumed by verification.
For more details, see Payments with a Handle.
Tokenize method signature
The tokenize function has the following signature:
/**
Tokenization using Venmo from native android code.
@param readableVenmoTokenizeOptions Options for tokenizing Venmo data.
@param coroutineScope The [CoroutineScope] used to launch the tokenization request (defaults to [Dispatchers.IO]).
@param onTokenizeSuccess An optional callback invoked when tokenization is successful. Provides the resulting payment handle token as a [String].
@param onTokenizeFailure An optional callback invoked when tokenization fails. Provides the [Exception] that caused the failure.
@param onTokenizeCancelled An optional callback invoked when tokenization is cancelled by the user. Provides the [Exception] representing the cancellation reason.
*/
fun tokenize(
readableVenmoTokenizeOptions: ReadableMap,
coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.IO),
onTokenizeSuccess: ((String) -> Unit)? = null,
onTokenizeFailure: ((Exception) -> Unit)? = null,
onTokenizeCancelled: ((Exception) -> Unit)? = null
)
function tokenizeVenmo(readableVenmoTokenizeOptions: unknown)
readableVenmoTokenizeOptions are from type ReadableMap
This method calls the native Android SDK tokenize method and executes a callBack once the tokenization process is complete. The completion handler provides the single-use payment handle or any error encountered during the tokenization process.
/**
Callback interface for receiving the result of Venmo tokenization.
*/
interface PSVenmoTokenizeCallback {
/**
Called when Venmo tokenization is successful.
@param paymentHandle The payment handle representing the tokenized data.
*/
fun onSuccess(paymentHandleToken: String)
/**
Called when an error occurs during Venmo tokenization.
@param exception The exception indicating the error encountered during tokenization.
*/
fun onFailure(exception: Exception)
/**
Called when Venmo tokenization is cancelled.
@param paysafeException The Paysafe exception indicating the cancellation reason.
*/
fun onCancelled(paysafeException: PaysafeException)
}
Parameters:
-
readableVenmoTokenizeOptions: The ReadableMap of VenmoTokenizeOptions provides a comprehensive set of options for configuring the tokenization process. For more information about the options, see Android SDK Venmo PSVenmoTokenizeOptions.
After the tokenization process, an event will be sent for communication with JavaScript.
| case | event |
|---|---|
| onSuccess | VenmoTokenizationSuccessful |
| onFailure | VenmoTokenizationFailed |
| onCancelled | VenmoTokenizationCanceled |
Tokenization exceptions
For information about tokenization exceptions, see Android SDK Venmo Tokenization Exceptions.
In your MainApplication, set up the Paysafe SDK first, then initialize Venmo.
import com.paysafevenmo.PaysafeVenmoModule
override fun onCreate() {
super.onCreate()
SoLoader.init(this, OpenSourceMergedSoMapping)
registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
PaysafeVenmoModule.setupPaysafeSdk(
"api-key",
"TEST"
)
PaysafeVenmoModule.initialize(activity, "USD", "account-id")
}
override fun onActivityStarted(activity: Activity): Unit = Unit
override fun onActivityResumed(activity: Activity): Unit = Unit
override fun onActivityPaused(activity: Activity): Unit = Unit
override fun onActivityStopped(activity: Activity): Unit = Unit
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle): Unit = Unit
override fun onActivityDestroyed(activity: Activity): Unit = Unit
})
}
In your TypeScript code, you can now listen for the initialization status event. Once the success event is received, you can proceed with tokenization.
import { NativeEventEmitter, Alert, Button, findNodeHandle, InteractionManager, TouchableOpacity, ActivityIndicator, NativeModules } from 'react-native';
import React, { useEffect, useState, useRef } from 'react';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { ThemedText } from '@/components/ThemedText';
import { ThemedView } from '@/components/ThemedView';
import { IconSymbol } from '@/components/ui/IconSymbol';
import { useRouter } from 'expo-router';
import * as Venmo from 'paysafe-venmo';
export default function screen() {
const [isVenmoInitialized, setIsVenmoInitialized] = useState<boolean>(false);
const [loadingVenmo, setLoadingVenmo] = useState<boolean>(true);
const router = useRouter();
useEffect(() => {
const eventEmitterVenmo = new NativeEventEmitter(Venmo);
let receivedEventVenmoInitialized = false;
const subscriptionVenmoInitializationSuccess = eventEmitterVenmo.addListener(
'VenmoInitializedSuccessful',
() => {
receivedEventVenmoInitialized = true;
setIsVenmoInitialized(true);
setLoadingVenmo(false);
}
);
const subscriptionVenmoInitializationFailure = eventEmitterVenmo.addListener(
'VenmoInitializationFailed',
(error: { title?: string; message?: string }) => {
receivedEventVenmoInitialized = true;
setIsVenmoInitialized(false);
setLoadingVenmo(false);
const errorTitle = error?.title ?? 'Venmo Initialization Failed';
const errorMessage = error?.message ?? 'Unknown error occurred while initializing Venmo.';
Alert.alert(errorTitle, errorMessage);
}
);
const subscriptionVenmoTokenizationSuccess = eventEmitterVenmo.addListener(
'VenmoTokenizationSuccessful',
(eventData) => {
const token = eventData?.paymentHandleToken;
router.push({
pathname: '/paymentSuccessScreen',
params: { token },
});
}
);
const subscriptionVenmoTokenizationFailure = eventEmitterVenmo.addListener(
'VenmoTokenizationFailed',
(error) => {
Alert.alert('Payment Failed', error?.message ?? 'An error occurred during tokenization.');
}
);
setTimeout(() => {
if (!receivedEventVenmoInitialized) {
setIsVenmoInitialized(false);
setLoadingVenmo(false);
}
}, 30000);
return () => {
subscriptionVenmoInitializationSuccess.remove();
subscriptionVenmoInitializationFailure.remove();
subscriptionVenmoTokenizationSuccess.remove();
subscriptionVenmoTokenizationFailure.remove();
};
}, []);
const venmoTokenizeOptions = {
amount: 10000,
currencyCode: 'USD',
transactionType: 'PAYMENT',
merchantRefNum: 'merchant_ref_' + Math.floor(Math.random() * 1000000),
billingDetails: {
nickName: 'NickName',
street: 'Street',
city: 'City',
state: 'AL',
country: 'US',
zip: '12345',
},
profile: {
firstName: 'John',
lastName: 'Doe',
locale: 'EN_GB',
merchantCustomerId: 'customer_123',
dateOfBirth: {
day: 1,
month: 1,
year: 1990,
},
email: 'email@mail.com',
phone: '0123456789',
mobile: '0123456789',
gender: 'MALE',
nationality: 'US',
},
accountId: '1002777190',
merchantDescriptor: {
dynamicDescriptor: 'dynamicDescriptor',
phone: '0123456789',
},
shippingDetails: {
shipMethod: 'NEXT_DAY_OR_OVERNIGHT',
street: 'Street',
street2: 'Street2',
city: 'Marbury',
state: 'AL',
countryCode: 'US',
zip: '36051',
},
customUrlScheme: 'customScheme',
venmoRequest: {
consumerId: 'customer-123243421',
merchantAccountId: 'merch-acc-id',
profileId: 'profile-id',
},
};
const handleVenmoPayment = () => {
try {
Venmo.tokenizeVenmo(venmoTokenizeOptions);
} catch (error: unknown) {
setLoadingVenmo(false);
Alert.alert('Error', `Venmo tokenization failed: ${error?.message || error}`);
}
};
return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
headerImage={
<IconSymbol
size={310}
color="#808080"
name="chevron.left.forwardslash.chevron.right"
style={paymentsStyles.headerImage}
/>
}>
<ThemedView style={paymentsStyles.titleContainer}>
<ThemedText type="title">Explore</ThemedText>
</ThemedView>
<ThemedText>Venmo Initialized: {isVenmoInitialized ? 'Yes' : 'No'}</ThemedText>
{isVenmoInitialized && !loadingVenmo && (
<Button title="Pay with Venmo" onPress={handleVenmoPayment} />
)}
</ParallaxScrollView
Setting up context switching
To enable Venmo integration in your app, you will need to configure a few settings to support context switching—allowing your app to open the Venmo app and receive control back after the payment is completed.
-
To enable your app to handle Venmo deep linking, you need to configure an intent filter in the AndroidManifest.xml:
<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="${applicationId}.braintree" />
</intent-filter> -
In the Venmo app settings, go to Choose Channel and select App Switch.
NOTE: You can perform both initialization and tokenization either in your TypeScript code or in the native part of your code.