Collect Payments with BNPL using Link and Pay

The following steps are involved when collecting payment with BNPL using Link and Pay:

  1. Check the BNPL eligibility
  2. Initiate the payment
  3. Submit the OTP (First-Time flow only)

Step 1: Check the BNPL eligibility

Before you can initiate payment with PayU, you can check the eligibility using the Get Checkout Details API. For more information, refer to Check BNPL Eligibility.

Environment

Sample request

curl --location --request POST 'https://info.payu.in/merchant/postservice.php?form=2' \ --form 'key="J*****g"' \ --form 'command="get_checkout_details"' \ --form 'var1="{\"requestId\":\"745452892102453443\",\"transactionDetails\":{\"amount\":\"1000\"},\"customerDetails\":{\"mobile\":\"9999999999\"},\"filters\":{\"paymentOptions\":{\"bnpl\":\"all\"}},\"useCase\":{\"checkCustomerEligibility\":true}}"' \ --form 'hash="c0cd813aa5e21e05e0643c483d011a0a055ad193e26d87ea00583f5a339830050e1aae0a6571a9de967c7072faf1c35c01f9c6b2c8534a3e412abea132a596b2"' \"

Sample response

{
    "status": 1,
    "details": {
        "paymentOptions": {
            "bnpl": {
                "all": {
                    "HDFCF15": {
                        "eligibility": {
                            "status": false,
                            "reason": "Customer not eligible for this Payment type"
                        }
                    },
                    "HDFCF30": {
                        "eligibility": {
                            "status": false,
                            "reason": "Customer not eligible for this Payment type"
                        }
                    },
                    "HDFCF60": {
                        "eligibility": {
                            "status": false,
                            "reason": "Customer not eligible for this Payment type"
                        }
                    },
                    "HDFCF90": {
                        "eligibility": {
                            "status": false,
                            "reason": "Customer not eligible for this Payment type"
                        }
                    },
                    "ICICPL": {
                        "eligibility": {
                            "status": false,
                            "reason": "Customer not eligible for this Payment type"
                        }
                    },
                    "LAZYPAY": {
                        "eligibility": {
                            "status": true
                        }
                    }
                }
            }
        }
    }
}

Step 2: Initiate the payment

You can initiate the payment using the _payment API along with the following additional parameters as in Merchant Hosted Checkout Integration for BNPL. For complete list of parameters and "Try It" experience on API Reference, refer to Collect Payment API - S2S Link and Pay.

📘

Notes:

  • The txn_s2s_flow parameter must be passed with the value 4 for OneClick checkout flow.
  • User credentials is a request parameter in the payment request which will be the unique identifier for each user that will have to be passed by the merchant and will be used to identify each unique user. It can be string with the following format. abc:xyz (data type: string), abc corresponds to the merchant key and xyz corresponds to the user identifier. For example, BmzSVc: userid

Environment

Request parameters

ParameterDescriptionExample
txn_s2s_flow String Pass the values as 4 for Link & Pay.4
LinkAndPayFlowTypeStringThis parameter can contain any of the following values:
- 0: If the value is 1, then auto-debit will be preferred if customer is found already linked for the payment instrument basis result of the API and final captured / failure response will be returned.
- 1: If value is 0, then the request will be considered as a standard native OTP request and transaction in progress response will be returned with OTP sent to the customer by the issuer
Valid Values: 0 and 1
LinkAndPayFlowDetailsString This parameter is to include additional details are required.
user_credentialsString Unique user credential mapped against each user, to be passed by the merchant..abc:xyz

Response parameters

📘

Reference

For the response parameters, refer to Additional Info for Payment APIs.

Sample response

📘

Notes:

There will be different scenarios and the response according to different scenarios:

  • Repeat User Flow: If the customer’s account is linked and auto-debit is success:
  • Repeat User Flow: If the customer’s account is linked and auto debit fails (eg. Customer not eligible, Failed at Payment Option’s end)
  • First Time User Flow: If customer is eligible, but is not linked: This is the registration flow, where a first-time user is paying on a merchant with the specific payment option

Repeat User Flow: Auto-debit Successful

