iOS SDK Setup
In this part we will talk about how you can integrate iOS SDK and initiate payment:
Prerequisites:
- XCode 12.5 or newer
- Cocoapod
- Onboarded on PhonePe as a Merchant (Given a MerchantID, Client Secret and version to generate the o-auth token )
iOS PG SDK setup
- The PhonePePayment framework is needed for the SDK to work for both Sandbox (Testing) and Production (Deployment) environments.
- The PhonePePayment SDK is available through CocoaPods [Refer to this link ], Latest Phonepe iOS SDK Version: 5.0.0.
- To install it, simply add the following line to your Podfile:
pod 'PhonePePayment'pod install- Import the framework in your project using “import PhonePePayment”
- Remove the “DirectPaymentSDK” from your project if you have already integrated and want to migrate to CocoaPods.
import PhonePePaymentiOS PG 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>
<string>credpay</string>
<string>amazonpay</string>
<string>bhim</string>
</array>
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)

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.
Step 3. Create B2BPGTransactionRequest Object
Using the Payload from your server, create a B2BPGTransactionRequest object, with appSchema as the URLType created in the step above.
Example: appSchema : iOSIntentIntegration
To Enable Debug Logs
Update the PPPayment.enableDebugLogs = true or enableLogging flag to true in startPG method.
Environment :
.Productionfor Live.Sandboxfor Sandbox testing
Step 4. Initialize the PG SDK
let ppPayment = PPPayment(environment: .production,
flowId: "FLOW_ID",
merchantId: "MERCHANT_ID")| Parameter Name | Type | Description |
environment | Enum | .production for Production.sandbox for PreProd |
flowId | String | Pass the merchant user Id or the unique string (UUID().uuidString) for every init for analytics purposes. |
merchantId | String | The merchant Id provided by PhonePe |
enableLogging | Boolean | [Optional Parameter] – True (To enable the SDK logs) – False (To disable the SDK logs) Note: In Prod, make sure to set as False. |
- Initialize the PPPayment with the environment
- The B2BPGTransactionRequest is an object that you need to pass the SDK and SDK will handle the request and get back the response after the payment completion.
- In the completion handle you get the state of the payment. After that, You need to call the status API from the backend to get the status of the transaction.
Pass the merchant ID, Order ID and the Token generated using create order API here along with payment mode and app schema details.
Custom Checkout
public func startTransaction(request: PhonePePayment.B2BPGTransactionRequest, on viewController: UIViewController, completion: @escaping PhonePePayment.PPTransactionCompletion)
Example:
ppPayment.startTransaction(request: request,
on: vc) { _, state in
print(state)
}
//In B2BPGTransactionRequest, We need 5 parameters to init the object.
public struct B2BPGTransactionRequest {
public init(merchantId: String, orderId: String, token: String, appSchema: String, paymentMode: PhonePePayment.PaymentMode)
}
//Example below for B2BPGTransactionRequest for UPI Intent Payment Mode:
let request = B2BPGTransactionRequest(merchantId: "TEST",
orderId: "TXT",
token: token,
appSchema: "YOUR_APP_SCHEMA",
paymentMode: .upiIntent(request: UPIIntentPaymentMode(targetApp: "PHONEPE")))| Parameter Name | Type | Description |
merchantId | String | Provided by PhonePe |
orderId | String | The PhonePe Order ID received in the Create Order API response. |
token | String | The order token received in the backend from Create Order API call. |
appSchema | Long | The app schema that you need to pass for redirect to the merchant app after the payment succeeded. |
paymentMode | Object | The Payment mode that you need to pass as per your use case. |
PaymentModes
Use the particular instrument that you need for your request.
public enum PaymentMode {
case upiIntent(request: PhonePePayment.UPIIntentPaymentMode)
case upiCollect(request: PhonePePayment.UpiCollectPaymentMode)
case netBanking(request: PhonePePayment.NetbankingPaymentMode)
case newCard(request: PhonePePayment.NewCardPaymentMode)
}PaymentMode – UPI Intent
public struct UPIIntentPaymentMode {
public init(targetApp: String)
}
//For targetApp parameter - Allowed Values:[PHONEPE, GPAY, PAYTM, CRED, AMAZON, BHIM]PaymentMode – UPI Collect
public struct UpiCollectPaymentMode {
public init(message: String, details: PhonePePayment.PGBaseCollect)
}
// VPA Model that is needed for Collect Payment
public struct VPACollectDetails : PhonePePayment.PGBaseCollect {
public private(set) var type: String? { get }
public init(vpa: String)
public func encode(to encoder: Encoder) throws
}
// PhoneNumber Model is needed for Collect Payment
public class PhoneNumberDetails : PhonePePayment.PGBaseCollect {
public private(set) var type: String? { get }
public init(phoneNumber: String)
public func encode(to encoder: Encoder) throws
}Note: When you initialise the collect payment, you need to pass the VPA or phoneNumber. We have two models under collect, that you need to pass as per your use case.
PaymentMode – NetBanking
public struct NetbankingPaymentMode {
public
init(bankId: String? = nil)
}PaymentMode – Card Payment
⚠️ Compliance for SDK Payments!
To accept card payments via the SDK, you must be either PCI or SAQ-A-EP compliant.
public struct NewCardPaymentMode {
public init(cardNumber: String,
cardHolderName: String,
cvv: String,
expiryMonth: String,
expiryYear: String,
merchantUserId: String)
}
| Parameter | DataType | Description |
cardNumber | String | Card number entered by user. |
cardHolderName | String | Card holder name entered by user. |
cvv | String | Card’s CVV or security code. |
expiryMonth | String | Card’s expiration month entered in mm format. |
expiryYear | String | Card’s expiration year entered in yyyy format. |
merchantUserId | String | Your unique user ID or a random string you’ve generated for this transaction. |
Now you need to call the validateCardDetails method, to check the card details before calling the startTransaction:
public func validateCardDetails(mode: PhonePePayment.NewCardPaymentMode, completion: @escaping (_ isValid: Bool, _ errorMessage: String?) -> Void)ppPayment.validateCardDetails(mode: NewCardPaymentMode) { (isValid, errorMessage) in
if isValid {
// StartTransaction
} else {
consoleLog(errorMessage.emptyIfNil, type: .error)
}
}
Card Validation
- If a customer enters invalid card details like a wrong card number, CVV, expiry date, or cardholder name, we will let you know with a specific error message. In this case, the system will show that the card details are not valid.
- You can share this error message with your customer so they can correct the issue and try again.
Successful Transaction
- Once the customer enters all the correct card information, the system will confirm that the details are valid. Only then can you proceed by calling the startTransaction method to begin the payment.
In your appdelegate, check for a callback from the phonepe app and if found, pass it to the sdk.
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let handled = PPPayment.checkDeeplink(url)
if handled {
// Phonepe is handling this, no need for any processing
return true
}
//Process your own deeplinks here
return true
}After the method calls, you will get the control in the completion block.
Once the redirection back to the merchant app then back to the Order Status API /check for webhook response accordingly update the original status to Users.
Code Snippet to Check App Availability
PhonePe App
Swiftprivate struct UriSchemeConstants {
static let uriScheme1 = "ppemerchantsdkv1"
static let uriScheme2 = "ppemerchantsdkv2"
static let uriScheme3 = "ppemerchantsdkv3"
static let hyphenation = "://"
}
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
}
}GPay App
Swiftprivate 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
}
}Paytm App
Swiftprivate struct UriSchemeConstants {
static let uriScheme1 = "paytmmp"
static let hyphenation = "://"
}
func isPaytmInstalled() -> Bool {
DispatchQueue.main.sync {
guard let openUrl1 = URL(string: UriSchemeConstants.uriScheme1 + UriSchemeConstants.hyphenation) else {
return false
}
let appInstalled = UIApplication.shared.canOpenURL(openUrl1)
return appInstalled
}
}