Collect Payments with BNPL using Link and Pay
The following steps are involved when collecting payment with BNPL using Link and Pay:
- Check the BNPL eligibility
- Initiate the payment
- Check the response from PayU
- 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 EMI Checkout Details API. For more information, refer to Get EMI Checkout Details API.
Environment
Test Environment | https://test.payu.in/info/linkAndPay/get_emi_checkout_details |
Production Environment | https://info.payu.in/linkAndPay/get_emi_checkout_details |
Sample request
curl --location 'https://test.payu.in/info/linkAndPay/get_emi_checkout_details' \
--header 'x-credential-username: smsplus' \
--header 'Content-Type: application/json' \
--header 'authorization: hmac username="x0i6r2", algorithm="sha512", headers="date", signature="0e0ebc518c085d8ff49058b7c232bfe2e8779e9e9cafd34a4cdf1c11114035eea75b0e404a9b9e152757dbcc4926f78b6f18ba7f6643e2bf687a65942d3bde38"' \
--header 'date: Mon, 28 Oct 2024 10:34:49 GMT' \
--data '{
"amount": 2000000,
"userCredentials": "aaa:bbb",
"phone": "9560012582",
"bankCode": null,
"payuToken": null
}'
Sample response
{
"bnpl": {
"all": [
{
"Lazypay": {
"status": 1,
"kfsLink": https://www.somekfsLink.com, // only if applicable
"eligible": true,
"customerLinked": true,
“PayuToken”: “Token12345”
},
"Simpl": {
"status": 1,
"availableBalance": 500, // only if applicable
"kfsLink": https://www.somekfsLink.com, // only if applicable
"eligible": true,
"customerLinked": true,
“PayuToken”: “Token78901”
}
}
]
}
}
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
Test Environment | https://test.payu.in/_payment |
Production Environment | https://secure.payu.in/_payment |
Request parameters
Reference:
For Try It experience, refer to Collect Payments API - BNPL under API Reference.
Parameter | Description | Example |
---|---|---|
keymandatory | String Merchant key provided by PayU during onboarding. | JPg***r |
txnidmandatory | String The transaction ID is a reference number for a specific order that is generated by the merchant. | ypl938459435 |
amount mandatory | String The payment amount for the transaction. | 10.00 |
productinfo mandatory | String A brief description of the product. | iPhone |
firstname mandatory | String The first name of the customer. | Ashish |
emailmandatory | String The email address of the customer. | [email protected] |
phonemandatory | String The phone number of the customer. | |
pg mandatory | String It defines the payment category using the Merchant Hosted Checkout integration. For a BNPL payment, "BNPL" must be specified in the pg parameter. | BNPL |
bankcode mandatory | String The merchant must post this parameter with the corresponding payment option’s bank code value in it. For the list of bankcodes for BNPL, refer to BNPL Codes . | LAZYPAY |
furlmandatory | String The success URL, which is the page PayU will redirect to if the transaction is successful. | |
surlmandatory | String The Failure URL, which is the page PayU will redirect to if the transaction is failed. | |
txn_s2s_flowmandatory | String Pass the values as 4 for Link & Pay. | 4 |
LinkAndPayFlowTypemandatory | String This 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 | 1 |
LinkAndPayFlowDetailsmandatory | String This parameter is to include additional details are required. | abc:xyz |
storecard_token_typeoptional | String This parameter is used to specify the store card token type for stored card. For this scenario, you must include 0. | 1 |
storecard_tokenoptional | String This parameter must include the token generated by PayU for the payment instrument and applicable for stored card only.Note: Either pass PayU token or user credentials with mobile number for customer identification | 123456 |
user_credentialsmandatory | String` Unique user credential mapped against each user, to be passed by the merchant.. | |
hashmandatory | String It is the hash calculated by the merchant. The hash calculation logic is:sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||SALT) | |
address1optional | String The first line of the billing address.For Fraud Detection: This information is helpful when it comes to issues related to fraud detection and chargebacks. Hence, it is must to provide the correct information. | |
address2optional | String The second line of the billing address. | |
cityoptional | String The city where your customer resides as part of the billing address. | |
stateoptional | String The state where your customer resides as part of the billing address, | |
countryoptional | String The country where your customer resides. | |
zipcodeoptional | String Billing address zip code is mandatory for the cardless EMI option.Character Limit -20 | |
udf1optional | String User-defined fields (udf) are used to store any information corresponding to a particular transaction. You can use up to five udfs in the post designated as udf1, udf2, udf3, udf4, udf5. | |
udf2optional | String User-defined fields (udf) are used to store any information corresponding to a particular transaction. You can use up to five udfs in the post designated as udf1, udf2, udf3, udf4, udf5. | |
udf3optional | String User-defined fields (udf) are used to store any information corresponding to a particular transaction. | |
udf4optional | String User-defined fields (udf) are used to store any information corresponding to a particular transaction. | |
udf5optional | String User-defined fields (udf) are used to store any information corresponding to a particular transaction. |
Hashing
You must hash the request parameters using the following hash logic:
sha512(key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||SALT)
For more information, refer to Generate Hash.
Sample request
curl --request POST \
--url https://test.payu.in/_payment \
--header 'accept: application/json' \
--header 'content-type: application/x-www-form-urlencoded' \
--data key=JPM7Fg \
--data pg=BNPL \
--data txn_s2s_flow=4 \
--data LinkAndPayFlowType=1 \
--data LinkAndPayFlowDetails=1 \
--data txnid=951bccfde0ac54f75612 \
--data amount=2 \
--data productinfo=Product Info \
--data firstname=Ashish \
--data [email protected] \
--data phone=9123412345 \
--data surl=https://apiplayground-response.herokuapp.com/ \
--data furl=https://apiplayground-response.herokuapp.com/ \
--data hash=02647d079d45737aede205a5bf0060ffcf32b5104facebaf901b479b958d80a0e0e88c9edd4f5c9a0576c7bc1688cce15957759029a0e58f5699b8a696c98d10 \
--data user_credentials=abc:xyz
Step 3: Check the response from PayU
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
Success scenario
- Repeat User Flow: Auto-debit Successful
This is the case where Customer’s account is liked & Auto debit is also successful
{
"metaData": {
"message": "No Error",
"referenceId": "748e033af87f1bb7b6aefd405bec9473",
"statusCode": "E000",
"txnId": "951bccfde0ac54f75612",
"unmappedStatus": "success",
"submitOtp": {
"status": "success"
}
},
"result": {
"link_and_pay": {
"customerLinked": "true",
"payuToken": "token12345"
},
"mihpayid": "18828133385",
"mode": "BNPL",
"status": "success",
"key": "smsplus",
"txnid": "951bccfde0ac54f75612",
"amount": "2.00",
"addedon": "2023-12-27 18:13:41",
"productinfo": "Product Info",
"firstname": "Ashish",
"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"
}
}
Failure scenario
- Repeat User Flow: Auto-debit Failed
{
"metaData": {
"message": "The customer is not eligible for this transaction",
"referenceId": "423fe9bfebdb2f92b8ae95a125aff397",
"statusCode": "E2401",
"txnId": "4223974b64f88ab4e3a1",
"txnStatus": "failed",
"unmappedStatus": "failure"
},
"result": {
"link_and_pay": {
"customerLinked": "true",
"payuToken": "token12345"
}
}
}
- Failed at Payment option’s end
{
"metaData": {
"message": "Transaction Failed at bank end.",
"referenceId": "ea68a970115a9d87c6ece8d0218e6c2a",
"statusCode": "E308",
"txnId": "54d2d883f8e4a3fff6ba",
"txnStatus": "failed",
"unmappedStatus": "failure"
},
"result": {
"link_and_pay": {
"customerLinked": "true",
"payuToken": "token12345" // can be null or "" <empty string>
}
}
}
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 4: 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.
Updated about 1 month ago