payu-blik-pl

Lightweight BLIK, Google Pay, Apple Pay payment library for PAYU customers

Usage no npm install needed!

<script type="module">
  import payuBlikPl from 'https://cdn.skypack.dev/payu-blik-pl';
</script>

README

A simple and lightweight PayU BLIK and Google Pay payment facility

Installation

npm install payu-blik-pl

Usage

To use:

  • simply require module
  • create connector
  • call payWithBLIK() method or payWithGooglePay() method

Create a connector

var PayUBlikModule = require('payu-blik-pl');
// these is the minimal set of configuration options, you MUST provide your clientId and secret that was given to you when you registered to PayU
var initOptions = {
    clientId: 111111,
  clientSecret: '7261414absecrete1d3080a8c0751928',
  clientSecondKey: 'zzz305d1e4a1507931d0eae070fbbxxx', 
  apiNotificationURL: "https://your.eshop.com/notify"
};
var payConnector = PayUBlikModule.createPayUConnector(initOptions);
// from now on you can request BLIK payments

Invoke BLIK payments

// prepare order data, i.e. what is being paid for and how much
var orderData = {
    "currencyCode": "PLN",
    "totalAmount": "31000",
    "description": "Transakcja testowa",
    "notifyUrl": "https://your.eshop.com/notify",
    "customerIp": "127.0.0.1",
    "products": [
        {
            "name": "Wireless Mouse for Laptop",
            "unitPrice": "21000",
            "quantity": "1"
        }
    ]
}
//...
// make a BLIK payment

// this is the BLIK code that is entered by the customer
var BLIKCode = 712898;

var customerEmail = 'test@test.pl';
var customerExternalId = 'myCRMId1'
payConnector.payWithBLIK( BLIKCode, customerEmail, customerExternalId, orderData).then(response=>{
  // here one can check on the response if the payment was a success 
    console.log('There was a valid response', response);
}).catch(error=>{
  // this is called when any business related error has happened (such as unauthorized payment attempt)
    console.log('Failed to hanle payment', error);
});

Invoke Google Pay payments


//...
// handle Google Pay flow ( https://developers.google.com/pay/api/web/guides/tutorial ) until you get Token Google Pay (example below)
{
    "signature": "MEUCIQDY3wBQyHB4sZcktRoJXKxm+OLcjHzCvdDeGn23oX0kkwIgKznRFZZL+sDMv1b5cuD+YurXMZraYBsr9hbravVY5Ro\u003d",
    "protocolVersion": "ECv1",
    "signedMessage": "{\"encryptedMessage\":\"cI87tLqzqTGyCFnMMCVWcTHw3xhYIK+CEnuQ74K+nlLpCgOlfpScib9jds4sxDtN6CunCqCSMfd/3yHeeRy6aCx1yyqcT4ey6NueeBznprJpkmVVgI1JHWLQt4hzAXMUAcYASYLOabKP9fUZvHkOBDytD531jpzNXa+Spc/zrpGzFKx2C4VU9sC95q9i+ey+kr7ZMNVCOFJPWXu7lKZ105IOOqozJ6/70MKmxP3jM89eeq+/19QnyHjQLXfnQPvQjiUJKGCcRKDLlrb3XoY5ZUUzGfN5eZCLzCVg0hWEbwU+6J7KWYJyW+Wr1r8bagN9zWsrMKhDpsQbHfyzb+yBzFUoxeUgL4a7FeVvEllIcHtqsvTCf6FENV20aF5VLDv5qzUkV+PzTAIbFEuabA0God9UbVCVVv7nM8QFzvRPhzYYFVFTn4JHvL2qZ4pAR9lE+w\\u003d\\u003d\",\"ephemeralPublicKey\":\"BPHLC4sBHpenY1M0ixmiDMuWJTaTJOqggRUwtgBJMcBp28VsxHD7zPI7985x4F5EjMP5y8j/cuUzbe/cGPjOKGk\\u003d\",\"tag\":\"RaXrPOUuc5iw3oxDa0C2MOjaKxgxIRQvwOspmtFV0zU\\u003d\"}"
}