{
    "metaData": {
        "message": "No Error",
        "referenceId": "748e033af87f1bb7b6aefd405bec9473",
        "statusCode": "E000",
        "txnId": "951bccfde0ac54f75612",
        "unmappedStatus": "success",
        "submitOtp": {
            "status": "success"
        }
    },
    "result": {
        "mihpayid": "18828133385",
        "mode": "BNPL",
        "status": "success",
        "key": "smsplus",
        "txnid": "951bccfde0ac54f75612",
        "amount": "2.00",
        "addedon": "2023-12-27 18:13:41",
        "productinfo": "Product Info",
        "firstname": "Payu-Admin",
        "lastname": "",
        "address1": "",
        "address2": "",
        "city": "",
        "state": "",
        "country": "",
        "zipcode": "",
        "email": "[email protected]",
        "phone": "9123412345",
        "udf1": "",
        "udf2": "",
        "udf3": "",
        "udf4": "",
        "udf5": "",
        "udf6": "",
        "udf7": "",
        "udf8": "",
        "udf9": "",
        "udf10": "",
        "card_token": "",
        "card_no": "",
        "field0": "",
        "field1": "9582567614",
        "field2": "EMI1014338639070843702",
        "field3": "Transaction is successful",
        "field4": "bnpl",
        "field5": "VFhOMzk2MjA3ODY2",
        "field6": "TXN396207866",
        "field7": "PAYMENT_SUCCESSFUL",
        "field8": "SUCCESS",
        "field9": "Transaction is successful",
        "payment_source": "payuPureS2S",
        "PG_TYPE": "BNPL-PG",
        "error": "E000",
        "error_Message": "No Error",
        "net_amount_debit": "2.07",
        "discount": "0.00",
        "offer_key": "",
        "offer_availed": "",
        "additionalCharges": "0.07",
        "unmappedstatus": "captured",
        "hash": "3a7742e5d9284e4f43d349bf1a5ff04353a099920ced98330fab15728841b6c772f00f83163c491d8954ead0c9a1dee7af94d67ddc539ff6cb2d0246baed8148",
        "bank_ref_no": "TXN396207866",
        "bank_ref_num": "TXN396207866",
        "bankcode": "LAZYPAY",
        "surl": "https://admin.payu.in/test_response",
        "curl": "https://admin.payu.in/test_response",
        "furl": "https://admin.payu.in/test_response"
    }
}

