iOS PG SDKLess Integration

Objective

SDKLess PG UPI Intent request feature for iOS.

Steps to Integrate SDKLess Solution

To support SDKLess integration, deviceContext has to be added to the request body of the pg/v1/pay API call.

Sample Request for PG UPI Open Intent

{
  "merchantId": "MERCHANTUAT",
  "merchantTransactionId": "MT7850590068188104",
  "merchantUserId": "MU933037302229373",
  "amount": 10000,
  "callbackUrl": "https://webhook.site/callback-url",
  "mobileNumber": "9999999999",
  "deviceContext": {
    "deviceOS": "iOS",
        "isPPAppPresent": true,
        "merchantCallBackScheme": "iOSIntentIntegration",
        "appSupportedSchemas": [
        "ppemerchantsdkv1"
        ]
  },
  "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",
        "merchantCallBackScheme": "iOSIntentIntegration",
  },
  "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",
        "merchantCallBackScheme": "iOSIntentIntegration",
  },
  "paymentInstrument": {
    "type": "UPI_INTENT",
    "targetApp": "PAYTM"
  }
}

🚧

Redirection after Payment Completion (For PhonePe App )

The merchantCallBackScheme can be passed only for the PhonePe App ("openIntentWithApp": "PHONEPE") that helps to open the merchant app after the completion of the Payment.

❗️

Redirection after Payment Completion (Other UPI Apps)

For GPay and Paytm, the redirection will be manual after the completion of the payment.

{ 
    "request": "ewogICJtZXJjaGFudElkIjogIk1FUkNIQU5UVUFUIiwKICAibWVyY2hhbnRUcmFuc2FjdGlvbklkIjogIk1UNzg1MDU5MDA2ODE4ODEwNCIsCiAgIm1lcmNoYW50VXNlcklkIjogIk1VOTMzMDM3MzAyMjI5MzczIiwKICAiYW1vdW50IjogMTAwMDAsCiAgImNhbGxiYWNrVXJsIjogImh0dHBzOi8vd2ViaG9vay5zaXRlL2NhbGxiYWNrLXVybCIsCiAgIm1vYmlsZU51bWJlciI6ICI5OTk5OTk5OTk5IiwKICAiZGV2aWNlQ29udGV4dCI6IHsKICAgICJkZXZpY2VPUyI6ICJpT1MiLAoJCSJpc1BQQXBwUHJlc2VudCI6IHRydWUsCgkJIm1lcmNoYW50Q2FsbEJhY2tTY2hlbWUiOiAiaU9TSW50ZW50SW50ZWdyYXRpb24iLAoJCSJhcHBTdXBwb3J0ZWRTY2hlbWFzIjogWwoJCSJwcGVtZXJjaGFudHNka3YxIgoJCV0KICB9LAogICJwYXltZW50SW5zdHJ1bWVudCI6IHsKICAgICJ0eXBlIjogIlVQSV9JTlRFTlQiLAogICAgInRhcmdldEFwcCI6ICJQSE9ORVBFIgogIH0KfQ=="
}
{ 
    "request": "ewogICJtZXJjaGFudElkIjogIk1FUkNIQU5UVUFUIiwKICAibWVyY2hhbnRUcmFuc2FjdGlvbklkIjogIk1UNzg1MDU5MDA2ODE4ODEwNCIsCiAgIm1lcmNoYW50VXNlcklkIjogIk1VOTMzMDM3MzAyMjI5MzczIiwKICAiYW1vdW50IjogMTAwMDAsCiAgImNhbGxiYWNrVXJsIjogImh0dHBzOi8vd2ViaG9vay5zaXRlL2NhbGxiYWNrLXVybCIsCiAgIm1vYmlsZU51bWJlciI6ICI5OTk5OTk5OTk5IiwKICAiZGV2aWNlQ29udGV4dCI6IHsKICAgICJkZXZpY2VPUyI6ICJpT1MiLAogICAgIm1lcmNoYW50Q2FsbEJhY2tTY2hlbWUiOiAiaU9TSW50ZW50SW50ZWdyYXRpb24iLAogIH0sCiAgInBheW1lbnRJbnN0cnVtZW50IjogewogICAgInR5cGUiOiAiVVBJX0lOVEVOVCIsCiAgICAidGFyZ2V0QXBwIjogIlBBWVRNIgogIH0KfQ=="
}
{ 
    "request": ""
}

Sample Response for PG UPI Open Intent

{
  "success": true,
  "code": "PAYMENT_INITIATED",
  "message": "Payment initiated",
  "data": {
    "merchantId": "MERCHANTUAT",
    "merchantTransactionId": "MT7850590068188104",
    "instrumentResponse": {
      "type": "UPI_INTENT",
      "intentUrl": "ppe://[email protected]&pn=MerchantUAT&am=1.00&mam=1.00&tr=MT7850590068188104&tn=Payment%20for%20MT7850590068188104&mc=5311&mode=04&purpose=00&utm_campaign=B2B_PG&utm_medium=JUSPAYUAT&utm_source=MT7850590068188104"
    }
  }
}
{
    "success": true,
    "code": "PAYMENT_INITIATED",
    "message": "Payment initiated",
    "data": {
        "merchantId": "JUSPAYUAT",
        "merchantTransactionId": "04b4307c-4f2a-400a-bbf4-983bf892cb92",
        "instrumentResponse": {
            "type": "UPI_INTENT",
            "intentUrl": "gpay://upi/[email protected]&pn=JUSPAYUAT&am=9.00&mam=9.00&tr=04b4307c-4f2a-400a-bbf4-983bf892cb92&tn=Payment%20for%2004b4307c-4f2a-400a-bbf4-983bf892cb92&mc=5311&mode=04&purpose=00&utm_campaign=B2B_PG&utm_medium=JUSPAYUAT&utm_source=04b4307c-4f2a-400a-bbf4-983bf892cb92"
        }
    }
}
{
    "success": true,
    "code": "PAYMENT_INITIATED",
    "message": "Payment initiated",
    "data": {
        "merchantId": "JUSPAYUAT",
        "merchantTransactionId": "7d673027-5d0d-424b-abb5-884727db4060",
        "instrumentResponse": {
            "type": "UPI_INTENT",
            "intentUrl": "paytmmp://upi/[email protected]&pn=JUSPAYUAT&am=9.00&mam=9.00&tr=7d673027-5d0d-424b-abb5-884727db4060&tn=Payment%20for%207d673027-5d0d-424b-abb5-884727db4060&mc=5311&mode=04&purpose=00&utm_campaign=B2B_PG&utm_medium=JUSPAYUAT&utm_source=7d673027-5d0d-424b-abb5-884727db4060"
        }
    }
}

🚧

Handling UPI Apps on the Checkout Page

Merchants should display only the list of the UPI Apps installed on the user's device.

Integration Steps

iOS PG SDKLess App Side Implementation

Step 1. In your Info.plist, 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>
2210
Step 2. Create DeepLink Schema

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)

2194

Code Snippet to Generate "deviceContext"

To find 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
    }
}