SDK Integration
Step 1: Android SDK setup
Install PhonePe SDK using Android Studio. To add the SDK to the android app please follow the steps given below:
- 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"
}
}
}
- Add the below line to the 'dependencies' section of your app build.gradle.
implementation 'phonepe.intentsdk.android.release:IntentSDK:1.6.5'
- Add meta-data in <application> tag of AndroidManifest.xml file.
<!-- Keep it false in production environment-->
<meta-data
android:name="com.phonepe.android.sdk.Debuggable"
android:value="true"/>
<!-- Keep it false in production environment-->
<meta-data
android:name="com.phonepe.android.sdk.isUAT"
android:value="true"/>
<!-- Get the App Id from PhonePe-->
<meta-data
android:name="com.phonepe.android.sdk.AppId"
android:value="<your app id given by PhonePe>"/>
Step 2: SDK Initialization
- Initialize the PhonePe SDK in an Activity that gets launched before a user selects the PhonePe option on your checkout screen.
Note: Don't initialize in the Application class of your project.
PhonePe.init(this)
- Use isUPIAccountRegistered API before displaying the PhonePe icon. This API checks if the user has the PhonePe app installed as well as if the app is in a state to initiate UPI payments.
try {
PhonePe.isUPIAccountRegistered { shouldShow ->
Log.d(TAG, "$shouldShow")
}
} catch (e: PhonePeInitException) {
Log.d(TAG, "make sure you call PhonePe init before calling this")
}
try {
PhonePe.isUPIAccountRegistered(new ShowPhonePeCallback() {
@Override
public void onResponse(boolean show) {
Log.d(TAG, "onResponse: "+show);
Toast.makeText(MainActivity.this, show? "YES":"NO", Toast.LENGTH_SHORT).show();
}
});
} catch (PhonePeInitException e) {
e.printStackTrace();
}
Step 3: Server-Side Setup
- Use the below PhonePe debit API endPoint value for the debit request.
val apiEndPoint = "/v4/debit"
String apiEndPoint = "/v4/debit";
- Construct the request body and encode it using Base64.
val data: HashMap<String, Any?> = hashMapOf(
"merchantId" to "UATMERCHANT", //String. Mandatory
"transactionId" to "TX123456789", //String. Mandatory - length should be less than 38 characters
"amount" to 100L, //Long. Mandatory
"merchantOrderId" to "OD1234", //String. Mandatory - length should be less than 48 characters
"message" to "Payment for order placed 001234", //String Optional
"mobileNumber" to "9xxxxxxxxx" //String. Optional
// Put more info as intimated. Nesting is allowed
)
val base64Body: String = Base64.encodeToString(Gson().toJson(data), Base64.DEFAULT)
HashMap<String, Object> data = new HashMap<>();
data.put("merchantId", “UATMERCHANT”); //String. Mandatory
data.put("transactionId", “TX123456789”); //String. Mandatory.
data.put("amount", 100); //Long. Mandatory
data.put("merchantOrderId", “OD1234”); //String. Mandatory
data.put("message", “Payment for order placed 001234”); //String. Optional
data.put("mobileNumber", “9xxxxxxxxx”); //String. Optional
// transactionId length should be less than 38 characters.
// merchantOrderId length should be less than 48 characters.
// Put more info as intimated. Nesting is allowed
String base64Body = Base64(new GSON().toJson(data));
- Select one of the salt keys and saltIndex. Refer link link for salt & index credentials. Use these values to construct the checksum as follows:
val checksum: String = sha256(base64Body + apiEndPoint + salt) + "###" + saltIndex
String checksum = sha256(base64Body + apiEndPoint + salt) + ### + saltIndex;
- Construct additional headers for S2S callback.
val headers = hashMapOf(
"X-CALLBACK-URL" to "https://www.demoMerchant.com",
"X-CALL-MODE" to "POST"
)
Map<String, String> headers = new HashMap();
headers.put("X-CALLBACK-URL","https://www.demoMerchant.com"); // Merchant server URL
headers.put("X-CALL-MODE","POST");
- Pass on these values to your Android app in an API.
Step 4: Payment using the SDK
- Use the TransactionRequestBuilder to construct TransactionRequest from the data obtained from your server as mentioned in Step-3.
val debitRequest: TransactionRequest = TransactionRequestBuilder()
.setData(base64Body)
.setChecksum(checksum)
.setUrl(apiEndPoint)
.setHeaders(headers)
.build()
TransactionRequest debitRequest = new TransactionRequestBuilder()
.setData(base64Body)
.setChecksum(checksum)
.setUrl(apiEndPoint)
.setHeaders(headers)
.build();
- Define an intent request code for initiating a PhonePe transaction.
const val DEBIT_REQUEST_CODE = 777
private static int DEBIT_REQUEST_CODE = 777;
- Initiate payment using the PhonePe app.
startActivityForResult(PhonePe.getTransactionIntent(debitRequest), DEBIT_REQUEST_CODE)
//For Intent SDK call below function
try {
startActivityForResult(PhonePe.getTransactionIntent(
/* Context */ this, debitRequest),DEBIT_REQUEST_CODE);
} catch(PhonePeInitException e){
}
- Override onActivityResult to receive a callback once the PhonePe app exits.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == DEBIT_REQUEST_CODE) {
/*This callback indicates only about completion of UI flow.
Inform your server to make the transaction
status call to get the status. Update your app with the
success/failure status.*/
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == DEBIT_REQUEST_CODE) {
/*This callback indicates only about completion of UI flow.
Inform your server to make the transaction
status call to get the status. Update your app with the
success/failure status.*/
}
}
Step 5: Handling callback from PhonePe
In order to receive server to server callbacks from PhonePe server we recommend merchants to pass X-CALLBACK-URL and X-CALL-MODE in the headers of the Accept Payment API. Before considering this response you need to validate the checksum and amount parameter. This will provide the payment status response as success/failure only. Based on payment status response, handling can be built at merchants end
- After the transaction is complete:
Once the transaction is complete, you will get a Base64 Encoded JSON response along with the headers with checksum value. Find the below code snippet:
{
"response":"eyJzdWNjZXNzIjp0cnVlLCJjb2RlIjoiUEFZTUVOVF9TVUNDRVNTIiwibWVzc2FnZSI6IllvdXIgcGF5bWVudCBpcyBzdWNjZXNzZnVsLiIsImRhdGEiOnsidHJhbnNhY3Rpb25JZCI6IlRYMzIzMjE4NDk2NDQyMzQiLCJtZXJjaGFudElkIjoiTTIzMDYxNjA0ODMyMjA2NzU1NzkxNDAiLCJwcm92aWRlclJlZmVyZW5jZUlkIjoiUDE4MDYxNTEzMjMwOTM5MDA1NTQ5NTciLCJhbW91bnQiOjEwMDAsInBheW1lbnRTdGF0ZSI6IkNPTVBMRVRFRCIsInBheVJlc3BvbnNlQ29kZSI6IlNVQ0NFU1MiLCJwYXltZW50TW9kZXMiOlt7Im1vZGUiOiJBQ0NPVU5UIiwiYW1vdW50IjoxMDAwLCJ1dHIiOiI4MTY2MjY1MjE2MTYifV0sInRyYW5zYWN0aW9uQ29udGV4dCI6e319fQ"
}
{
"headers": {
"x-verify":"2abaa82a4810c57dcd6aa52680dd772173b1e40770afe028131f31ddbe5487a8###1"
}
}
- To calculate the checksum in the server to server callback response. Find the code snippet
Content-Type application/json
X-VERIFY SHA256(response + salt key) + ### + salt index
- To validate the amount, the merchant needs to compare the amount parameter received in the server to server callback response with the amount parameter passed in the Accept Payment API
- You need to validate the X-verify. Once both checksum and the amount parameters are validated, order can be fulfilled based on the response. Note that completion of a transaction does not imply that payment is successful. Payment can be in a successful or failed state which needs to be derived from JSON response. Here is the code snippet:
{
"success":true,
"code":"PAYMENT_SUCCESS",
"message":"Your payment is successful.",
"data":{
"transactionId":"TX32321849644234",
"merchantId":"UATMERCHANT",
"providerReferenceId":"P1806151323093900554957",
"amount":1000,
"paymentState":"COMPLETED",
"payResponseCode":"SUCCESS",
"paymentModes":[
{
"mode":"ACCOUNT",
"amount":1000,
"utr":"816626521616"
}
],
"transactionContext":{
}
}
}
- When the back button is pressed by customer, SDK will return a UI callback to the App.You should take action as mentioned below
UI callbacks | Server to Server callbacks | Check Transaction Status API | Action |
---|---|---|---|
RESULT_OK | Success / Failure | Success / Failure | Take the decision based on response. |
RESULT_CANCELLED | Success / Failure | Success / Failure | Take the decision based on response. |
RESULT_CANCELLED | X | Payment Pending | Temporarily Mark transaction as payment failure. |
RESULT_CANCELLED | X | Internal Server Error | Call Check Transaction Status API - Take decisions based on the response received. |
Step 6: Validating the X-verify
Once the response is received, you need to validate the X-verify in order to ensure that the response received is not tampered with. In order to validate the X-verify, please follow the below steps:
- Generate the checksum by using a SHA256 of the encoded body received in the response, salt key and salt index
- The salt we would use will be appended with ### to the checksum value in the checksum attribute. Upon receiving this payload, you need to look at the salt_index in the checksum attribute after ### delimiter and use the appropriate salt_index to be able to calculate checksum at their end for the said payload. If it doesn't match, then you need to abort the request.
- Salts are already pre-shared with you at the time of onboarding
- If the value of any parameter is null, it will not be included in the calculation of the checksum.
Updated 5 months ago