Repeat user flow: Auto-debit failed

  • Customer not eligible
{
"metaData": {
"message": "The customer is not eligible for this transaction",
"referenceId": "423fe9bfebdb2f92b8ae95a125aff397",
"statusCode": "E2401",
"txnId": "4223974b64f88ab4e3a1",
"txnStatus": "failed",
"unmappedStatus": "failure"
},
"result": {}  
  • Failed at option's end
{ 
  "metaData": 
  { 
    "message": "Transaction Failed at bank end.", 
    "referenceId": "ea68a970115a9d87c6ece8d0218e6c2a", 
    "statusCode": "E308", 
    "txnId": "54d2d883f8e4a3fff6ba", 
    "txnStatus": "failed", 
    "unmappedStatus": "failure" 
  }, 
  "result": {} 
}

First-time user flow

{ "metaData": { "message": null, "referenceId": "748e033af87f1bb7b6aefd405bec9473", "statusCode": null, "txnId": "951bccfde0ac54f75612", "txnStatus": "pending", "unmappedStatus": "pending" }, "result": { "acsTemplate": "PGh0bWw+PGJvZHk+PGZvcm0gbmFtZT0icGF5bWVudF9wb3N0IiBpZD0icGF5bWVudF9wb3N0IiBhY3Rpb249Imh0dHBzOi8vc2VjdXJlLnBheXUuaW4vX3BheW1lbnRfb3B0aW9ucz9taWhwYXlpZD03NDhlMDMzYWY4N2YxYmI3YjZhZWZkNDA1YmVjOTQ3MyZyZXNlbmRFbGlnaWJpbGl0eVJlcz0zNTk0YzczYjE4ZjdjYTllODE0NmYwYmIzZDBiZDg0MjllNWEyMGMyZjYxZDc3OGJmZDBmYjRiMGQ0MzBlYmQyMWE4ZDhmZjIwZTc3NzU4YzkwM2E3MWZlMjJkMzlkMTQ5NDEyNzAzNGVkN2Q1MDUyMzdjYjZmN2JmODBjYzMxMDdhMDJjYmQyMjIxN2MxOWY2NjYyZWZhYzhlOGY4M2RjYTkwMjQ3MGE5ODFiZGQwYTBjMDM4NDdkNTQ2ZjQxYWQ4ZjMwNjZiMmNjYzhhMzU5ZTAzMDMyOTUzZjM2MTEyZDBlNTUxZWMxOWJhNzE5NTRkZmU3ODhkMThhMjhhYzc2MDliYTUzYmQ3NzU0OGNmZmI4MTg4MjM0N2ZjOGI5NzMxNTUwOWFmZGY4YTA4OTQ0NDNjZjkxZTBiMWZkZTg0NTk0YmVlNmZjOWQzOWRhODg0ZjMwMjFlYjIyMjQ2MThlMmM3ZjExNWEwMjA1NzA1MTk4NzIyMGVjNzg2NGVjYzQ0YTAxMjQxN2U0ODgwYjE4N2VlMWYxMjM2M2EyNWE0YmEzNmQ3YjI5MjcxNmUyYjNiNDkzZDhlNzAxNGNiOTIyM2Q1YmUzNjg4N2YyYzViNTNkNTI1MjM1NWU4MjA5NTBiMzllZDk3OWNiMzY3ZTVlNDc0YzBiMTVjOTJjNzJiOWE2Y2E3MTk0OWQ2YTYyYTNjYTlmNDMyY2VjMDY0MWY5ODIyYmM4OGI2NTUwODcwZGU5ZTE4MzQxMGY3YzI0YmVlYjk1ZjNjMTkzN2ZjN2U4N2YzZDRjYmVjNWEyYTFmNiIgbWV0aG9kPSJwb3N0Ij48L2Zvcm0+PHNjcmlwdCB0eXBlPSd0ZXh0L2phdmFzY3JpcHQnPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93Lm9ubG9hZD1mdW5jdGlvbigpewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmZvcm1zWydwYXltZW50X3Bvc3QnXS5zdWJtaXQoKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgPC9zY3JpcHQ+PC9ib2R5PjwvaHRtbD4=", "otpPostUrl": "https:\\/\\/secure.payu.in\\/ResponseHandler.php" } }

Handling response

📘

Notes:

To request OTP on a page, you can utilize the URLs in the response itself. There are two URLs to use:

  • otpPostUrl (Merchant Hosted OTP page)
  • acsTemplate (PayU Hosted OTP page) which acts as a fallback

If you are getting a URL in otpPostUrl, use otpPostUrl, otherwise, you can use acsTemplate, which acts as a fallback. In this scenario, use PayU (or WebView or Checkout) OTP page as this is a fallback case.
Hence, for cases where the above response is not successful, it could either be Failed or Pending. In the Pending state, you can send a fallback URL (as above) which can be shown to the customer.

Step 3: Submit the OTP (for First time Flow only)

You can submit the OTP using any of the following methods:

  • Capture the OTP natively on your interface
  • Use fallback option to redirect to Payu page to capture OTP

Capture the OTP natively on your interface

After you have collected the OTP from the customer, the reference ID can be found in the Collect Payment API (_payment) response. Submit the OTP that is entered by the customer is submitted along with the reference ID using the Submit OTP API. For more information, refer to Submit OTP API.

Capture the OTP after redirection to Payu page

The redirect URL would be shared as part of the payment response in acsTemplate using which customer can be redirected to Payu page:

<html> <body> <form name="payment_post" id="payment_post" action="https://test.payu.in/ _payment_options?mihpayid=1983a7cf520b567155ed95ca181e37e3&resendEligibilityRes =3594c73b18f7ca9e8146f0bb3d0bd8429e5a20c2f61d778bfd0fb4b0d430ebd21a8d8ff20e7775 8c903a71fe22d39d1494127034ed7d505237cb6f7bf80cc3107a02cbd22217c19f6662efac8e8f8 3dca902470a981bdd0a0c03847d546f41ad8f3066b2ccc8a359e03032953f36112d0e551ec19ba7 1954dfe788d18a28ac7609ba53bd77548cffb81882347fc8b97315509afdf8a0894443cf91e0b1f de84594bee6fc9d39da884f3021eb2224618e2c7f115a02057051987220ec7864ecc44a012417e4 880b187ee1f12363a25a4bec62d8322eb1b185195a714124b5de94309a6dce42ef441464d3462e7 809670c" method="post"></form> <script type='text/javascript'> window.onload=function(){ document.forms['payment_post'].submit(); } </script> </body> </html>

On opening the above HTML, you will get a PayU checkout OTP page similar to the following screenshot:

From here, the steps are as in PayU Hosted (non-seamless) or Merchant Hosted or Server-to-Server (seamless) transactions.

Handling incorrect OTP submission

Incorrect OTP Submission is allowed 3 times in total (1 + 2 retries), post which the transaction fails. Scenarios are described as follows:

📘

Note:

If the customer enters the incorrect OTP or OTP has expired, you need to resend the OTP to the customer using the Resend OTP API and then submit using the Submit OTP API. For more information, refer to Collect Payments with BNPL-Merchant Hosted Checkout

  • Case 1: With 1st Incorrect retry OTP attempt
{ 
    "metaData": { 
        "message": "Unauthorized", 
        "referenceId": "ac2155676982514fd2e3199e83a9c9ec", 
        "txnId": "ad5a54b6af3e52ab24d6", 
        "unmappedStatus": "in progress", 
        "submitOtp": { 
            "status": "in progress", 
            "retryAttemptCount": "2" 
        } 
    }, 
    "result": null 
} 
  • Case 2: With 2nd Incorrect retry OTP attempt
{ 
    "metaData": { 
        "message": "Unauthorized", 
        "referenceId": "ac2155676982514fd2e3199e83a9c9ec", 
        "txnId": "ad5a54b6af3e52ab24d6", 
        "unmappedStatus": "in progress", 
        "submitOtp": { 
            "status": "in progress", 
            "retryAttemptCount": "1" 
        } 
    }, 
    "result": null 
} 

📘

Note:

The driving factor here is retryAttemptCount. In case 1, retryAttemptCount was 2, whereas it is 1 in case 2.

📘

Reference:

If your customer fails to authorize the payment due to incorrect OTP submission or the OTP was submitted after OTP had expired, they can request another OTP based on the number of retry attempts remaining using the Resend OTP API. For more information, refer to Resend OTP API.