// since You have received Token Google Pay you can make a Google Pay payment

// prepare order data, i.e. what is being paid for and how much
var orderData = {
    "currencyCode": "PLN",
    "totalAmount": "31000",
    "description": "Transakcja testowa",
    "notifyUrl": "https://your.eshop.com/notify",
    "customerIp": "127.0.0.1",
    "products": [
        {
            "name": "Wireless Mouse for Laptop",
            "unitPrice": "21000",
            "quantity": "1"
        }
    ]
}

// this is the Token Google Pay received from Google Pay (notice that this is a string)
var gPayToken = "{"signature":"MEUCIEJoMGDQ3eIAty6A0IHFaVOU3PEp0tE2NVwuQdJU7hGDAiEAk/P8so4D0riPSaPaYDK7LlS/LSLWku35cDpqOLolbt4\u003d","protocolVersion":"ECv1","signedMessage":"{\"encryptedMessage\":\"CqgxuNJ5GPD05mvx2vJ1TljNIYxoKeTNVOowjJQsgwHqKmN+nlBJ4C/b0RxiGMiNwb3xxzlnLt13fnszi7sawSuQ0mY2go/XE5qTukgFSrUKjKON044Np5b5suNnS0LCynNAme2OJGl3JJ5nMNTq+mBN82klA+LKGg6EKSmLBGIEaShFeqxGOXxpqNuzmnXoW4zMlXwwNasKM48cVOC2AqW7svipxDskZbD7dLuwFzJowZq3v//Yh5VDR1ktZRsjqRhU7DDcZkA33S6oWK1Rx7DTpMeSDtmkgSd7Da7YrIM1WCLFr/4cljUXQTAY9+hbf+yWS4a4rmg5qLZej6RGDVySSvyivZwSLBy5olxNYUxHVMBGNj/ia7Adzzh6REr0XBogvXpzOdf4CzrJllvusRxlwZbSnNLUW1PawdW/OtDEDVFZ+id3vXFILvYjgXLV7g\\u003d\\u003d\",\"ephemeralPublicKey\":\"BIBCdO1fyvbl2Jk/Q4yGICJarDVbzT0N3737T+McJ089lVv0zjdKgyqYhznR3saKK4e5Qc4VLJTNRTKin3stYFs\\u003d\",\"tag\":\"C4cxIqJF1iPKWI9vPN+URR3GyFo5l34Ks+BPyFQwtCg\\u003d\"}"}";

var customerEmail = 'test@test.pl';
var customerExternalId = 'myCRMId1'
payConnector.payWithGooglePay( gPayToken, customerEmail, customerExternalId, orderData).then(response=>{
  // here one can check on the response if the payment was a success 
    console.log('There was a valid response', response);
}).catch(error=>{
  // this is called when any business related error has happened (such as unauthorized payment attempt)
    console.log('Failed to hanle payment', error);
});

Invoke Apple Pay payments


