Key Notes

  • Debit init call is allowed only in the ACTIVE state of the subscription.
  • Cancel/Revoke flows are only allowed after the subscription is ACTIVE.
  • Recurring debit payment will be skipped if cancellation/revoke flow is triggered after notification callback and before the Debit Execute call.
  • Recurring debit payment will succeed if Cancellation/Revoke flow is triggered after the Debit Execute call and before the Debit Execute callback.
  • If Revoke flow is triggered then cancel flow will throw an exception, and vice versa is also true.

ANDROID – Code Snippets

Code Snippet to Get PhonePe App VersionCode

  1. Code Snippet to fetch the PhonePe App version code installed in the user’s device.
public long getPhonePeVersionCode(Context context)
{
    String PHONEPE_PACKAGE_NAME_UAT = "com.phonepe.app.preprod";
    String PHONEPE_PACKAGE_NAME_PRODUCTION = "com.phonepe.app";
    PackageInfo packageInfo = null;
    long phonePeVersionCode = -1L;
    try {
        packageInfo = getPackageManager().getPackageInfo(PHONEPE_PACKAGE_NAME_UAT,PackageManager.GET_ACTIVITIES);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            phonePeVersionCode = packageInfo.getLongVersionCode();
        } else {
            phonePeVersionCode = packageInfo.versionCode;
        }
    } catch (PackageManager.NameNotFoundException e) {
        Log.e(TAG, String.format("failed to get package info for package name = {%s}, exception message = {%s}",
                PHONEPE_PACKAGE_NAME_UAT, e.getMessage()));
    }
    return  phonePeVersionCode;
}
  1. Add the below line to your AndroidManifest.xml file
    Note: If you declare a element in your app’s manifest file, then the app associated with that package name appears in the results of any query to PackageManager that matches a component from that app.
<queries>
    <package android:name="com.phonepe.app" />								// PhonePe Prod
    <package android:name="com.phonepe.app.preprod" />						// PhonePe UAT
  	<package android:name="net.one97.paytm" />								// Paytm
  	<package android:name="in.org.npci.upiapp" />							// BHIM
</queries>

Code Snippet to Check PhonePe App for Mandate

Method to check whether the PhonePe UPI app is installed on the android device and supports Mandate:

 private boolean isUpiRegistered() {
    String phonepePackageName = "com.phonepe.app"; 
    //For PreProd app, "com.phonepe.app.preprod"
  	//For Production app, "com.phonepe.app"
    Uri uri = Uri.parse(String.format("%s://%s", "upi", "mandate"));
    Intent upiUriIntent = new Intent();
    upiUriIntent.setData(uri);
    PackageManager packageManager = getApplication().getPackageManager();
    List < ResolveInfo > resolveInfoList = packageManager.queryIntentActivities(upiUriIntent, PackageManager.MATCH_DEFAULT_ONLY);
    if (resolveInfoList != null) {
        for (ResolveInfo resolveInfo: resolveInfoList) {
            String packageName = resolveInfo.activityInfo.packageName;
            if (packageName != null && !packageName.isEmpty() && phonepePackageName.matches(packageName)) {
                return true;
            }
        }
    }
    return false;
}

Code Snippet to Check Supported UPI Apps for Mandate

Method to get the list of all the UPI apps installed on the android device and supports Mandate:

private ArrayList < String > getInstalledUPIApps() {
    ArrayList < String > upiList = new ArrayList < > ();
    Uri uri = Uri.parse(String.format("%s://%s", "upi", "mandate"));
    Intent upiUriIntent = new Intent();
    upiUriIntent.setData(uri);
    PackageManager packageManager = getApplication().getPackageManager();
    List < ResolveInfo > resolveInfoList = packageManager.queryIntentActivities(upiUriIntent, PackageManager.MATCH_DEFAULT_ONLY);
    if (resolveInfoList != null) {
        for (ResolveInfo resolveInfo: resolveInfoList) {
            upiList.add(resolveInfo.activityInfo.packageName);
        }
    }
    return upiList;
}

E2M Recurring : Code Snippet to invoke the app-specific Intent

