Ionic SDK Integration
The steps to integrate the PhonePe Payment Gateway with the Ionic platform. We provide a plugin/bridge to integrate our SDK.
We can implement with the below 2 steps:
- Add the native configuration (Android/iOS)
- Add the Plugin to the Ionic project
Quick Links
- Add the native configuration (Android/iOS)
- Android - Add the native configuration in the Android Studio project
- iOS - Add the native configuration in the Xcode project
- Add the Plugin in your Ionic Project/App
- Parameters
- Server Side Implementation
- Ionic Sample App
Add the native configuration (Android/iOS)
Android
Add the native configuration in the Android Studio project
- Add the below code to 'repositories' section of your project level build.gradle file
// Top-level build file where you can add configuration options common to all sub-projects/modules.
allprojects {
repositories {
google()
maven {
url "https://phonepe.mycloudrepo.io/public/repositories/phonepe-intentsdk-android"
}
}
}
iOS
Add the native configuration in the Xcode project
1. In your Info.plist under the iOS Xcode project, create or append a new Array type node LSApplicationQueriesSchemes to append the following values:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>ppemerchantsdkv1</string>
<string>ppemerchantsdkv2</string>
<string>ppemerchantsdkv3</string>
<string>paytmmp</string>
<string>gpay</string>
</array>

2. Create a URLType for your app (Deeplink), if not already present.
For example, we have used: iOSIntentIntegration. (You can create your own identifier for your app)