//...
// handle Apple Pay flow ( https://applepaydemo.apple.com/ ) until you get Apple Payment Token (example below)
{
  "version": "EC_v1",
  "data": "DjI8Ez7nPhVo742aGEzABz/TfxCPt9LSdf2/h+0xIgVJbi3fQqd4lv3ogoTI3SQ7vZrDAWI8g2lbd5sflXBHc0z+wSeybsCcqZB3n1edRFXU7+6DYmdhFFWWCejwUc6XZWmsSaVNEQf+Kc0SeYrj8Eskdapj8bYX/QXxXSPqS4IKSjB+f3O0gUXSq7LK/jA9dl+BbWW0l3gXERU6n5rcYndO5rnjiwNUpnm7EMIMfNU+IPbsubpL82kbL2MdMJB1grel03J4JKld6G0pFSmjR2mF/xBY/yKkADRhoQkVlDRicuKVMpdRXXbIQjw/yRkLv/u8iy1wXI5YmEBB+W4QpPYsuxys94gMPaKhcaEK/OaT099aFrNBezbuLMTcTzbhXOpPwWn9pkAK0eZNOQ==",
  "signature": "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",
  "header": {
    "ephemeralPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZMzlWOx8Xo8pXlOvzYONy+gvUy59ZOeuCov3kzc7fESczZTyvmA9dU9AdVMFaYyfCXlMG5oedi3Wy4yubqfxtg==",
    "publicKeyHash": "xrJqUFO2jN5edGS8iETkfNXtwqnwSqRUUrQJBysFpZ8=",
    "transactionId": "aa0b77fbb4f64cd3e5deef65177938b2d836e0d7d93d58000d8d54cfca19ae13"
  }
}


// since You have received Apple Payment Token you can make an Apple Pay payment

// prepare order data, i.e. what is being paid for and how much
var orderData = {
    "currencyCode": "PLN",
    "totalAmount": "31000",
    "description": "Transakcja testowa",
    "notifyUrl": "https://your.eshop.com/notify",
    "customerIp": "127.0.0.1",
    "products": [
        {
            "name": "Wireless Mouse for Laptop",
            "unitPrice": "21000",
            "quantity": "1"
        }
    ]
}

// this is the Apple Payment Token received from Apple  Pay in the onPaymentAuthorized callback
var aPayToken = ....

var customerEmail = 'test@test.pl';
var customerExternalId = 'myCRMId1'
payConnector.payWithApplePay( aPayToken, customerEmail, customerExternalId, orderData).then(response=>{
  // here one can check on the response if the payment was a success 
    console.log('There was a valid response', response);
}).catch(error=>{
  // this is called when any business related error has happened (such as unauthorized payment attempt)
    console.log('Failed to hanle payment', error);
});

Response structure

// sample success response
{ 
  status: { 
    message: 'Created', 
    code: 201 
  },
  body:{ 
    orderId: 'XJVLWS4WSS190531GUEST000P01',
    status: { statusCode: 'SUCCESS' } 
  } 
}

Notification signature validation

// get signature header
var signatureHeader = req.header('OpenPayu-Signature');
// get message body
var messageBody = req.body;
// validate if the notification is original and valid
var isValid = payConnector.validateNotificationSignature(signatureHeader, messageBody);

Formdata signature generation



// generate order form fields signature
var signatureObject = payConnector.generateFormSignature([
    { field: "customerIp", value: '123.123.123.123' },
    { field: "merchantPosId", value: payConnector.initOptions.clientId },
    { field: "description", value: 'Order description' },
    { field: "totalAmount", value: 200 },
    { field: "currencyCode", value: 'PLN' },
    { field: "products[0].name", value: 'Product 1' },
    { field: "products[0].unitPrice", value: 200 },
    { field: "products[0].quantity", value: 1 },
    { field: "notifyUrl", value: 'http://shop.url/notify' },
    { field: "continueUrl", value: 'http://shop.url/continue' }
])

// now one can add hidden field with signature
var fieldName = signatureObject.name;
var signature = signatureObject.signature;

Changelog

  • v1.2.1 - added Order Form Fields signature generation
  • v1.2.0 - added Apple Pay integration
  • v1.1.3 - added Google Pay integration
  • v1.0.18 - added token expiration handling
  • v1.0.16 - functional fixes
  • v1.0.10 - added method for notification signature validation
  • v1.0.9 - added transaction id
  • v1.0.7 - added buyer email
  • v1.0.6 - readme fixes
  • v1.0.5 - single item blik payment added
  • v1.0.3 - readme fixes
  • v1.0.2 - readme fixes
  • v1.0.1 - initial fixes
  • v1.0.0 - initial version