1. Integration Steps

Set up pod

The CheckoutPro SDK is offered through CocoaPods. To add the SDK in your app project:

Include the SDK framework in your podfile.

// make sure to add below-mentioned line to use dynamic frameworks
use_frameworks!
// Add this to include our SDK
pod 'PayUIndia-CheckoutPro' 
  • Install dependency using the pod install command in terminal
  • Add the following imports in the class where you need to initiate a payment.
#import 
#import 
#import 
import PayUCheckoutProKit
import PayUCheckoutProBaseKit
import PayUParamsKit
  • Test the key and salt in the following environments:
    • Production— Refer to Generate Production Merchant Key and Salt
    • Test— Refer to Generate Test Merchant Key and Salt

Swift Package Manager Integration

You can integrate PayUIndia-Checkoutpro with your app or SDK using the following methods:

  • Using Xcode: Navigate to File > Add Package menu and add the following package:
    https://github.com/payu-intrepos/PayUCheckoutPro-iOS
  • Using Package.Swift: Add the following line in the Package.swift dependencies: .package(name: "PayUCheckoutProKit", url: "https://github.com/payu-intrepos/PayUCheckoutPro-iOS", from: "7.2.1")

CrashReporter

In order to receive all the crashes related to our SDKs, add the following line to your AppDelegate’s didFinishLaunchingWithOptions:

[PayUCheckoutPro start];
PayUCheckoutPro.start()

🚧

Remember

Please add NSCameraUsageDescription key in your application Info.plist file.

Step 2: Set up the payment hashes

🚧

Remember

Always generate the hashes on your server. Do not generate the hashes locally in your app, as it will compromise the security of the transactions.

The CheckoutPro SDK uses hashes to ensure the security of the transaction and prevent any unauthorized intrusion or modification. The CheckoutPro SDK requires two types of hashes. For more information on the two types of hashes, refer to Hash Generation for CheckoutPro SDK.

Step 3: Build the payment parameters (mandatory step)

To initiate a payment, your app must send the transaction information to the Checkout Pro SDK. To pass this information, build a payment parameter object as in the following code snippet:

PayUPaymentParam *paymentParam = [[PayUPaymentParam alloc] initWithKey:<#(NSString * _Nonnull)#>
                                                         transactionId:<#(NSString * _Nonnull)#>
                                                                amount:<#(NSString * _Nonnull)#>
                                                           productInfo:<#(NSString * _Nonnull)#>
                                                             firstName:<#(NSString * _Nonnull)#>
                                                                 email:<#(NSString * _Nonnull)#>
                                                                 phone:<#(NSString * _Nonnull)#>
                                                                  surl:<#(NSString * _Nonnull)#>
                                                                  furl:<#(NSString * _Nonnull)#>
                                                           environment:<#(enum Environment)#> /*EnvironmentProduction or EnvironmentTest*/];

paymentParam.userCredential = <#(NSString)#>; // For saving and fetching use saved card
let paymentParam = PayUPaymentParam(key: <#T##String#>,
                                    transactionId: <#T##String#>,
                                    amount: <#T##String#>,
                                    productInfo: <#T##String#>,
                                    firstName: <#T##String#>,
                                    email: <#T##String#>,
                                    phone: <#T##String#>,
                                    surl: <#T##String#>,
                                    furl: <#T##String#>,
                                    environment: <#T##Environment#> /*.production or .test*/)
                                    
paymentParam.userCredential = <#T##String#> // For saving and fetching user’s saved card

The TransactionId parameter cannot have a special character and not more than 25 characters.

Mandatory parameters

ParameterDescriptionData Type and Validation
Key
mandatory
String Merchant Key received from PayUCannot be null or empty
TransactionId
mandatory
String Cannot be null or empty and should be unique for each transaction. Maximum allowed length is 25 characters. It cannot contain special characters like: -_/Should be unique for each transaction
Product Info
mandatory
String Information about ProductCannot be null or empty
First Name
mandatory
String Customer’s first nameCannot be null or empty
Email
mandatory
String Customer’s Email IDCannot be null or empty
Phone
mandatory
String Customer’s phone numberShould be of 10 digits
surl
mandatory
String PayU will load this url and pass transaction responseCannot be null or empty
furl
mandatory
String When the transaction is a failure, PayU will load this url and pass transaction responseCannot be null or empty
Environment
mandatory
String
Environment of SDK
Should be either
Swift: Environment.production or Environment.test
ObjectiveC: EnvironmentProduction or EnvironmentTest
User Credential
optional
String This is used for the store card feature. PayU will store cards corresponding to passed user credentials and similarly, user credentials will be used to access previously saved cardsShould be a unique value
Format: :
Here, UserId is any id/email/phone number to uniquely identify the user
PayUSIParams
optional
Object of PayUSIParams. This contains SI Details. Object of PayUSIParams
SplitPaymentDetails
optional
String
This parameter is required for splitting the transactions.
Should be a json String

The code block for passing the parameters is similar to the following:

If you required any value in the response then pass the below value

paymentParam.additionalParam = [[NSDictionary alloc] initWithObjectsAndKeys:
                                    <#(NSString)#>, PaymentParamConstant.udf1,
                                    <#(NSString)#>, PaymentParamConstant.udf2,
                                    <#(NSString)#>, PaymentParamConstant.udf3,
                                    <#(NSString)#>, PaymentParamConstant.udf4,
                                    <#(NSString)#>, PaymentParamConstant.udf5,
                                    <#(NSString)#>, PaymentParamConstant.walletURN,
                                    nil];
paymentParam.additionalParam[PaymentParamConstant.udf1] = <#T##String#>
paymentParam.additionalParam[PaymentParamConstant.udf2] = <#T##String#>
paymentParam.additionalParam[PaymentParamConstant.udf3] = <#T##String#>
paymentParam.additionalParam[PaymentParamConstant.udf4] = <#T##String#>
paymentParam.additionalParam[PaymentParamConstant.udf5] = <#T##String#>
paymentParam.additionalParam[PaymentParamConstant.walletURN] = <#T##String#>  // Required for Amul Wallet

For recurring payments (SI)

If you are integrating SI, create an object of SIParam. After creating an object, pass the object similar to the following code:

paymentParam.siParams = siParam;
paymentParam.siParams = siParam

For split settlements

If you are integrating Split Settlements, the splitPaymentDetails parameter is required to split the transactions.

After creating an object, pass the object similar to the following code:

paymentParam.splitPaymentDetails = @"";
paymentParam.splitPaymentDetails = ""

JSON request structure of splitInfo field

The sample JSON structure for the splitPaymentDetails field:

🚧

Remember

  • For the absolute type split, you must ensure that the sum of amount of all splits is equal to the parent transaction amount.
  • For the percentage type split, you must ensure that the sum of percentage of all splits is equal to 100. You can use any number decimal places for each split, but ensure the sum of percentage of all splits is equal to 100.
{
   "type":"absolute",
   "splitInfo":{
      "P****Y":{
         "aggregatorSubTxnId":"9a70ea0155268101001ba",
         "aggregatorSubAmt":"50",
         "aggregatorCharges":"20"
      },
      "P***K":{
         "aggregatorSubTxnId":"9a70ea0155268101001bb",
         "aggregatorSubAmt":"30"
      }
   }
}

The following fields are included in the splitPaymentDetails parameter in a JSON format to specify the split details. The fields in the JSON format are described in the following table:

FieldDescriptionExample
type
mandatory
string Any of the following types of split is specified in this field.

absolute: The absolute amount is specified for each part of the split. The absolute amount is specified in the aggregatorSubAmt field of the JSON for each child or aggregator. For a sample request and response, refer to Absolute Split During Payment

percentage: The percentage of the amount is specified for each part of the split. The percentage of the amount is specified in the aggregatorSubAmt field of the JSON for each child or aggregator. For a sample request and response, refer to Split by Percentage During Payment
absolute
splitInfo
mandatory
JSON This parameter must include the list of aggregator sub-transaction IDs and sub-amounts as follows:

aggregatorSubTxnId: The transaction ID of the aggregator is posted in this parameter. This field is mandatory and applicable only to child merchants.

aggregatorSubAmt: The transaction amount split for the aggregator is posted in this parameter. This field is mandatory.

aggregatorCharges: The transaction amount split for aggregator charges is posted in this parameter. This field is optional.

Note: Only the parent aggregators can have the aggregatorCharges field as part of their JSON to collect charges.
The sample request structure JSON Request Structure of splitInfo Field.
The sample request structure JSON Request Structure of splitInfo Field.

Step 4: Initiate the payment

Initialize and launch the Checkout Pro SDK by calling the following method from your UIViewController subclass:

[PayUCheckoutPro openOn:self paymentParam:paymentParam config:<#(PayUCheckoutProConfig * _Nullable)#> delegate:self];
PayUCheckoutPro.open(on: self, paymentParam: paymentParam, config: <#T##PayUCheckoutProConfig?#>, delegate: self)

Step 5: Handle the payment completion

Confirm to PayUCheckoutProDelegate and use these functions to get appropriate callbacks from the SDK:

/// This function is called when we successfully process the payment
/// @param response  success response
- (void)onPaymentSuccessWithResponse:(id _Nullable)response {
    
}

/// This function is called when we get failure while processing the payment
/// @param response failure response
- (void)onPaymentFailureWithResponse:(id _Nullable)response {
    
}

/// This function is called when the user cancel’s the transaction
/// @param isTxnInitiated tells whether payment cancelled after reaching bankPage
- (void)onPaymentCancelWithIsTxnInitiated:(BOOL)isTxnInitiated {
    
}

/// This function is called when we encounter some error while fetching payment options or there is some validation error
/// @param error This contains error information
- (void)onError:(NSError * _Nullable)error {
    
}

/// Use this function to provide hashes
/// @param param NSDictionary that contains key as HashConstant.hashName & HashConstant.hashString
/// @param onCompletion Once you fetch the hash from server, pass that hash with key as param[HashConstant.hashName]
- (void)generateHashFor:(NSDictionary<NSString *, NSString *> * _Nonnull)param onCompletion:(void (^ _Nonnull)(NSDictionary<NSString *, NSString *> * _Nonnull))onCompletion {
    // Send below string hashStringWithoutSalt to your backend and append the salt at the end and send the sha512 back to us, do not calculate the hash at your client side, for security is reasons, hash has to be calculated at the server side
    NSString *hashStringWithoutSalt = [param objectForKey:HashConstant.hashString];
    // Or you can send below string hashName to your backend and send the sha512 back to us, do not calculate the hash at your client side, for security is reasons, hash has to be calculated at the server side
    NSString * hashName = [param objectForKey:HashConstant.hashName];
    
    // Set the hash in below string which is fetched from your server
    NSString *hashFetchedFromServer = <#(NSString)#>;
    
    NSDictionary *hashResponseDict = [NSDictionary dictionaryWithObjectsAndKeys:hashFetchedFromServer, hashName, nil];
    onCompletion(hashResponseDict);
}
/// This function is called when we successfully process the payment
/// - Parameter response: success response
func onPaymentSuccess(response: Any?) {
    
}

/// This function is called when we get failure while processing the payment
/// - Parameter response: failure response
func onPaymentFailure(response: Any?) {
    
}

/// This function is called when the user cancel’s the transaction
/// - Parameter isTxnInitiated: tells whether payment cancelled after reaching bankPage
func onPaymentCancel(isTxnInitiated: Bool) {
    
}

/// This function is called when we encounter some error while fetching payment options or there is some validation error
/// - Parameter error: This contains error information
func onError(_ error: Error?) {
    
}

/// Use this function to provide hashes
/// - Parameters:
///   - param: Dictionary that contains key as HashConstant.hashName & HashConstant.hashString
///   - onCompletion: Once you fetch the hash from server, pass that hash with key as param[HashConstant.hashName]
func generateHash(for param: DictOfString, onCompletion: @escaping PayUHashGenerationCompletion) {
    // Send this string to your backend and append the salt at the end and send the sha512 back to us, do not calculate the hash at your client side, for security is reasons, hash has to be calculated at the server side
    let hashStringWithoutSalt = param[HashConstant.hashString] ?? ""
    // Or you can send below string hashName to your backend and send the sha512 back to us, do not calculate the hash at your client side, for security is reasons, hash has to be calculated at the server side
    let hashName = param[HashConstant.hashName] ?? ""

    // Set the hash in below string which is fetched from your server
    let hashFetchedFromServer = <#T##String#>
    
    onCompletion([hashName : hashFetchedFromServer])
}

UPI Intent (Optional)

Currently, PayU supports only PhonePe and GooglePay through Intent. Add the query schemes in theinfo.plist:

<key>LSApplicationQueriesSchemes</key>
<array>
<string>phonepe</string>
<string>tez</string>
<string>paytm</string>
</array>

📘

Note

In the case of UPI intent and Collect flow, you will not receive a callback response in SURL/FURL. In this case, the format of the PayU response received will be different from other payment options that you can handle accordingly. For handling surl or furl, refer to Handling Return URLs.
If you get mihpayid in the PayU response, consider it as a PayU ID/ ID.

Distributing your app (App Store / Ad-hoc)

PayU provides a fat framework that allows you to test your app seamlessly on the device as well as a simulator. But before archiving your app, you need to remove simulator slices from the framework. To archive your app with the PayU CheckoutPro integration, refer to Releasing the app.

Additional integration

Integrate MCP (Multi-Currency Pricing)

📘

Before you begin

Connect with your Key Account Manager at PayU to get the following credentials:

  • Merchant Access Key
  • Merchant Secret Key

The following video shows the demo of an app with MCP integration:

Step 1: Pass merchant access key

Pass the following merchant access key in additional parameters of the PayUCheckoutPro Payment Parameters. For more information on Payment Parameters, refer to Integration with PayUCheckoutPro > Build the Payment Parameters.

paymentParam.additionalParam[PaymentParamConstant.merchantAccessKey] = @<Merchant-Access-Key>; 
paymentParam.additionalParam[PaymentParamConstant.merchantAccessKey] = <Merchant-Access-Key>       

Step 2: Generate hash For MCP

For MCP payments, SDK requires Lookup API hash which is a dynamic hash. SDK will call the generateHash() method as explained in this section.
Lookup API hash is calculated with the HmacSHA1 signature. It requires a Merchant Secret key in calculating the hash. The following example, code demonstrates how to calculate the Lookup API hash.

- (void)generateHashFor:(NSDictionary<NSString *,NSString *> * _Nonnull)param onCompletion:(void (^ _Nonnull)(NSDictionary<NSString *,NSString *> * _Nonnull))onCompletion {
    NSString *commandName = [param objectForKey:HashConstant.hashName];
    NSString *hashStringWithoutSalt = [param objectForKey:HashConstant.hashString];
    // get hash for "commandName" from server
    // After fetching hash set its value in below variable "hashValue"
    NSString *hashValue = [NSMutableString new];
    if (commandName == HashConstant.mcpLookup) {
       if commandName == HashConstant.mcpLookup {
        //To create HMACSHA1 Signature 
        // Signature = HMAC-SHA1(data, key);
        //Data = hashStringWithoutSalt
        //Key = Mechent Secret Key shared with the merchant at the time of on-boarding 
        hashValue = @<HMACSHA1 signature from your server>;
    } else {
        hashValue = @<HMACSHA512 hash from your server>;
    }
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:hashValue, commandName, nil];
    onCompletion(dict);
}
func generateHash(for param: DictOfString, onCompletion: @escaping PayUHashGenerationCompletion) {
        let commandName = (param[HashConstant.hashName] ?? "")
        let hashStringWithoutSalt = (param[HashConstant.hashString] ?? "")
        // get hash for "commandName" from server
        // After fetching hash set its value in below variable "hashValue"
        var hashValue = ""
        if commandName == HashConstant.mcpLookup {
        //To create HMACSHA1 Signature 
        // Signature = HMAC-SHA1(data, key);
        //Data = hashStringWithoutSalt
        //Key = Mechent Secret Key shared with the merchant at the time of on-boarding 
            hashValue = <HMACSHA1 signature from your server>
        } else {
            hashValue = <HMACSHA512 hash from your server>
        }
        onCompletion([commandName : hashValue])
    }

Add custom notes

Step 1: Create a Custom Note list

Create a list of custom notes that you want to pass to the CheckoutPro SDK. For each custom note, custom_note and custom_note_category need to be passed.

  var customNotes = [PayUCustomNote]() 
// for specific custom_note_category
  let customNote = PayUCustomNote()
  customNote.note = "Please welcome note"
  customNote.noteCategories =  [.ccdc]
  customNotes.append(customNote)
  // when want to pass same custom note for multiple custom_note_category
  let customNote2 = PayUCustomNote()
   customNote2.note = "Please welcome note"
   customNote2.noteCategories =  [.ccdc , .netBanking]
   customNotes.append(customNote2)
// If you want to show custom note on L1 screen, please set custom_note_category to nil
  let customNote3 = PayUCustomNote()
  customNote3.note = "Please welcome note"
  customNote3.noteCategories =  nil
  customNotes.append(customNote3)

Step 2: Pass the Custom Note list to SDK

To pass the custom note list (array) created in Step 1 to the SDK, create a PayUCheckoutProConfig object and set customNotes similar to the following code block:

let checkoutProConfig = PayUCheckoutProConfig()
config.customNotes = customNotes

Integrate convenience fee

Set up Convenience Fee

When the Convenience Fee is set for a payment mode like NB. In CheckoutPro SDK, whenever the user selects any NetBanking option then the header amount will be updated with a convenience fee. Amount breakup is accessed by clicking “View Details” in the toolbar. Below screen will be displayed that shows the breakup of the transaction amount with a convenience fee.

The above screenshot displays the amount breakup with the Convenience Fee

By default, when no convenience fee is set, an amount breakup will be similar to the following screenshot.

Integrate Closed Loop wallet

📘

Before you begin

  • Enable Closed-Loop Wallet from your Dashboard.
  • Build the payment parameters with PaymentParamConstant.walletURN parameters. See Integrate with PayU checkoutpro for iOS to learn more.

The following screens show how Closed-Loop wallet payment works on the PayU payment page:

  • When you enable the Closed-Loop wallet for your account, your customer sees the Closed-Loop wallet payment on top of the payment page under the SAVED OPTION tab.
  • The closed-loop wallet balance is fetched and loaded (see the screenshot below) by default.
  • If the balance is not loaded due to some error, an error message will be displayed (see the screenshot below). The customer can tap on the wallet option to reload the amount.
  • Once the balance is loaded the customer can make the payment by clicking Pay Now.