URLScheme should match the below conditions
- Only Alphabets (lower and upper case) and numbers are allowed.
- We can allow special characters only like dot and Hyphen
- The name should always start with alphabets.
The schema should be correct to redirect the app otherwise it will not redirect back to the merchant app.
Add the Plugin in your Ionic Project/App
- Add the dependency in your project
npm i 'https://phonepe.mycloudrepo.io/public/repositories/phonepe-mobile-capacitor-sdk/phonepe-payment-capacitor.tgz'
- import the package in your code
import { PhonePePaymentPlugin } from 'phonepe-payment-capacitor'
- Call the PhonePe methods as below
Init Method (Initialisation of SDK)
Initialize the init method before starting the transaction.
Note
appId is only required for the PRODUCTION environment. For UAT environments, you can pass empty String as well.
/**
* This method is used to initiate PhonePe Payment sdk.
* Provide all the information as requested by the method signature.
* Params:
* - environment: This signified the environment required for the payment sdk
* possible values: UAT, UAT_SIM, PRODUCTION
* if any unknown value is provided, PRODUCTION will be considered as default.
* - merchantId: The merchant id provided by PhonePe at the time of onboarding.
* - appId: The appId provided by PhonePe at the time of onboarding.
* - enableLogging: If you want to enabled / visualize sdk log
* - enabled = true
* - disable = false
*
* Return: Will be returning a dictionary / hashMap
* {
* status: boolean, // boolean value to provide the callback of the init method
* }
*/
init(options: {
environment: string,
merchantId: string,
appId: string,
enableLogging: boolean | false
}): Promise<Record<string, boolean>>;
Example:
PhonePePaymentPlugin.init({
environment: environment,
merchantId: merchantId,
appId: appId,
enableLogging: false
}).then(result => {
console.log('VS: '+ JSON.stringify(result['status']));
setMessage(JSON.stringify(result['status']));
}).catch(error => {
console.log('VS: error:'+ error.message);
})
To get App Id - Refer here
Without calling PhonePePaymentPlugin.init() method, getPackageSignatureForAndroid() method can't be called to fetch the Signature as it will throw an error as the SDK is not initialized.
Solution: Before calling the getPackageSignatureForAndroid() method, the merchant has to initialize the SDK using PhonePePaymentPlugin.init(environmentValue, appId, merchantId, enableLogging). For initializing, merchant can pass the dummy value in the appId for the first time and later once the App ID is shared by the PhonePe Team, it should be replaced for the transactions to work smoothly.
Pre-Requisite
After the SDK is initialized, for Custom UPI Intent flow,
- Merchants should call the getInstalledUpiAppsForAndroid() to fetch the list of UPI apps supported in the merchant app.
- Display the custom UI containing the list of UPI apps obtained from the previous step on the checkout page under the UPI section.
- When the user selects any of the UPI apps to initiate the payment, then you must pass the following parameters in the PAY API request payload based on the app selected by the user and the device platform.
- deviceContext.deviceOS - Possible Values: ANDROID, IOS
- paymentInstrument.type - "UPI_INTENT"
- paymentInstrument.target app - The package name of the UPI app selected by the user to initiate the payment.
Example (Android): For PhonePe App - "com.phonepe.app", Gpay App - "com.google.android.apps.nbu.paisa.user", etc.
Example (iOS): For PhonePe App - "PHONEPE", Gpay App - "GPAY".- For UAT testing, kindly install the PhonePe Test app.
Start The PG transaction
/**
* This method is used to initiate PhonePe B2B PG Flow.
* Provide all the information as requested by the method signature.
* Params:
* - body : The request body for the transaction as per the developer docs.
* Make sure the request body is base64encoded
* - checkSum: checksum for the particular transaction as per the developer docs.
* - apiEndPoint: The API endpoint for the PG transaction.
* - headers: Headers as per the developer doc for PG flow
* - packageName: @Optional(for iOS) in case of android if intent url is expected for specific app.
* - callBackURL: Your custom URL Schemes, as per the developer docs.
* Return: Will be returning a dictionary / hashMap
* {
* status: String, // string value to provide the status of the transaction
* // possible values: SUCCESS, FAILURE, INTERUPTED
* error: String // if any error occurs
* }
*/
startPGTransaction(options: {
body: string,
checksum: string,
apiEndPoint: string,
headers: any,
packageName: string | null,
callBackURL: string | null
}):Promise<Record<string, string>>;
Example:
PhonePePaymentPlugin.startPGTransaction({
body: base64,
checksum: checksum,
apiEndPoint: '/pg/v1/pay', // api end point
headers: {'Content-Type': 'application/json'},
packageName: '', // Package name for android apps.
callBackURL: 'ionicDemoApp' // Your iOS URL Schema
}).then(result => {
console.log('VS: '+ JSON.stringify(result['status']));
setMessage(JSON.stringify(result['status']));
}).catch(error => {
console.log('VS: error:'+ error.message);
})
Helper Methods (For Android and iOS)
Check if PhonePeApp is Installed
/**
* This method is called to check the particular app is installed or not
* Return: Will be returning a dictionary / hashMap
* {
* status: Boolean // true -> App Installed , false -> App Not Installed
* }
*/
isPhonePeInstalled(): Promise<Record<string, boolean>>;
Example:
PhonePePaymentPlugin.isPhonePeInstalled().then(result => {
console.log('VS: '+ JSON.stringify(result['status']));
setMessage(JSON.stringify(result['status']));
}).catch(error => {
console.log('VS: error:'+ error.message);
})
Check if Gpay is Installed
/**
* This method is called to check the particular app is installed or not
* Return: Will be returning a dictionary / hashMap
* {
* status: Boolean // true -> App Installed , false -> App Not Installed
* }
*/
isGpayInstalled(): Promise<Record<string, boolean>>;
Example:
PhonePePaymentPlugin.isGpayInstalled().then(a => {
console.log('VS: '+ JSON.stringify(result['status']));
setMessage(JSON.stringify(result['status']));
}).catch(error => {
console.log('VS: error:'+ error.message);
})
Check if Paytm is Installed
/**
* This method is called to check the particular app is installed or not
* Return: Will be returning a dictionary / hashMap
* {
* status: Boolean // true -> App Installed , false -> App Not Installed
* }
*/
isPaytmInstalled(): Promise<Record<string, boolean>>;
Example:
PhonePePaymentPlugin.isPaytmInstalled().then(a => {
console.log('VS: '+ JSON.stringify(result['status']));
setMessage(JSON.stringify(result['status']));
}).catch(error => {
console.log('VS: error:'+ error.message);
})
Helper Methods (Only Android Specific)
Get Package Signature for Android
/**
* This method is called to get package signature while creation of AppId in @Android only.
* Return: String
* Non empty string -> app package signature
* NOTE :- In iOS, it will send null.
*/
getPackageSignatureForAndroid(): Promise<Record<string, string>>;
Example:
if (Capacitor.getPlatform() === 'android') {
PhonePePaymentPlugin.getPackageSignatureForAndroid().then(result => {
console.log('VS: '+ JSON.stringify(result['status']));
setMessage(JSON.stringify(result['status']));
}).catch(error => {
setMessage("error:" + error.message);
})
}
};
For Production, share the package signature of the release build that will be published to the Playstore to generate the App ID.
For Production, do not share the package signature from the Debug or Test Build which won't work.
Get UPI Apps for Android
/**
* This method is called to get list of upi apps in @Android only.
* Return: String
* JSON String -> List of UPI App with packageName, applicationName & versionCode
* NOTE :- In iOS, it will throw os error at runtime.
*/
getUpiAppsForAndroid(): Promise<Record<string, string>>;
Example:
if (Capacitor.getPlatform() === 'android') {
PhonePePaymentPlugin.getUpiAppsForAndroid().then(result => {
console.log('VS: '+ JSON.stringify(result['status']));
setMessage(JSON.stringify(JSON.parse(result['status'])));
}).catch(error => {
setMessage("error:" + error.message);
})
}
Show your custom UI containing the list of apps obtained from the method getInstalledUpiAppsForAndroid(). Make Sure packageName is accessible when the user selects any of the UPI Applications.