Update the APP_PACKAGE** value with the package name of the UPI app selected by the user on the merchant’s checkout page to launch the mandate setup.

val intent = Intent()
intent.action = Intent.ACTION_VIEW
intent.data = Uri.parse(redirectUrl)		//PhonePe Intent redirectUrl from the response.
intent.setPackage(APP_PACKAGE)					//APP_PACKAGE will be the package name of the App selected by the user.

startActivityForResult(intent,PHONEPE_REQUEST_CODE);

iOS – Code Snippets

Code Snippet to Generate “deviceContext”

To find the appSupportedSchema + isPPAppPresent value, the below code snippet has to be used to check it or to generate deviceContext.
Usage: PhonePeContextGenerator(callbackSchema: “demoAppSchema”).getDeviceContext()

class PhonePeContextGenerator {
    private let callbackSchema: String?
     
    init(callbackSchema: String?) {
        self.callbackSchema = callbackSchema
    }
     
    private struct UriSchemeConstants {
        static let uriScheme1 = "ppemerchantsdkv1"
        static let uriScheme2 = "ppemerchantsdkv2"
        static let uriScheme3 = "ppemerchantsdkv3"
        static let hyphenation =  "://"
    }
     
    private func isPhonePeInstalled() -> Bool {
        DispatchQueue.main.sync {
            guard let openUrl1 = URL(string: UriSchemeConstants.uriScheme1 + UriSchemeConstants.hyphenation),
                  let openUrl2 = URL(string: UriSchemeConstants.uriScheme2 + UriSchemeConstants.hyphenation),
                  let openUrl3 = URL(string: UriSchemeConstants.uriScheme3 + UriSchemeConstants.hyphenation) else {
                return false
            }
             
            let appInstalled = UIApplication.shared.canOpenURL(openUrl1) ||
                                UIApplication.shared.canOpenURL(openUrl2) ||
                                UIApplication.shared.canOpenURL(openUrl3)
             
            return appInstalled
        }
    }
     
    private func getAppSupportedSchema() -> [String] {
        var supportedAppSchemas: [String] = []
        DispatchQueue.main.sync {
            [UriSchemeConstants.uriScheme1, UriSchemeConstants.uriScheme2, UriSchemeConstants.uriScheme3].forEach { (scheme) in
                 
                if let openUrl = URL(string: scheme + UriSchemeConstants.hyphenation),
                   UIApplication.shared.canOpenURL(openUrl) {
                    supportedAppSchemas.append(scheme)
                }
            }
        }
        return supportedAppSchemas
    }
     
    func getDeviceContext() -> [String: Any] {
        var context: [String: Any] = [:]
         
        context["appSupportedSchemas"] = getAppSupportedSchema()
        context["isPPAppPresent"] = isPhonePeInstalled()
        context["deviceOS"] = "iOS"
         
        if let schema = callbackSchema {
          context["merchantCallBackScheme"] = schema
        }
         
        return context
    }
}
//Step 1: Create the swift class in the project.
import UIKit

@objc
class PhonePeContextGenerator: NSObject {
    private let callbackSchema: String?
     
    @objc
    init(callbackSchema: String?) {
        self.callbackSchema = callbackSchema
    }
     
    private struct UriSchemeConstants {
        static let uriScheme1 = "ppemerchantsdkv1"
        static let uriScheme2 = "ppemerchantsdkv2"
        static let uriScheme3 = "ppemerchantsdkv3"
        static let hyphenation =  "://"
    }
     
    private func isPhonePeInstalled() -> Bool {
        DispatchQueue.global().sync {
            guard let openUrl1 = URL(string: UriSchemeConstants.uriScheme1 + UriSchemeConstants.hyphenation),
                  let openUrl2 = URL(string: UriSchemeConstants.uriScheme2 + UriSchemeConstants.hyphenation),
                  let openUrl3 = URL(string: UriSchemeConstants.uriScheme3 + UriSchemeConstants.hyphenation) else {
                return false
            }
             
            let appInstalled = UIApplication.shared.canOpenURL(openUrl1) ||
                                UIApplication.shared.canOpenURL(openUrl2) ||
                                UIApplication.shared.canOpenURL(openUrl3)
             
            return appInstalled
        }
    }



     
    private func getAppSupportedSchema() -> [String] {
        var supportedAppSchemas: [String] = []
        DispatchQueue.global().sync {
            [UriSchemeConstants.uriScheme1, UriSchemeConstants.uriScheme2, UriSchemeConstants.uriScheme3].forEach { (scheme) in
                 
                if let openUrl = URL(string: scheme + UriSchemeConstants.hyphenation),
                   UIApplication.shared.canOpenURL(openUrl) {
                    supportedAppSchemas.append(scheme)
                }
            }
        }
        return supportedAppSchemas
    }
  
