Capturing Card Data
The PayU payment form presents card payments as one of the available options for buyers to complete their transactions. However if you want save card information for future use, you have to use the Secure Form.
Secure Form is a customizable form hosted by PayU that can be integrated into your website through an iframe. When customers enter their card details on the Secure Form, this information is securely transmitted to PayU, where it undergoes tokenization before being returned in the form of a unique token. Utilizing this approach ensures optimal protection for customer card data and helps you comply with PCI DSS regulations.
When using Secure Form you should display text provided in the Disclosure Obligations section.
For more details on the tokenization process and how to use tokens effectively, please refer to Card Tokenization section.
Secure Form Examples
- Preview
- HTML
- Javascript
- CSS
Single Input Window Secure Form Example
<script
type="text/javascript"
src="https://secure.payu.com/javascript/sdk"
></script>
<section class="container">
<div class="card-container">
<div class="payu-card-form" id="payu-card"></div>
</div>
<button id="tokenizeButton">Tokenize</button>
<div id="responseTokenize"></div>
</section>
var optionsForms = {
style: {
basic: {
fontSize: "18px",
},
},
lang: "pl",
};
var renderError = function (element, errors) {
element.className = "response-error";
var messages = [];
errors.forEach(function (error) {
messages.push(error.message);
});
element.innerText = messages.join(", ");
};
var renderSuccess = function (element, msg) {
element.className = "response-success";
element.innerText = msg;
};
//initialize the SDK by providing your POS ID and create secureForms object
var payuSdkForms = PayU("393823");
var secureForms = payuSdkForms.secureForms();
//create the form by providing type and options
var card = secureForms.add("card", optionsForms);
//render the form in selected element
card.render("#payu-card");
var tokenizeButton = document.getElementById("tokenizeButton");
var responseElement = document.getElementById("responseTokenize");
tokenizeButton.addEventListener("click", function () {
responseElement.innerText = "";
try {
payuSdkForms.tokenize("SINGLE").then(function (result) {
//example for SINGLE type token
result.status === "SUCCESS"
? renderSuccess(responseElement, result.body.token) //pass the token to your back-end and charge it
: renderError(responseElement, result.error.messages); //check the business error type and messages and display appropriate information to the user
});
} catch (e) {
console.log(e); // technical errors
}
});
.container * {
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
color: #ffffff;
}
.container {
text-align: center;
width: 420px;
margin: 20px auto 10px;
display: block;
border-radius: 5px;
box-sizing: border-box;
}
.card-container {
width: 100%;
margin: 0 auto;
border-radius: 6px;
padding: 10px;
background: rgb(2, 0, 60);
text-align: left;
box-sizing: border-box;
}
.payu-card-form {
background-color: #ffffff;
padding: 5px;
border-radius: 4px;
}
button {
border: none;
background: #438f29;
padding: 8px 15px;
margin: 10px auto;
cursor: pointer;
}
.response-success {
color: #438f29;
}
.response-error {
color: #990000;
}
- Preview
- HTML
- Javascript
- CSS
Multiple Input Windows Secure Form Example
<script
type="text/javascript"
src="https://secure.payu.com/javascript/sdk"
></script>
<section class="container">
<div class="card-container">
<aside>Card Number</aside>
<div class="payu-card-form" id="payu-card-number"></div>
<div class="card-details clearfix">
<div class="expiration">
<aside>Valid Thru</aside>
<div class="payu-card-form" id="payu-card-date"></div>
</div>
<div class="cvv">
<aside>CVV</aside>
<div class="payu-card-form" id="payu-card-cvv"></div>
</div>
</div>
</div>
<button id="tokenizeButton">Tokenize</button>
<div id="responseTokenize"></div>
</section>
var optionsForms = {
cardIcon: true,
style: {
basic: {
fontSize: "24px",
},
},
placeholder: {
number: "",
date: "MM/YY",
cvv: "",
},
lang: "pl",
};
var renderError = function (element, errors) {
element.className = "response-error";
var messages = [];
errors.forEach(function (error) {
messages.push(error.message);
});
element.innerText = messages.join(", ");
};
var renderSuccess = function (element, msg) {
element.className = "response-success";
element.innerText = msg;
};
//initialize the SDK by providing your POS ID and create secureForms object
var payuSdkForms = PayU("393823");
var secureForms = payuSdkForms.secureForms();
//create the forms by providing type and options
var cardNumber = secureForms.add("number", optionsForms);
var cardDate = secureForms.add("date", optionsForms);
var cardCvv = secureForms.add("cvv", optionsForms);
//render the form in selected element
cardNumber.render("#payu-card-number");
cardDate.render("#payu-card-date");
cardCvv.render("#payu-card-cvv");
var tokenizeButton = document.getElementById("tokenizeButton");
var responseElement = document.getElementById("responseTokenize");
tokenizeButton.addEventListener("click", function () {
responseElement.innerText = "";
try {
////tokenize the card (communicate with PayU server)
payuSdkForms.tokenize("SINGLE").then(function (result) {
// example for SINGLE type token
result.status === "SUCCESS"
? renderSuccess(responseElement, result.body.token) //pass the token to your back-end and charge it
: renderError(responseElement, result.error.messages); //check the business error type and messages and display appropriate information to the user
});
} catch (e) {
console.log(e); // technical errors
}
});
.container * {
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
color: #ffffff;
}
.container {
text-align: center;
width: 420px;
margin: 20px auto 10px;
display: block;
border-radius: 5px;
box-sizing: border-box;
}
.card-container {
width: 100%;
margin: 0 auto;
border-radius: 6px;
padding: 10px;
background: rgb(2, 0, 60);
text-align: left;
box-sizing: border-box;
}
.card-container aside {
padding-bottom: 6px;
}
.payu-card-form {
background-color: #ffffff;
padding: 5px;
border-radius: 4px;
}
.card-details {
clear: both;
overflow: auto;
margin-top: 10px;
}
.card-details .expiration {
width: 50%;
float: left;
padding-right: 5%;
}
.card-details .cvv {
width: 45%;
float: left;
}
button {
border: none;
background: #438f29;
padding: 8px 15px;
margin: 10px auto;
cursor: pointer;
}
.response-success {
color: #438f29;
}
.response-error {
color: #990000;
}
Typescript
If you use Typescript
in your project, just add a types definition to your project.
npm install --save @types/payu-emea-sdk
SDK Documentation
The following description refers to methods and objects available in browser-side JavaScript library, contained in JS SDK.
Add JS SDK script to every page you want to use Secure Form on. It should always be loaded from the PayU server. You mustn't load it from your own server and then attach it to the package that is being built at the moment.
- Production
- Sandbox
<script type="text/javascript" src="https://secure.payu.com/javascript/sdk"></script>
<script type="text/javascript" src="https://secure.snd.payu.com/javascript/sdk"></script>
- Example
var payu = PayU("393823");
Creates SecureForms instance. It will be possible to add SecureForm elements on an object created this way.
SecureForms Options Instance. More information about individual options in Secure Forms Instance Options section.
Occurs when trying to create another SecureForms instance. If you want to append more than one card form to your page, create a separate instance of JS SDK for each one of them.
- Example
var secureForms = payu.secureForms();
Request for card token creation with use of created SecureForm fields.
Possible Values (default value - SINGLE) | |
---|---|
SINGLE | Card not saved - token with short lifespan (11 minutes). |
SINGLE_LONGTERM | Card not saved. |
MULTI | Card saved - multi-use token will be returned after the it is charged via REST API. |
Field | Description |
---|---|
status | Tokenization status:
|
body | Only for SUCCESS status. Object contains tokenization information. |
error | Only for ERROR status. Object with messages array which contains error information. Details can be found in Errors section. |
correlationId | Only for ERROR status. |
- Example
{
"status": "SUCCESS",
"body": {
"token": "TOK_1JOQVU5KJNOV4c4O8UbZySwcfBdS",
"mask": "444433******1111"
}
}
card
form or number
, date
and cvv
type forms.- Example
var secureForms = payu.secureForms();
cvv
.refReqId
parameter from redirectUri
field, from the response. You can use extractRefReqId method to get refReqId
from the URL. If you are redirected to the page after 3DS is executed, you can retrieve refReqId
parameter from URL. URL example:
https://address.page/summary/?statusCode=WARNING_CONTINUE_CVV&refReqId=7b09781ee6a3303cc86712fce16fe030
Field | Description |
---|---|
status | CVV sending status:
|
error | Only for ERROR status. Object containing error information. Details can be found in Errors section. |
correlationId | Only for ERROR status. |
- Example
{
"status": "SUCCESS"
}
cvv
form is required.- Example
payu.sendCvv("7b09781ee6a3303cc86712fce16fe030");
refReqId
parameter from the URL.- Example
var refReqId = payu.extractRefReqId(
'https://secure.payu.com/cpm/threeds/proxy?refReqId=7b09781ee6a3303cc86712fce16fe030"'
);
Possible Values (default value - card) | |
---|---|
card | Complete card data form (card number, expiration date, CVV). |
number | Card number form. |
date | Card expiration date form. |
cvv | CVV form. |
aria-label
) for the form fields.message
array contains details about errors.card
when another number
, date
or cvv
form was already added. It also occurs in the opposite situation while trying to add number
, date
or cvv
form when card
form was already added. message
array contains details about errors.- Example
var cardNumberForm = secureForms.add("number");
selector
parameter was no specified or is empty.selector
parameter is not of the string type.appendChild
method is not implemented or it is an input element).- Example
cardNumberForm.render("#cardNumberForm");
options
parameter is the same as options parameter in the add method. New options are overriding the existing ones, lack of an option does not remove existing one.- Example
cardNumberForm.update({ lang: "en" });
Possible Values | |
---|---|
ready | Emitted when the form is displayed. |
focus | Emitted when the form gains focus. |
blur | Emitted when the form loses focus. |
change | Emitted when the value of the form is changed. |
callback
parameter is not a function.- Example
cardNumberForm
.on("ready", function () {
// form ready
})
.on("focus", function () {
// form activated
})
.on("blur", function () {
// form deactivated
})
.on("change", function (body) {
// value of the form has changed
});
- Example
cardForm.clear();
- Example
cardForm.focus();
- Example
cardForm.remove();
Options
Secure Forms Instance
All parameters are checked for their type and values correctness. Unknown and invalid parameters are ignored without information about error.
Parameter | Type | Description |
---|---|---|
fonts | array | Custom fonts for forms. |
lang | string | Two-character language code. Available languages: bg , cs , da , de , el , en , es , et , fi , fr , hr , hu , it , lt , lv , nl , pl , pt , ro , ru , sk , sl , sr , sv , tr , uk . If there is no language specified, it is retrieved from the browser. In the case of an unsupported language, the en value is used. |
Below is a list of the objects defining additional fonts, which
will be added to every form using @font-face
.
Permitted values: [-_a-zA-Z0-9 ]+
Permitted values: url(URL) format([collection|embedded-opentype|opentype|svg|truetype|woff|woff2])
May contain multiple entries separated by coma.
Permitted values:
(auto|block|swap|fallback|optional)
Permitted values: (normal|italic|oblique)
Permitted values: ([1-9]00|normal|bold)
- Example
{
fonts: [
{
family: "Own Font",
src: 'url(https://ownulr.com/own_font_normal.woff2) format("woff2"), url(https://ownulr.com/own_font_normal.woff) format("woff2)',
style: "normal",
weight: 400,
},
{
family: "Own Font",
src: 'url(https://ownulr.com/own_font_bold.woff2) format("woff2")',
style: "normal",
weight: "bold",
},
];
}
Form
All parameters are optional and are checked for their type, and values correctness. Unknown and invalid parameters are ignored without information about error.
aria-label
) for the form fields. If the parameter is missing, the text is added according to the current language.Your own placeholder text in the form input fields.
You own iframe title. If the parameter is missing, the title is added according to the current language.
Two-character language code. Available languages are: bg
, cs
, da
, de
, el
, en
, es
, et
, fi
, fr
, hr
, hu
, it
, lt
, lv
, nl
, pl
, pt
, ro
, ru
, sk
, sl
, sr
, sv
, tr
, uk
. Parameter is used when the language was not specified in the Secure Forms Instance. If language is not specified, it is
retrieved from the browser. For languages that are not
supported, en
is used.
When set to true
form will be blocked,
otherwise it will be active.
When set to false
, card icon, next to card
number input field, is not displayed, otherwise it is
displayed.
- Example
{
style: {
basic: {
fontColor: '#0000FF'
fontSize: '26px'
fontWeight: '700'
},
invalid: {
fontColor: '#990000'
},
placeholder: {
fontColor: '#aaaaaa'
}
},
placeholder: {
number: '',
date: 'MM / YY',
cvv: ''
},
cardIcon: true,
lang: 'en',
disabled: false
}
Groups styles for different form behaviours in objects. Each group has its permitted styles.
Permitted styles: fontColor
fontSize
fontFamily
fontWeight
letterSpacing
Form styles.
Permitted styles: fontColor
fontWeight
Styles for the form with invalid values.
Permitted styles: fontColor
fontWeight
Style for the form with active focus.
Permitted styles: fontColor
fontWeight
Styles for the form placeholders.
Permitted styles: fontColor
fontWeight
Styles for the disabled form.
Permitted values:
#[0-9a-f]{6}
font color
Permitted values: (\d+|\d*.\d+)(px|em|%)
font
size
Permitted values: [0-9a-z-\s,"']{1, 150}
font
family
Permitted values:
([1-9]00|normal|bold|lighter|bolder|inherit|initial|unset)
font weight
Permitted values:
normal|(-?)(\d+|\d*.\d+)(px|em|%)
spacing
between letters
Placeholder text for the card number form.
Placeholder for the card expiration date form.
Events
Forms emit events to which you can attach your own callback using the on method.
This event is emitted after calling render method after the form is displayed.
This event is emitted when the value of the form is changed. Callback is called with one object parameter with the following structure:
Field | Description |
---|---|
empty | Indicates if the form is empty. Possible values:
|
error | Indicates if the data entered in the form is correct. Possible values:
validation . Details can be found in Errors section. |
brand | Only for form with the type number . Contains information about the brand of the card.Possible values:
|
Dynamic Classes
Dynamic classes are added to the element in which the form is displayed.
Class | Description |
---|---|
payu-secure-form-empty | Set when form is empty. |
payu-secure-form-focus | Set when for is active (in focus). |
payu-secure-form-invalid | Set when data entered into the form are invalid. |
Errors
error
object contains an array of objects (messages
), which
contain detailed information about the errors.
- Error Object Example
{
"status": "ERROR",
"correlationId": "",
"error": {
"messages": [
{
"type": "validation",
"code": "error.validation.expDate.value",
"parameters": {},
"message": "Card expiration date is invalid"
},
{
"type": "validation",
"code": "error.validation.cvv.empty",
"parameters": {},
"message": "Empty CVV"
}
]
}
}
Highlighted above is one of the objects inside the messages
array with the error details.
Field | Description |
---|---|
type | Error type. Possible values:
|
code | Error code. |
source | Element with possible error (only for errors with validate type). Possible values: card , number , date , cvv . |
message | Error description in the language of the form. In case of the technical type errors, description in always in english. |
parameters | Object containing changeable error fragments. |
Error Code | Type | Description |
---|---|---|
error.validation.card.empty | validate | Empty card number. |
error.validation.card.length | validate | Invalid card number length. |
error.validation.card.number | validate | Invalid card number. |
error.validation.card.unsupported | validate | Card type is not supported. Supported card types: Visa, Mastercard and Maestro. |
error.validation.expDate.empty | validate | Empty expiration date. |
error.validation.expDate.past | validate | Expiration date is in the past. |
error.validation.expDate.value | validate | Incorrect expiration date. |
error.validation.cvv.empty | validate | Empty CVV. |
error.validation.cvv.value | validate | Invalid CVV. |
error.tokenization | technical | Error has occured while trying to tokenize the card. Error information can be found in the parameters object in the error field. |
error.send.cvv | technical | Error has occured while sending CVV. Error information can be found in the parameters</code object in the |
error.network | technical | A network communication error has occured. Error information can be found in the parameters object in the error field. |
FAQ
I need translation into xx language.
Elements that are translated are placeholder texts and error messages. Both elements you can translate freely on your own.
In case of placeholder elements we passed them in the placeholder
parameter in the form options e.g.
{
"placeholder": {
"number": "Kartennummer",
"date": "MM / JJ",
"cvv": "CVV"
}
}
In case of errors, we display message based on the error codes e.g.
var errors = {
messages: [
{
type: "validation",
code: "error.validation.card.number",
parameters: {},
message: "Nieprawidłowy numer karty",
},
],
};
var translations = {
"error.validation.card.number": "Ungültige Kartennummer",
};
var showError = function () {
errors.messages.forEach(function (message) {
console.log(translations[message.code]); // show error message
});
};
Someone has resized the browser window or flipped the phone. I want to change the font size and disable the card brand icon, so that the form fits completely on the page.
While resizing the browser window you should use the update method to update form options e.g.
// initializing code of JS SDK and SecureForms has been omitted
var cardNumber = secureForms.add("number");
var options = {
current: "gt500",
profiles: {
gt500: {
style: {
basic: {
fontSize: "18px",
},
},
cardIcon: true,
},
lt500: {
style: {
basic: {
fontSize: "14px",
},
},
cardIcon: false,
},
},
};
// window size change
window.addEventListener("resize", function () {
var newProfile = window.innerWidth > 500 ? "gt500" : "lt500";
if (newProfile !== options.current) {
options.current = newProfile;
// form options update
cardNumber.update(options.profiles[options.current]);
}
});