Several months back I was struggling to integrate payfort payment gateway into my React Native application, even after I found some posts regarding that I couldn't achieve it.
After multiple attempts finally I was able to complete that integration.
I had been thinking to share this for long time but now only I got the time.
Shall we start ?
Contents
- Test account
- Packages & Configurations
- Base Page
- Device id
- SDK Token
- Transaction Object
- Checkout Component
- OnSuccess OnFailure
- Show Payfort
- Thats it
Test Account
First we need a test account to simulate the process. For this, contact merchantsupport-ps@amazon.com and get our test account. Once we got and logged in into our account we need to collect this information from security settings.
- Merchant Identifier
- Access Code
- Request Phrase
Packages & Configuration
Coming to the application, create a simple basic react native project and install these packages.
- axios (for network call)
- crypto-js (for encryption)
- rn-amazon-payment-services (for payfort)
for rn-amazon-payment-services we need to do some platform oriented configurations.
Android
In android\build.gradle
allprojects {
repositories {
...
maven { url 'https://android-sdk.payfort.com' }
}
}
In AndroidManifest.xml
add 2 permissions
< uses-permission android:name="android.permission.INTERNET" />
< uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
iOS
In Podfile (inside the target section)
pod 'PayFortSDK'
In Podfile (at bottom)
post_install do |installer|
installer.pods_project.targets.each do |target|
if ['PayFortSDK'].include? target.name
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
end
end
pod install
Reference > https://paymentservices-reference.payfort.com/docs/api/build/index.html#installing-the-mobile-sdk155
Base Page
All set, lets start touching the front page. Create a simple page with one button at the center which shows the payfort payment page.
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<TouchableOpacity style={styles.btn}>
<Text style={styles.text}>Proceed to Pay</Text>
</TouchableOpacity>
</View>
);
}
To perform a payfort transaction we need to form a transaction object which has the transaction details and an SDK token. For each and every transaction we need a unique SDK token. To generate an SDK token we need device id on which this application runs.
So we have to perform these 5 steps,
- Get Device Id
- Generate SDK Token
- Form Transaction Object
- Configure Checkout Component
- Process Payfort Transaction
Step 1 - Get Device Id
For this we have to call a method from amazon package called getDeviceId
and set the value on page load.
import { getDeviceId } from 'rn-amazon-payment-services';
var deviceId = '';
export default function App() {
. . .
const setupDeviceId = async () => {
deviceId = await getDeviceId();
};
const loadPageData = async () => {
await setupDeviceId();
};
useEffect(() => {
loadPageData();
}, []);
return (
<View style={styles.container}>
. . .
)
}
Step 2 - Generate SDK Token
This is quite tricky.
To get the SDK token, we have to call an API with a request object. This request object should contain properties device_id
, language
, merchant_identifier
, access_code
, service_command
and signature
. Among these properties the signature property value has to be generated from other property values.
Shall we start forming the request object? Lets go one by one.
Define payfort field values of Merchant Identifier, Access code, Request Phrase which we collected from the portal.
// testing environment payfort field values, production values are different
const payfortFields = {
merchant_identifier: 'PQRstuv',
access_code: '123axisCode123',
request_phrase: 'abcd1234$',
};
var deviceId = '';
export default function App() {
Now in SDK token request object, assign initial properties like this.
export default function App() {
const [token, setToken] = useState('');
. . .
const getSDKToken = async () => {
const sdkTokenObj = {
device_id: deviceId,
merchant_identifier: payfortFields.merchant_identifier,
access_code: payfortFields.access_code,
language: 'en',
service_command: 'SDK_TOKEN',
};
}
. . .
}
Now in this object we need to add the signature property value which is an encrypted value of a string pattern. To create that string pattern we need to follow 4 steps.
Step 1, sort the request object property keys in ascending alphabetical order.
const sortedKeys = Object.keys(sdkTokenObj).sort((a, b) =>
a.localeCompare(b)
);
Step 2, concatenate the request object properties as string in ascending order. Property separator null and Key Value separator =
.
let concatenatedString = '';
sortedKeys.forEach((ele) => {
concatenatedString += ele + '=' + sdkTokenObj[ele];
});
At this point, the concatenatedString value will be like this
// concatenatedString = 'access_code=SILgpo7pWbmzuURp2qridevice_id=aAbC123zZfF56700language=enmerchant_identifier=MxvOupuGservice_command=SDK_TOKEN'
Step 3, Add the PASS_PHRASE or REQUEST_PHRASE at the beginning and the end of the concatenated string.
concatenatedString =
payfortFields.request_phrase +
concatenatedString +
payfortFields.request_phrase;
console.log('concatenated string', concatenatedString )
// concatenatedString = 'abcd1234$access_code=SILgpo7pWbmzuURp2qridevice_id=aAbC123zZfF56700language=enmerchant_identifier=MxvOupuGservice_command=SDK_TOKENabcd1234$'
Step 4, now generate hash value from the concatenated string using a method in crypto-js
package
import CryptoJS, { SHA256 } from 'crypto-js'
. . .
const getSDKToken = async () => {
. . .
const hash = SHA256(concatenatedString);
console.log('hash', hash)
After following these 4 steps we prepared the string pattern. Lets encrypt this value.
const sign = hash.toString(CryptoJS.enc.Hex);
console.log('sign', sign )
// sample output
// sign = 94C38AFC7BDAE0114FC8C740EDF12416F22998241CE4B4EA70D5521233A2C882
Now we generated the required encrypted signature value. Lets setup the request object with the signature property.
sdkTokenObj.signature = sign;
The request object for the API call is ready, its time to call the API and get the SDK token. Note, the API url is different for TESTING and PRODUCTION.
import axios from 'axios'
. . .
const getSDKToken = async () => {
. . .
const headers = { 'Content-type': 'application/json' };
// const productionUrl = 'https://paymentservices.payfort.com/FortAPI/paymentApi';
const testUrl = 'https://sbpaymentservices.payfort.com/FortAPI/paymentApi';
const response = await axios.post(testUrl, sdkTokenObj, { headers });
if (response?.data?.sdk_token) {
/**
response object
{
access_code: '***HDZRe****P4$$$$',
device_id: 'e34abc-123-abcdf-742-d987b67957',
language: 'en',
merchant_identifier: 'PQRstuv',
response_code: '22000',
response_message: 'Success',
sdk_token: 'abcd1234AFGHTYUI00bnmghjklpo',
service_command: 'SDK_TOKEN',
signature: '660288c0e0cabcd$5e06c57bb19126e181185291195ad6ef33006191aa741604218',
status: '22',
}
*/
setToken(response.data.sdk_token);
}
Yeah, we have successfully got the SDK token and updated the state. So far all fine? If you missed anything the whole getSDKToken method FYR.
const getSDKToken = async () => {
const sdkTokenObj = {
device_id: deviceId,
language: 'en',
merchant_identifier: payfortFields.merchant_identifier,
access_code: payfortFields.access_code,
service_command: 'SDK_TOKEN',
};
const sortedKeys = Object.keys(sdkTokenObj).sort((a, b) =>
a.localeCompare(b)
);
let concatenatedString = '';
sortedKeys.forEach((ele) => {
concatenatedString += ele + '=' + sdkTokenObj[ele];
});
concatenatedString =
payfortFields.request_phrase +
concatenatedString +
payfortFields.request_phrase;
console.log('concatenated string', concatenatedString);
const hash = SHA256(concatenatedString);
console.log('hash', hash);
const sign = hash.toString(CryptoJS.enc.Hex);
console.log('sign', sign);
sdkTokenObj.signature = sign;
const headers = { 'Content-type': 'application/json' };
// const productionUrl = 'https://paymentservices.payfort.com/FortAPI/paymentApi';
const testUrl = 'https://sbpaymentservices.payfort.com/FortAPI/paymentApi';
const response = await axios.post(testUrl, sdkTokenObj, { headers });
if (response?.data?.sdk_token) {
setToken(response.data.sdk_token);
}
};
Calling this method in useEffect
for the first transaction.
const loadPageData = async () => {
await setupDeviceId();
await getSDKToken();
};
useEffect(() => {
loadPageData();
}, []);
Step 3 - Transaction Object
Form transaction object with the SDK token value and the transaction information.
const paymentObject = {
command: 'PURCHASE',
merchant_reference: 'companyName' + Date.now().toString(),
amount: 100, // use state variable
currency: 'USD',
language: 'en',
customer_email: 'custemail@email.com',
sdk_token: token,
};
Here in this sample we are making a purchase transaction for the amount of $100. You can use a state variable which holds the amount information like cartTotal or totalPrice.
Step 4 - Checkout Component
In the UI part, we are using the payfort checkout component and define the values for the respective properties.
import { getDeviceId, StandardCheckout } from 'rn-amazon-payment-services';
. . .
return (
<View style={styles.container}>
<TouchableOpacity style={styles.btn}>
<Text style={styles.text}>Proceed to Pay</Text>
</TouchableOpacity>
<StandardCheckout
showStandardCheckoutPage={showStandardCheckout}
environment={'TEST'} // TEST or PRODUCTION
requestCode={1}
showLoading={true}
showResponsePage={true}
requestObject={paymentObject}
onSuccess={onSuccess}
onFailure={onFailure}
onCancel={onCancel}
/>
</View>
);
Here showStandardCheckout
state variable will be used to show/hide the payfort payment page.
Step 5 - OnSuccess OnFailure
As we defined in the component, need to write methods for onSuccess and onFailure props.
export default function App() {
const [token, setToken] = useState('');
const [showStandardCheckout, setShowStandardCheckout] = useState(false);
. . .
const onSuccess = (response) => {
console.log('payfort success', response);
/**
success response object
{
amount: '100',
authorization_code: '4567891230',
card_holder_name: 'my cust name',
card_number: '12345******0001',
command: 'PURCHASE',
currency: 'USD',
customer_email: 'custemail@email.com',
customer_ip: '123.456.789.01',
eci: 'ECOMMERCE',
expiry_date: '2505',
fort_id: '16900000098',
language: 'en',
merchant_reference: 'companyName202404158789',
payment_option: 'VISA',
response_code: '14000',
response_message: 'Success',
sdk_token: 'bb39b7a54abcdffghjklpoiuytrewq12',
status: '14',
token_name: 'abcdfghty6a84100112233440377cecfghtyuer',
}
*/
setToken('');
setShowStandardCheckout(false);
};
const onFailure = (response) => {
console.log('payfort failure', response);
setToken('');
setShowStandardCheckout(false);
};
const onCancel = (response) => {
console.log('payfort cancel', response);
setToken('');
setShowStandardCheckout(false);
};
We have to clear the SDK token on each attempt ends.
Step 6 - Show Payfort
After setting up the device id, SDK token, transaction object and checkout component its time to show the payfort payment page. In the onPress
of the button
const openPayfort = async () => {
if (!token) {
await get_sdk_token();
}
setShowStandardCheckout(true);
};
. . .
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => openPayfort()} style={styles.btn}>
<Text style={styles.text}>Proceed to Pay</Text>
</TouchableOpacity>
. . .
Note, We have to generate the SDK token for each and every attempts.
That's It
When we click the ProceedToPay button we will be redirected to payfort payment page.
Yes finally we achieved on successfully integrating the Amazon Payment Service | Payfort into our application.
Full source code available here
Thank you !
Tags: #javascript, #react, #react-native, #android, #ios, #mobile, #payment-gateway, #payfort, #amazon-payfort, programming
Top comments (0)