    @objc
    func getDeviceContext() -> [String: Any] {
        var context: [String: Any] = [:]
         
        context["appSupportedSchemas"] = getAppSupportedSchema()
        context["isPPAppPresent"] = isPhonePeInstalled()
        context["deviceOS"] = "iOS"
         
        if let schema = callbackSchema {
          context["merchantCallBackScheme"] = schema
        }
         
        return context
    }
}


//Step 2: Import the header in the .m file that you want to generate the deviceContext
#import <YourProjectName-Swift.h>

  
//Step 3: Initialize the class and call the method to get the device context.
[[[PhonePeContextGenerator alloc] initWithCallbackSchema:@"demoAppSchema"] getDeviceContext];

Code Snippet to Check if PhonePe App is Present

isPhonePeInstalled() will return True if the PhonePe App is installed in the user’s device.

private struct UriSchemeConstants {
  static let uriScheme1 = "ppemerchantsdkv1"
  static let uriScheme2 = "ppemerchantsdkv2"
  static let uriScheme3 = "ppemerchantsdkv3"
  static let hyphenation =  "://"
}

private func isPhonePeInstalled() -> Bool {
  DispatchQueue.main.sync {
    guard let openUrl1 = URL(string: UriSchemeConstants.uriScheme1 + UriSchemeConstants.hyphenation),
    let openUrl2 = URL(string: UriSchemeConstants.uriScheme2 + UriSchemeConstants.hyphenation),
    let openUrl3 = URL(string: UriSchemeConstants.uriScheme3 + UriSchemeConstants.hyphenation) else {
      return false
    }

    let appInstalled = UIApplication.shared.canOpenURL(openUrl1) ||
    UIApplication.shared.canOpenURL(openUrl2) ||
    UIApplication.shared.canOpenURL(openUrl3)

    return appInstalled
  }
}
//Step 1: Create the swift class in the project.
import UIKit
@objc
class PhonePeAppCheck: NSObject {
  @objc
  func isPhonePeInstalled() -> Bool {
        DispatchQueue.global().sync {
            guard let openUrl1 = URL(string: UriSchemeConstants.uriScheme1 + UriSchemeConstants.hyphenation),
                  let openUrl2 = URL(string: UriSchemeConstants.uriScheme2 + UriSchemeConstants.hyphenation),
                  let openUrl3 = URL(string: UriSchemeConstants.uriScheme3 + UriSchemeConstants.hyphenation) else {
                return false
            }
             
            let appInstalled = UIApplication.shared.canOpenURL(openUrl1) ||
                                UIApplication.shared.canOpenURL(openUrl2) ||
                                UIApplication.shared.canOpenURL(openUrl3)
             
            return appInstalled
        }
    }

}
//Step 2: Import the header in the .m file that you want to check for PhonePe app present.
#import <YourProjectName-Swift.h>

  
//Step 3: Initialize the class and call the method to get whether the app is installed in the device or not.
[[PhonePeAppCheck alloc] isPhonePeInstalled];

Code Snippet to Check if GPay App is Present

private struct UriSchemeConstants {
  static let uriScheme1 = "gpay"
  static let hyphenation =  "://"
}

func isGPayInstalled() -> Bool {
  DispatchQueue.main.sync {
    guard let openUrl1 = URL(string: UriSchemeConstants.uriScheme1 + UriSchemeConstants.hyphenation) else {
      return false
    }

    let appInstalled = UIApplication.shared.canOpenURL(openUrl1)
    return appInstalled
  }
}