Forte React Native SDK for iOS, Android, and Web
Integration for mobile browser and in-app payments
Overview
Forte’s PCI compliant React Native SDK solution allows customers the convenience of making payments via mobile apps on iOS and Android platforms while providing Merchant developers the framework to efficiently integrate this flow and retain total control of their application experience.
The SDK supports the request to the Forte platform for a one-time token that can be used to send encrypted cardholder and payment method data to Forte. This reduces the chance of exposing sensitive customer information because it moves this information directly to Forte’s servers instead of yours.
Integration using React Native saves time and developing efforts at programming the payment flow for mobile apps because it provides a PCI-compliant component that may be used for both iOS and Android apps and web or in browser payments, simplifying integration projects.
The steps below outline how the SDK can be downloaded, installed, configured, and tested, including the transaction using tokens provided in the process.
Getting Started
The following sections detail what actions you must perform before you can begin processing payments from your mobile platform. Use these steps to download, install and configure options for your application.
Step 1: Generating Credentials
Make sure you have a Sandbox account in Dex to generate API credentials.
Before creating your first API request, you must create your API authentication credentials. These include an API Access ID, which acts as your username, and an API Secure Key, which acts as a password. You will create and maintain these credentials exclusively in Dex.
To generate your API Access ID and API Secure Key, complete the following steps:
- From a Google Chrome browser, log into your Dex Account.
- Select Developer > API Credentials from the Dex Main Menu.
- Click the CREATE button. The Create API Credentials screen displays.
- Enter a name for this set of API credentials in the Name field.
- Click the CREATE NEW API KEY button. The API Access ID and API Secure Key values display in their corresponding fields.
- Click the COPY button next to the API Access ID and API Secure Key fields to record both of these newly generated values in a secure location to use in authenticating your REST API requests.
NOTE: Once you save your API Secure Key, you will not be able to see the value again. If you forget your API Secure Key or it becomes compromised, you will have to regenerate the value in Dex.
STEP 2: Downloading and Installing the SDK
The SDK is housed on the npm repositories and can be accessed by following the steps for Download / Install Packages.
Download / Install Packages
To install the SDK, use the following:
# With npm
npm i @fortepayments/forte-react-native-sdk
# With Yarn
yarn add @fortepayments/forte-react-native-sdk
Dependencies
Peer Dependencies
"peerDependencies": {
"react": "*",
"react-native":
},
STEP 3: Configuring Options
In this step you can define the state of the parameters for the payment form.
import FortePaymentView, { init } from '@fortepayments/forte-react-native-sdk';
//declare the api environement to hit i.e. sandbox or prod
const backendType = 'sandbox';
//allowed card types declaration from client application
const [cardTypes, setCardTypes] = useState([
{
id: 0,
title: 'visa',
checked: false,
},
{
id: 1,
title: 'mastercard',
checked: false,
},
{
id: 2,
title: 'discover',
checked: false,
},
{
id: 3,
title: 'amex',
checked: false,
},
{
id: 4,
title: 'jcb',
checked: false,
},
{
id: 5,
title: 'dinersclub',
checked: false,
},
]);
//allowed payment method declaration from client application
const [paymentMethods, setPaymentMethods] = useState([
{
id: 0,
title: 'card',
checked: false,
},
{
id: 1,
title: 'echeck',
checked: false,
},
]);
const getBackendUrl = () => {
if (backendType === 'sandbox') {
return 'sandbox';
}
else if (backendType === 'production') {
return 'production';
}
}
//setting init params
const setInitParam = () => {
setParamSection(false);
let selectedPaymentMethods = [];
let selectedCardTypes = [];
paymentMethods
.filter(item => item.checked)
.map(item => selectedPaymentMethods.push(item.title));
cardTypes
.filter(item => item.checked)
.map(item => selectedCardTypes.push(item.title));
let tempInitObject = {
appLoginId: LoginId
cardValidTillYears: 20
supportedPaymentMethods: selectedPaymentMethods,
supportedCardTypes: selectedCardTypes,
environment: getBackendUrl()
};
//Init object based on init object
setTimeout(() => {
let response = init(tempInitObject);
//if you have down stream logic based on init success , you could invoke them
//SomeDownStreamProcessOrUpdate(!response.success);
}, 1000);
};
//calling init function
setInitParam()
//Javascript functions
const fortePaymentViewRef = useRef(null);
const onPressFunctionOfClientApp = async () => {
if (fortePaymentViewRef) {
const apiResponse = await fortePaymentViewRef.current.submit();
console.log('apiResponse', apiResponse);
}
};
//Markup
<View
style={{
paddingBottom: '20%',
}}>
<FortePaymentView
ref={fortePaymentViewRef}
onLoaderState={loaderValue => setLoaderVisible(loaderValue)}
/>
<TouchableOpacity
style={{
backgroundColor: appColor,
borderWidth: 1,
borderRadius: 3,
borderColor: appColor,
height: Platform.OS == 'web' ? '5%' : '7.5%',
width: Platform.OS == 'web' ? '15%' : '40%',
alignSelf: 'center',
alignContent: 'center',
alignItems: 'center',
justifyContent: 'center',
marginTop: Platform.OS == 'web' ? '1%' : '10%',
}}
onPress={onPressFunctionOfClientApp}>
<Text style={{ color: '#FFFFFF' }}>Done</Text>
</TouchableOpacity>
)}
</View>
//Javascript functions
const fortePaymentViewRef = useRef(null);
const onPressFunctionOfClientApp = async () => {
if (fortePaymentViewRef) {
const apiResponse = await fortePaymentViewRef.current.submit();
console.log('apiResponse', apiResponse);
}
};
//Markup
<View
style={{
paddingBottom: '20%',
}}>
<FortePaymentView
ref={fortePaymentViewRef}
onLoaderState={loaderValue => setLoaderVisible(loaderValue)}
/>
<TouchableOpacity
style={{
backgroundColor: appColor,
borderWidth: 1,
borderRadius: 3,
borderColor: appColor,
height: Platform.OS == 'web' ? '5%' : '7.5%',
width: Platform.OS == 'web' ? '15%' : '40%',
alignSelf: 'center',
alignContent: 'center',
alignItems: 'center',
justifyContent: 'center',
marginTop: Platform.OS == 'web' ? '1%' : '10%',
}}
onPress={onPressFunctionOfClientApp}>
<Text style={{ color: '#FFFFFF' }}>Done</Text>
</TouchableOpacity>
)}
</View>
STEP 4: Creating the OTT Request Object
To create the OTT, use the following parameters.
- Login ID: Your API login ID
- Card Valid Until Date: How far ahead you set the expiration date. For ex: 20 years.
- Supported Payment Method: You can set up to show card, and eCheck (ACH) or just one payment option. End users would choose from the options you provide.
- Supported Card Types: Supported card brands are Visa, Mastercard, Discover, American Express, JCB, Diner’s Club.
- Valid account and routing numbers.
- A method to submit information. This function checks to see if the Forte payment view reference is initialized.
STEP 5: Triggering the Call for OTT Generation
Use the init() method from the SDK, invoking the OTT request object so that payment details are sent to Forte.
STEP 6: Using the Token Received
You will get response code and description for the OTT request. If the response corresponds to a successful authentication, you will receive a one-time token. This token contains the data you need to complete the transaction using the steps outlined in Forte's REST API documentation.
The Transactions section of the documentation details what you need to use POST for credit card and ACH transactions: POST Transaction from a One-Time Token. One-time tokens are valid for up to 60 minutes, and may be submitted to generate a Transaction authorization or create a permanent paymethod token from the one-time token.
Response Codes:
A01 response code OK
UXX error response code
Creating a New RN Project
If you do not already have a project started with CSG Forte, you can create a new one by following these steps.
- Create a New Project with command:
npx react-native init csgfortesample - <latest version>
- Run the following command to install the required libs:
npm install react react-native-
- Install the latest version of Forte React Native SDK: “forte-react-native-sdk” from npm.
- Then copy the "Open Sans" fonts from npm example folder to your assets/fonts folder in your react native project. After that create a new file in your project named: react-native.config.js and add following contents to it:
module.exports = { project: { ios: {}, android: {}, }, assets: ['./assets/fonts/'], };
- Then run:
npx react-native link
- Go to your iOS project folder and run:
pod install
- Replace the contents of the App.js file with the contents form attached
AppBarebones.js
file - Now run:
npm run start
- In a new terminal, run:
npm run ios
. For Android, run:npm run android
If installing from NPM repository: npm install @fortepayments/forte-react-native-sdk
Sample Code
import React, { useRef, useState } from 'react';
import {
View,
TouchableOpacity,
Text,
Platform,
ActivityIndicator,
SafeAreaView,
KeyboardAvoidingView,
ScrollView,
Dimensions,
PixelRatio,
} from 'react-native';
import FortePaymentView, { init } from '@fortepayments/forte-react-native-sdk';
const App = () => {
// Need a reference to the Forte Payment View to call the submit method.
const fortePaymentViewRef = useRef(null);
// Init Options for CSG Forte RN Payment View
let forteOptions = {
appLoginId: 'YOUR_APP_LOGIN_ID', //You should find this from your CSG forte dashboard.
cardValidTillYears: '20',
supportedPaymentMethods: ['card', 'echeck'],
supportedCardTypes: [
'visa',
'mastercard',
'discover',
'amex',
'jcb',
'dinersclub',
],
environment: 'sandbox', // Use 'production' for the live payments.
};
// Call to init function.
// eslint-disable-next-line no-unused-vars
let response = init(forteOptions);
// Example: How you can submit the payment info and get payment token.
// Modify as per your applications requirement.
const onDonePress = async () => {
if (fortePaymentViewRef) {
const apiResponse = await fortePaymentViewRef.current.submit();
apiResponse && alert(JSON.stringify(apiResponse.message));
}
};
// State management to show loading indicator
const [isLoaderVisible, setLoaderVisible] = useState(false);
const convertToPixel = size => {
return PixelRatio.roundToNearestPixel(size);
};
const getDeviceWidth = () => {
return Dimensions.get('window').width;
};
return (
<SafeAreaView
style={{
alignSelf: 'center',
}}>
<KeyboardAvoidingView
behavior={Platform.OS == 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={0}
style={{
alignSelf: 'center',
width:
getDeviceWidth() >= 400
? convertToPixel(400)
: getDeviceWidth() < 320 && getDeviceWidth() > 400
? convertToPixel(360)
: convertToPixel(320),
height: '100%',
}}>
<ScrollView>
<View
style={{
flex: 1,
flexDirection: 'column',
}}>
<View
style={{
paddingBottom: '20%',
}}>
<FortePaymentView
ref={fortePaymentViewRef}
onLoaderState={loaderValue => setLoaderVisible(loaderValue)}
/>
<TouchableOpacity
style={{
backgroundColor: '#0057a8',
borderWidth: 1,
borderRadius: 3,
borderColor: '#0057a8',
height: convertToPixel(40),
width: convertToPixel(150),
alignSelf: 'center',
alignContent: 'center',
alignItems: 'center',
justifyContent: 'center',
marginTop: convertToPixel(25),
}}
onPress={onDonePress}>
<Text style={{ color: '#FFFFFF' }}>Done</Text>
</TouchableOpacity>
{isLoaderVisible && (
<ActivityIndicator
style={{
borderRadius: 2,
width: convertToPixel(150),
alignSelf: 'center',
position: 'absolute',
zIndex: 10,
top: 80,
bottom: 0,
flex: 1,
}}
size="large"
color={'#0057a8'}
/>
)}
</View>
</View>
</ScrollView>
</KeyboardAvoidingView>
</SafeAreaView>
);
};
export default App;
Adding Support for RN for Web
If your project includes web / browser payments, please follow these additional steps:
- Continuing from the last section, run the following command to install required libs:
npm install -D react-dom@"^17.0.2" react-native-web@"^0.17.5" webpack@"^5.67.0" webpack-cli@"^4.10.0" webpack-dev-server@"^4.7.3" url-loader@"^4.1.1" html-webpack-plugin@"^5.5.0" babel-plugin-react-native-web@"^0.17.5" babel-loader@"^8.2.3"
- Then add these two lines in package script:
"build": "rm -rf dist/ && webpack --mode=production --config webpack.config.js", "web": "webpack serve --mode=development --config webpack.config.js"
- Then create a new file in your project named: 'index.html' and add following contents to it:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>CSG Forte</title> <style> @import url('https://fonts.googleapis.com/css2?famil=Open+Sans:wght@300;400;500;600;700&display=swap'); #app-root { display: flex; flex: 1 1 100%; height: 100vh; } </style> </head> <body> <div id="app-root"></div> </body> </html>
- Then create a new file in your project named: ‘index.web.js’ and add following contents to it (here APP is the Main component of the project):
import { AppRegistry } from 'react-native'; import { name as appName } from './app.json'; import App from './App'; if (module.hot) { module.hot.accept(); } AppRegistry.registerComponent(appName, () => App); AppRegistry.runApplication(appName, { initialProps: {}, rootTag: document.getElementById('app-root'), });
- Then create a new file in your project named: `webpack.config.js` and add following contents to it:
const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const appDirectory = path.resolve(__dirname); const { presets } = require(`${appDirectory}/babel.config.js`); const compileNodeModules = ['react-native-web', 'forte-react-native-sdk'].map( moduleName => path.resolve(appDirectory, `node_modules/${moduleName}`), ); const babelLoaderConfiguration = { test: /\.(sass|less|css)|.ttf$|.js$|tsx?$/, // Add every directory that needs to be compiled by Babel during the build. include: [ path.resolve(__dirname, 'index.web.js'), // Entry to your application path.resolve(__dirname, 'App.js'), // Change this to your main App file path.resolve(__dirname, 'src'), ...compileNodeModules, ], use: { loader: 'babel-loader', options: { cacheDirectory: true, presets, plugins: ['react-native-web'], }, }, }; const imageLoaderConfiguration = { test: /\.(gif|jpe?g|png)$/, use: { loader: 'url-loader', options: { name: '[name].[ext]', }, }, }; module.exports = { entry: { app: path.join(__dirname, 'index.web.js'), }, output: { path: path.resolve(appDirectory, 'dist'), publicPath: '/', filename: 'rnw_blogpost.bundle.js', }, resolve: { extensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.web.js', '.js'], alias: { 'react-native$': 'react-native-web', }, }, module: { rules: [babelLoaderConfiguration, imageLoaderConfiguration], }, plugins: [ new HtmlWebpackPlugin({ template: path.join(__dirname, 'index.html'), }), new webpack.HotModuleReplacementPlugin(), new webpack.DefinePlugin({ __DEV__: JSON.stringify(true), }), ], };
- Now Run:
npm run web
- Then look for the line such as Loopback: http://localhost:8080/ in the output and access the web application on the given address.