Node JS SDK
This SDK offers a simple-to-use API for integrating Pine Labs API in your node applications. It provides several easy methods for creating, fetching orders, calculating EMIs, and verifying hash.
A step-by-step guide on the usage is available here: Plural by Pinelabs | Youtube
Sample app: Link
Refer to Github: Link
Installation
Prerequisites
Before installing the Node SDK, make sure you meet the following prerequisites:
- NODE version 18.17.1 or higher
- NPM version 9.6.7 or higher
To install this SDK locally from a folder you'll need to run the following commands. It will link and install the SDK in your node project.
npm link "../path-to-sdk-folder"
npm install "../path-to-sdk-folder"
Usage For SDK
Create an Instance of Pine Labs SDK
Require pinelabs sdk and call the default
method on it. It takes 4 parameters which are as follows:
- Merchant ID (string): Merchant ID provided by PineLabs
- Merchant Access Code (string): Merchant Access Code Provided by PineLabs
- Merchant Secret (string): Merchant Secret
- isTest (boolean): If using test mode then set this to
true
const pinelabs = require("pinelabs_node").default("{merchant_id}", "merchant_access_code", "{merchant_secret}", isTest)
Create Order
This section explains how to create an order for payment processing. There are a couple of things required to create an order.
Parameters Required & Optional
// Transaction Data ( Mandatory )
const txn_data = {
txn_id: "", // String
callback: '', // String
amount_in_paisa: '1000', // String
}
// Customer Data ( Optional )
const customer_data = {
email_id: "", // String
first_name: "", // String
last_name: "", // String
mobile_no: "", // String
customer_id: "", // String
}
// Billing Data ( Optional )
const billing_data = {
address1: "", // String
address2: "", // String
address3: "", // String
pincode: "", // String
city: "", // String
state: "", // String
country: "", // String
}
// Shipping Data ( Optional )
const shipping_data = {
first_name: "", // String
last_name: "", // String
mobile_no: "", // String
address1: "", // String
address2: "", // String
address3: "", // String
pincode: "", // String
city: "", // String
state: "", // String
country: "", // String
}
// UDF data ( Optional )
const udf_data = {
udf_field_1: "", // String
udf_field_2: "", // String
udf_field_3: "", // String
udf_field_4: "", // String
udf_field_5: "", // String
}
// Payment Modes That Need to Be Shown ( Mandatory )
const payment_mode = {
netbanking: true, // Boolean
cards: true, // Boolean
emi: true, // Boolean
upi: true, // Boolean
cardless_emi: true, // Boolean
wallet: true, // Boolean
debit_emi: true, // Boolean
prebooking: true, // Boolean
bnpl: true, // Boolean
paybypoints: false, // Boolean
}
// Product Details (SKU is mandatory during emi)
const product_details = [
{
"product_code": "testSKU1", // String
"product_amount": 500000 // Integer
},
{
"product_code": "testSKU1", // String
"product_amount": 500000 // Integer
}
]
Order Creation
Using the instance of the SDK we created above we will call the .create()
method on the payment
interface for
creating an order with the provided parameters. It takes the following positional arguments
- Transaction Data
- Payment Modes
- Customer Data
- Billing Data
- Shipping Data
- UDF Data
- Product Details
The create()
method returns a promise with the response or else throws an error if something went wrong.
// Create Order
pinelabs.payment.create(txn_data, payment_mode, customer_data, billing_data, shipping_data, udf_data, product_details).then((data) => {
console.log(data)
});
Success Response
{
"status": true,
"redirect_url": "https://uat.pinepg.in/pinepg/v2/process/payment?token=S01wPSlIH%2bopelRVif7m7e4SgrTRIcKYx25YDYfmgtbPOE%3d"
}
Failure Response
Fatal error: Uncaught Exception: MERCHANT PASSWORD DOES NOT MATCH
Fetch Order
Using the instance of the SDK we created above we will call the .fetch()
method on the payment
interface for
fetching
an order details with the provided transaction ID and transaction type. It takes the following positional arguments
- Transaction ID
- Transaction Type
pinelabs.payment.fetch("650acb67d3752", 3).then((data) => {
console.log(data)
});
Success Response
{
"ppc_MerchantID": "106600",
"ppc_MerchantAccessCode": "bcf441be-411b-46a1-aa88-c6e852a7d68c",
"ppc_PinePGTxnStatus": "7",
"ppc_TransactionCompletionDateTime": "20\/09\/2023 04:07:52 PM",
"ppc_UniqueMerchantTxnID": "650acb67d3752",
"ppc_Amount": "1000",
"ppc_TxnResponseCode": "1",
"ppc_TxnResponseMessage": "SUCCESS",
"ppc_PinePGTransactionID": "12069839",
"ppc_CapturedAmount": "1000",
"ppc_RefundedAmount": "0",
"ppc_AcquirerName": "BILLDESK",
"ppc_DIA_SECRET": "D640CFF0FCB8D42B74B1AFD19D97A375DAF174CCBE9555E40CC6236964928896",
"ppc_DIA_SECRET_TYPE": "SHA256",
"ppc_PaymentMode": "3",
"ppc_Parent_TxnStatus": "4",
"ppc_ParentTxnResponseCode": "1",
"ppc_ParentTxnResponseMessage": "SUCCESS",
"ppc_CustomerMobile": "7737291210",
"ppc_UdfField1": "",
"ppc_UdfField2": "",
"ppc_UdfField3": "",
"ppc_UdfField4": "",
"ppc_AcquirerResponseCode": "0300",
"ppc_AcquirerResponseMessage": "NA"
}
Failure Response
{
"ppc_MerchantID": "106600",
"ppc_MerchantAccessCode": "bcf441be-411b-46a1-aa88-c6e852a7d68c",
"ppc_PinePGTxnStatus": "-6",
"ppc_TransactionCompletionDateTime": "21\/09\/2023 11:29:48 PM",
"ppc_UniqueMerchantTxnID": "106600_2109202323294890763",
"ppc_TxnResponseCode": "-40",
"ppc_TxnResponseMessage": "INVALID DATA",
"ppc_CapturedAmount": "0",
"ppc_RefundedAmount": "0",
"ppc_DIA_SECRET": "4B9DD62C1CE94C354E368A2DA1C51C2E8ED16ABDC46414B8AAA60F378CDCE390",
"ppc_DIA_SECRET_TYPE": "SHA256"
}
Incorrect Merchant Details
"IP Access Denied"
EMI Calculator
Using the instance of the SDK we created above we will call the .calculate()
method on the emi
interface for
fetching
offers for EMI with the provided product details. It takes the following positional arguments
- Transaction Data
- Product Details
const txn_data = {
amount_in_paisa: '1000',
}
const productsDetail = [
{
"product_code": "testproduct02",
"product_amount": 10000
}
];
const res = pinelabs.emi.calculate(txn_data, productsDetail).then((data) => {
console.log(data)
});
Success Response
{
"issuer": [
{
"list_emi_tenure": [
{
"offer_scheme": {
"product_details": [
{
"schemes": [],
"product_code": "testproduct02",
"product_amount": 10000,
"subvention_cashback_discount": 0,
"product_discount": 0,
"subvention_cashback_discount_percentage": 0,
"product_discount_percentage": 0,
"subvention_type": 3,
"bank_interest_rate_percentage": 150000,
"bank_interest_rate": 251
}
],
"emi_scheme": {
"scheme_id": 48040,
"program_type": 105,
"is_scheme_valid": true
}
},
"tenure_id": "3",
"tenure_in_month": "3",
"monthly_installment": 3417,
"bank_interest_rate": 150000,
"interest_pay_to_bank": 251,
"total_offerred_discount_cashback_amount": 0,
"loan_amount": 10000,
"auth_amount": 10000
},
{
"offer_scheme": {
"product_details": [
{
"schemes": [],
"product_code": "testproduct02",
"product_amount": 10000,
"subvention_cashback_discount": 0,
"product_discount": 0,
"subvention_cashback_discount_percentage": 0,
"product_discount_percentage": 0,
"subvention_type": 3,
"bank_interest_rate_percentage": 150000,
"bank_interest_rate": 440
}
],
"emi_scheme": {
"scheme_id": 48040,
"program_type": 105,
"is_scheme_valid": true
}
},
"tenure_id": "6",
"tenure_in_month": "6",
"monthly_installment": 1740,
"bank_interest_rate": 150000,
"interest_pay_to_bank": 440,
"total_offerred_discount_cashback_amount": 0,
"loan_amount": 10000,
"auth_amount": 10000
}
],
"issuer_name": "HDFC",
"is_debit_emi_issuer": false
}
],
"response_code": 1,
"response_message": "SUCCESS"
}
Failure Response
Fatal error: Uncaught Exception: INVALID DATA,MISMATCH_IN_TOTAL_CART_AMOUNT_AND_TOTAL_PRODUCT_AMOUNT
Verify Hash
Using the instance of the SDK we created above we will call the .verify()
method on the hash
interface to verify
a hash received in the response of callback and webhooks. It takes the following positional arguments
- Hash Received in Response (
DIA_SECRET
) - Response Received ( Not including
DIA_SECRET
andDIA_SECRET_TYPE
)
const isVerified = pinelabs.hash.verify("D640CFF0FCB8D42B74B1AFD19D97A375DAF174CCBE9555E40CC6236964928896", response);
console.log(isVerified);
Integration Best Practices
Best practices to put into effect for a smooth and secure integration with Plural:
- Signature Verification to avoid data tampering: This is a mandatory step to confirm the authenticity of the details returned to you on the return URL for successful payments.
- Convert the response received on the return URL into a string (remove secret and secret_type params)
- Sort the string alphabetically
- Hash the payload with your secret key using SHA256
- Match the generated signature with the one received in the response from Plural
- Check payment status before providing services: Check if the payment status is in the success state .i.e. : ppc_Parent_TxnStatus = 4 and ppc_ParentTxnResponseCode = 1 before providing the services to the customers
- One Inquiry API call (Fetch payment using ppc_UniqueMerchantTxnID) right after the Transaction
- Run Inquiry API periodically for the payments in initiated state
- Webhook Implementation: Implement webhooks to avoid callback failures (drop offs due to connectivity/network issues)
- Payment.captured
- Payment.failed
- TLS Version We support TLS_v_1.2 and above which is strongly recommended. Kindly ensure you are using higher TLS versions to avoid any transaction failures.
Note
Please note no additional charges like TDR, GST, etc are handled in our SDKs and the same need to be manually handled at the merchant end.