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 to save card information for future use, you have to use the Secure Form.
The 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. This approach ensures optimal protection of customer card data and helps you comply with PCI DSS regulations.
When using the Secure Form, you should display the text provided in the Disclosure Obligations section.
For more details on the tokenization process and how to use tokens effectively, please refer to the 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, add the type definitions:
npm install --save @types/payu-emea-sdk
SDK Documentation
The following description refers to the methods and objects available in the browser-side JavaScript library included in the JS SDK.
Add the JS SDK script to every page on which you want to use the Secure Form. Always load it from the PayU server. Do not host it on your own server or bundle it with your application package.
- 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>
posId parameter, which can be found in your management panel. In the following example, we used a test POS identifier from the Sandbox environment.posId parameter is not specified or is empty.https nor the file protocol and is not loaded from localhost, 127.0.0.1 or 0.0.0.0. During implementation, you can enable developer mode in the options parameter.- Example
var payu = PayU('393823')
Creates a SecureForms instance, to which you can add SecureForm elements.
SecureForms instance options. For more information about individual options, see the Secure Forms Instance Options section.
Occurs when trying to create another SecureForms instance. If you want to add more than one card form to your page, create a separate JS SDK instance for each of them.
- Example
var secureForms = payu.secureForms()
Requests creation of a card token using the SecureForm fields you created.
| 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 it is charged via REST API. |
| Field | Description |
|---|---|
status | Tokenization status:
|
body | Only for SUCCESS status. The object contains tokenization information. |
error | Only for ERROR status. Object with messages array which contains error information. Details can be found in the Errors section. |
correlationId | Only for ERROR status. |
- Example
{
"status": "SUCCESS",
"body": {
"token": "TOK_1JOQVU5KJNOV4c4O8UbZySwcfBdS",
"mask": "444433******1111"
}
}
type parameter.card form or number, date and cvv forms are required.- Example
payu.tokenize()
cvv.refReqId parameter from the redirectUri field of the response. You can use the extractRefReqId method to get refReqId from the URL. If you are redirected to the page after 3DS is executed, you can retrieve the refReqId parameter from the 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.refReqId value.- 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.type parameter.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')
querySelectorAll.selector parameter was not 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 the options parameter in the add method. New options override the existing ones; omitting an option does not remove its existing value.- 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 Options
All parameters are validated for type and value correctness. Unknown and invalid parameters are ignored without an error message.
| 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 commas.
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("woff")',
style: 'normal',
weight: 400,
},
{
family: 'Own Font',
src: 'url(https://ownulr.com/own_font_bold.woff2) format("woff2")',
style: 'normal',
weight: 'bold',
},
]
}
Form Options
All parameters are optional and are validated for type and value correctness. Unknown and invalid parameters are ignored without an error message.
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.
Your 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. The parameter is used when no language was specified in the Secure Forms Instance Options. If no language is specified, it is retrieved from the browser. For unsupported languages, en is used.
When set to true, the form is blocked; otherwise, it is active.
When set to false, the card icon next to the 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: ''
},
label: {
number: 'Card number',
date: 'Card expiration date',
cvv: 'CVV/CVC code'
},
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.
Accessibility text (aria-label) for the card number form.
Accessibility text (aria-label) for the card expiration date form.
aria-label) for the CVV form.Events
Forms emit events to which you can attach your own callback using the on method.
This event is emitted after the form is displayed following a call to the render method.
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 the Errors section. |
brand | Applies only to forms with the type number. Contains information about the brand of the card.Possible values:
|
length | Applies only to forms with the type number and when the error field is set to false. Contains information about the length of the card number. |
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 the form is active (in focus). |
payu-secure-form-invalid | Set when the data entered into the form is invalid. |
Errors
The error object contains the messages array of objects with 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"
}
]
}
}
The highlighted object is one of the elements of the messages array and contains the error details.
| Field | Description |
|---|---|
type | Error type. Possible values:
|
code | Error code. |
source | Element with possible error (only for errors with validation type). Possible values: card, number, date, cvv. |
message | Error description in the language of the form. For errors of the technical type, the description is always in English. |
parameters | Object containing changeable error fragments. |
| Error Code | Type | Description |
|---|---|---|
error.validation.card.empty | validation | Empty card number. |
error.validation.card.length | validation | Invalid card number length. |
error.validation.card.number | validation | Invalid card number. |
error.validation.card.unsupported | validation | Card type is not supported. Supported card types: Visa, Mastercard and Maestro. |
error.validation.expDate.empty | validation | Empty expiration date. |
error.validation.expDate.past | validation | Expiration date is in the past. |
error.validation.expDate.value | validation | Incorrect expiration date. |
error.validation.cvv.empty | validation | Empty CVV. |
error.validation.cvv.value | validation | Invalid CVV. |
error.tokenization | technical | Error has occurred 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 occurred while sending CVV. Error information can be found in the parameters object in the error field. |
error.network | technical | A network communication error has occurred. Error information can be found in the parameters object in the error field. |
FAQ
How do I translate the form into another language?
The translatable elements are placeholder texts and error messages. You can translate both on your own.
Placeholder texts are passed in the placeholder parameter in the form options, e.g.:
{
"placeholder": {
"number": "Kartennummer",
"date": "MM / JJ",
"cvv": "CVV"
}
}
Error messages are displayed based on 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
})
}
The browser window was resized or the phone was rotated. How do I change the font size and disable the card brand icon so that the form fits on the page?
When the browser window is resized, use the update method to update the 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])
}
})