Parameters
Keys | Data Type | Possible Values |
---|---|---|
environment | String | 1. UAT 2. UAT_SIM 3. PRODUCTION |
merchantId | String | Add the Merchant ID provided by the Integration Team |
appId | String | Add the PhonePe App Provided by the Integration Team. Details to be shared with the integration team to generate the AppId: iOS: Share the Apple Team ID Android: Share the Android signature. Refer |
enableLogs | Bool | Show the logs in the console in the SDK 1. true 2. false |
body | String | base64String |
callBackURL | String | [Only for iOS]Your App URL Scheme - To return the UI control back to the merchant app. Refer to this Link |
checksum | String | Checksum for the particular transaction. Refer here |
headers | Map | Headers if required as per the Dev Docs. |
apiEndPoint | String | The API endpoint for the PG transaction. Refer here |
packageName | String | [Only for Android]The Package name of the UPI app selected by the user. |
Server Side Implementation
Step 1. Save the below-assigned value on your server
String apiEndPoint = "/pg/v1/pay";
Step 2. Construct the request body and encode it in Base 64 at your server as per the platform (Android/iOS):
For PG Pay API (Standard Checkout), refer to this Link.
For PG Pay API (Custom Checkout - UPI Open Intent), refer to this Link.
For PG Pay API (Custom Checkout - Other Instruments), refer to this Link.
Android
{
"merchantId": "MERCHANTUAT",
"merchantTransactionId": "transaction_123",
"merchantUserId": "90223250",
"amount": 1000,
"mobileNumber": "9999999999",
"callbackUrl": "https://webhook.site/callback-url",
"paymentInstrument": {
"type": "UPI_INTENT",
"targetApp": "com.phonepe.app"
},
"deviceContext": {
"deviceOS": "ANDROID"
}
}
{
"merchantId": "MERCHANTUAT",
"merchantTransactionId": "MT7850590068188104",
"merchantUserId": "MUID123",
"amount": 10000,
"callbackUrl": "https://webhook.site/callback-url",
"mobileNumber": "9999999999",
"paymentInstrument": {
"type": "PAY_PAGE"
}
}
Convert the JSON Payload to Base64 Encoded Payload
The above JSON request payload should be converted to the Base64 Encoded Payload and then the request should be sent in the below format.
{
"request": "ewogICJtZXJjaGFudElkIjogIk1FUkNIQU5UVUFUIiwKICAibWVyY2hhbnRUcmFuc2FjdGlvbklkIjogInRyYW5zYWN0aW9uXzEyMyIsCiAgIm1lcmNoYW50VXNlcklkIjogIjkwMjIzMjUwIiwKICAiYW1vdW50IjogMTAwMCwKICAibW9iaWxlTnVtYmVyIjogIjk5OTk5OTk5OTkiLAogICJjYWxsYmFja1VybCI6ICJodHRwczovL3dlYmhvb2suc2l0ZS9jYWxsYmFjay11cmwiLAogICJwYXltZW50SW5zdHJ1bWVudCI6IHsKICAgICJ0eXBlIjogIlVQSV9JTlRFTlQiLAogICAgInRhcmdldEFwcCI6ICJjb20ucGhvbmVwZS5hcHAiCiAgfSwKICAiZGV2aWNlQ29udGV4dCI6IHsKICAgICJkZXZpY2VPUyI6ICJBTkRST0lEIgogIH0KfQ=="
}
{
"request": "ewogICJtZXJjaGFudElkIjogIk1FUkNIQU5UVUFUIiwKICAibWVyY2hhbnRUcmFuc2FjdGlvbklkIjogIk1UNzg1MDU5MDA2ODE4ODEwNCIsCiAgIm1lcmNoYW50VXNlcklkIjogIk1VSUQxMjMiLAogICJhbW91bnQiOiAxMDAwMCwKICAicmVkaXJlY3RVcmwiOiAiaHR0cHM6Ly93ZWJob29rLnNpdGUvcmVkaXJlY3QtdXJsIiwKICAicmVkaXJlY3RNb2RlIjogIlJFRElSRUNUIiwKICAiY2FsbGJhY2tVcmwiOiAiaHR0cHM6Ly93ZWJob29rLnNpdGUvY2FsbGJhY2stdXJsIiwKICAibW9iaWxlTnVtYmVyIjogIjk5OTk5OTk5OTkiLAogICJwYXltZW50SW5zdHJ1bWVudCI6IHsKICAgICJ0eXBlIjogIlBBWV9QQUdFIgogIH0KfQ=="
}
iOS
{
"merchantId": "MERCHANTUAT",
"merchantTransactionId": "MT7850590068188104",
"merchantUserId": "MU933037302229373",
"amount": 10000,
"callbackUrl": "https://webhook.site/callback-url",
"mobileNumber": "9999999999",
"deviceContext": {
"deviceOS": "IOS"
},
"paymentInstrument": {
"type": "UPI_INTENT",
"targetApp": "PHONEPE"
}
}
{
"merchantId": "MERCHANTUAT",
"merchantTransactionId": "MT7850590068188104",
"merchantUserId": "MU933037302229373",
"amount": 10000,
"callbackUrl": "https://webhook.site/callback-url",
"mobileNumber": "9999999999",
"deviceContext": {
"deviceOS": "IOS"
},
"paymentInstrument": {
"type": "UPI_INTENT",
"targetApp": "GPAY"
}
}
{
"merchantId": "MERCHANTUAT",
"merchantTransactionId": "MT7850590068188104",
"merchantUserId": "MU933037302229373",
"amount": 10000,
"callbackUrl": "https://webhook.site/callback-url",
"mobileNumber": "9999999999",
"deviceContext": {
"deviceOS": "IOS"
},
"paymentInstrument": {
"type": "UPI_INTENT",
"targetApp": "PAYTM"
}
}
{
"merchantId": "MERCHANTUAT",
"merchantTransactionId": "MT7850590068188104",
"merchantUserId": "MUID123",
"amount": 10000,
"redirectUrl": "https://webhook.site/redirect-url",
"redirectMode": "REDIRECT",
"callbackUrl": "https://webhook.site/callback-url",
"mobileNumber": "9999999999",
"paymentInstrument": {
"type": "PAY_PAGE"
}
}
Convert the JSON Payload to Base64 Encoded Payload
The above JSON request payload should be converted to the Base64 Encoded Payload and then the request should be sent in the below format.
{
"request": "ewogICJtZXJjaGFudElkIjogIk1FUkNIQU5UVUFUIiwKIAkibWVyY2hhbnRUcmFuc2FjdGlvbklkIjogIk1UNzg1MDU5MDA2ODE4ODEwNCIsCiAgIm1lcmNoYW50VXNlcklkIjogIk1VOTMzMDM3MzAyMjI5MzczIiwKICAiYW1vdW50IjogMTAwMDAsCiAgImNhbGxiYWNrVXJsIjogImh0dHBzOi8vd2ViaG9vay5zaXRlL2NhbGxiYWNrLXVybCIsCiAgIm1vYmlsZU51bWJlciI6ICI5OTk5OTk5OTk5IiwKICAiZGV2aWNlQ29udGV4dCI6IHsKICAgICJkZXZpY2VPUyI6ICJJT1MiCiAgfSwKICAicGF5bWVudEluc3RydW1lbnQiOiB7CiAgICAidHlwZSI6ICJVUElfSU5URU5UIiwKICAgICJ0YXJnZXRBcHAiOiAiUEhPTkVQRSIKICB9Cn0="
}
{
"request": "ewogICJtZXJjaGFudElkIjogIk1FUkNIQU5UVUFUIiwKICAibWVyY2hhbnRUcmFuc2FjdGlvbklkIjogIk1UNzg1MDU5MDA2ODE4ODEwNCIsCiAgIm1lcmNoYW50VXNlcklkIjogIk1VOTMzMDM3MzAyMjI5MzczIiwKICAiYW1vdW50IjogMTAwMDAsCiAgImNhbGxiYWNrVXJsIjogImh0dHBzOi8vd2ViaG9vay5zaXRlL2NhbGxiYWNrLXVybCIsCiAgIm1vYmlsZU51bWJlciI6ICI5OTk5OTk5OTk5IiwKICAiZGV2aWNlQ29udGV4dCI6IHsKICAgICJkZXZpY2VPUyI6ICJJT1MiCiAgfSwKICAicGF5bWVudEluc3RydW1lbnQiOiB7CiAgICAidHlwZSI6ICJVUElfSU5URU5UIiwKICAgICJ0YXJnZXRBcHAiOiAiR1BBWSIKICB9Cn0="
}
{
"request": "ewogICJtZXJjaGFudElkIjogIk1FUkNIQU5UVUFUIiwKICAibWVyY2hhbnRUcmFuc2FjdGlvbklkIjogIk1UNzg1MDU5MDA2ODE4ODEwNCIsCiAgIm1lcmNoYW50VXNlcklkIjogIk1VOTMzMDM3MzAyMjI5MzczIiwKICAiYW1vdW50IjogMTAwMDAsCiAgImNhbGxiYWNrVXJsIjogImh0dHBzOi8vd2ViaG9vay5zaXRlL2NhbGxiYWNrLXVybCIsCiAgIm1vYmlsZU51bWJlciI6ICI5OTk5OTk5OTk5IiwKICAiZGV2aWNlQ29udGV4dCI6IHsKICAgICJkZXZpY2VPUyI6ICJJT1MiCiAgfSwKICAicGF5bWVudEluc3RydW1lbnQiOiB7CiAgICAidHlwZSI6ICJVUElfSU5URU5UIiwKICAgICJ0YXJnZXRBcHAiOiAiUEFZVE0iCiAgfQp9"
}
{
"request": "ewogICJtZXJjaGFudElkIjogIk1FUkNIQU5UVUFUIiwKICAibWVyY2hhbnRUcmFuc2FjdGlvbklkIjogIk1UNzg1MDU5MDA2ODE4ODEwNCIsCiAgIm1lcmNoYW50VXNlcklkIjogIk1VSUQxMjMiLAogICJhbW91bnQiOiAxMDAwMCwKICAicmVkaXJlY3RVcmwiOiAiaHR0cHM6Ly93ZWJob29rLnNpdGUvcmVkaXJlY3QtdXJsIiwKICAicmVkaXJlY3RNb2RlIjogIlJFRElSRUNUIiwKICAiY2FsbGJhY2tVcmwiOiAiaHR0cHM6Ly93ZWJob29rLnNpdGUvY2FsbGJhY2stdXJsIiwKICAibW9iaWxlTnVtYmVyIjogIjk5OTk5OTk5OTkiLAogICJwYXltZW50SW5zdHJ1bWVudCI6IHsKICAgICJ0eXBlIjogIlBBWV9QQUdFIgogIH0KfQ=="
}
Step 3. Checksum Calculation
Select one of the salts shared with you and note its index. Construct the X-verify at your server as follows:
String checksum = sha256(base64Body + apiEndPoint + salt) + ### + saltIndex;
Step 4. Check the payment status
Once the payment is completed, please call the Check Transaction Status API to validate the response received via the App. You can call the Check Transaction Status at regular intervals to fetch the response from the PhonePe server in case a response is not received in the application even after 10 minutes of initiating the application.
Step 5. Handling Payment Status
The payment status can be Successful, Failed, Pending or any of the codes. For Pending, you should retry until the status changes to Successful or Failed.
Ionic Sample App
Refer to the Sample App to test the Plugin and use in your Ionic platform - Link
Updated 8 days ago