Card Tokenization

1 Introduction

Card tokenization service is based on a transparent integration type which allows to accept card payments without redirecting users to a page hosted by the payment service provider. This integration type retains the security level and minimizes the PCI DSS compliance effort. It is also meant to give you more flexibility and increase conversion rates through better control over the payment process.

A payment flow is based on two steps - capturing card credentials in a secure way (front-end process) and then using them to create a payment transaction (back-end process). Card credentials are returned in the form of a token and a masked card number, therefore the Merchant never receives full card details.

Tokens received from PayU can be either single-use or multi-use. Multi-use tokens can be stored and used for future payments. Typically such functionality can be used by e.g. a merchant who has an extensive database of returning users – linking a user account with a multi-use token improves user experience, because the user no longer needs to enter card data each time.

PayU configuration

Single-use card tokens do not require additional configuration, however to enable multi-use tokens please contact PayU via your Account Manager.

Security requirements and recommendations

Before integrating the service, please take a look at the requirements and recommendations prepared by our security experts. It will help you protect yourself against frauds.

2 Integration overview

Tokenization without card storing:
  • implement the Secure Forms feature in your front-end
  • tokenize the card using SINGLE type in your front-end and pass it to your back-end
  • send Order request with the token from your back-end
Card storing process overview:
  • implement the Secure Forms feature in your front-end
  • tokenize the card using MULTI type in your front-end and pass it to your back-end
  • send Order request with the token and necessary customer details from your back-end
  • retrieve stored token(s) during subsequent checkout of this customer

Transparent payment with a single-use token (first payment):

Transparent payment with a multi-use token (second and next payments):

3 Secure Form

The Secure Form is the preferred solution as it eliminates the need to handle the sensitive card data on your website - all the data are inputted in an iframe with PayU hosted form.

Note: when using Secure Form you should display text provided in the Information Requirements section.

3.1 Examples

Single-use 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;
}
Example of individual fields as a separate forms.
<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;
}

3.2 Typescript

If you use Typescript in your project, just add a types definition to your project.

npm install --save @types/payu-emea-sdk

3.3 SDK documentation

The following description refers to methods and objects available in browser-side JavaScript library, contained in JS SDK.

Loading 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.

<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>

JS SDK instance creation

PayU(posId, options?)

You will need posId parameter, which can be found in your management panel. In the following example we used test POS identifier from the Sandbox environment.

Method parameters

posIdrequiredstring
Point of Sale identifier.
optionsoptionalobject
Instance options.
devboolean
Enables instance creation in the developer mode which allows you to operate on a site without HTTPS protocol.

Return

PayU instance.

Exceptions

posid.is.empty
Occurs when a JS SDK instance is created and posId parameter is not specified or empty.
non.https.integration
Occurs on JS SDK instance creation when the protocol of the page, on which SDK is loaded, is not https and file, and the page is not loaded from localhost: 127.0.0.1 or 0.0.0.0.
During the implementation process you can enable developer mode in the options parameter.
var payu = PayU('393823');

JS SDK instance methods

secureForms(options?)

Creates SecureForms instance.
It will be possible to add SecureForm elements on an object created this way.

Method parameters

optionsoptionalobject
SecureForms Options Instance. More information about individual options in Secure Forms Instance Options section.
fontsarray
Additional fonts for forms.

Return

SecureForms instance.

Exceptions

secure.forms.already.exists
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.
var secureForms = payu.secureForms();

tokenize(type?)

Request for card token creation with use of created SecureForm fields.

Method parameters

typeoptionalstring
Type of the created card token.
Possible values (default - 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.

Return

Promise, which resolves to the object containing the result.

Field Description
status Tokenization status:
  • SUCCESS - successful tokenization, result is available in body field;
  • ERROR - tokenization attempt ended in an error. The errors that occurred can be found in error field.
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.
{
    "status": "SUCCESS",
    "body": {
        "token": "TOK_1JOQVU5KJNOV4c4O8UbZySwcfBdS",
        "mask": "444433******1111"
    }
}

Exceptions

incorrect.token.type
Incorrect token type. Possible values can be found in type parameter description.
tokenize.not.possible
Tokenization not possible. Required type card form or number, date and cvv type forms.
var secureForms = payu.secureForms();

sendCvv(refReqId)

Sends a request for CVV. Works only when the form type is cvv.

Method parameters

refReqIdrequiredstring
If during card charging process PayU responds with WARNING_CONTINUE_CVV, you should retrieve 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

Return

Promise, which resolves to the object containing the result.

Field Description
status CVV sending status:
  • SUCCESS - CVV was sent successfully - it does not mean that CVV is correct,
  • ERROR - sending CVV attempt ended in an error. The errors that occurred can be found in the error field.
error Only for ERROR status. Object containing error information. Details can be found in Errors section.
correlationId Only for ERROR status.
{
    "status": "SUCCESS",
}

Exceptions

refReqId.is.empty
refReqId was not specified or is empty.
sendCvv.not.possible
Error has occurred while trying to send CVV. Only cvv form is required.
payu.sendCvv('7b09781ee6a3303cc86712fce16fe030');

extractRefReqId(url)

Auxiliary function used for retrieving refReqId parameter from the URL.

Method parameters

urlrequiredstring
URL address.

Return

refReqId.
var refReqId = payu.extractRefReqId('https://secure.payu.com/cpm/threeds/proxy?refReqId=7b09781ee6a3303cc86712fce16fe030"');

SecureForms instance methods

add(type?, options?)

Creates single-use instance of SecureForm form.

Method parameters

typeoptionalstring
Form type.
Possible values (default - card)
card Complete card data form (card number, expiration date, CVV).
number Card number form.
date Card expiration date form.
cvv CVV form.
optionsoptionalobject
Form options. For more information about individual options see Form options section.
styleobject
Your own form style.
placeholderobject
Your own placeholder text in fields of the form.
langstring
Language.
disabledboolean
Blocks a field.
cardIconboolean
Should card icon be displayed next to the card number input field.

Return

SecureForm Instance.

Exceptions

secure.form.incorrect.type
Invalid form type. Possible values can be found in type parameter description.
secure.form.exist.type [message]
Occurs when trying to add another form of specified type. [message] array contains details about errors.
secure.form.exist.other.type [message]
Occurs when trying to add form with type 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.
var cardNumberForm = secureForms.add('number');

SecureForm instance methods

render(selector)

Displays the form on the page.

Method parameters

selectorrequiredstring
Selector of the element in which the form will be displayed. Searching for element is done by querySelectorAll.

Return

Its own Secure Form instance.

Exceptions

element.selector.empty
selector parameter was no specified or is empty.
element.selector.not.string
selector parameter is not of the string type.
element.not.exists
Element do not exists on the page.
element.too.many.exists
There is more than one element on the page.
element.not.valid
Invalid element (appendChild method is not implemented or it is an input element).
element.contains.children
Element contains secondary items.
cardNumberForm.render('#cardNumberForm');

update(options)

Updates form options.

Method parameters

optionsrequiredobject
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.

Return

Its own SecureForm instance.
cardNumberForm.update({lang: 'en'});

on(event, callback)

Attaching your own callback to the event emitted by the form. You can find more information about the events in the event section.

Method parameters

eventrequiredstring
Event type
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.
callbackrequiredfunction
Funkcja zwrotna wywoływana po wyemitowaniu zdarzenia. Callback called after event is emitted.

Return

SecureForm instance

Exceptions

event.unknown
Unknown event type in event parameter.
event.callback.not.function
callback parameter is not a function.
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
    });

clear()

Removes data entered in the form.

Return

Its own SecureForm instance.
cardForm.clear();

focus()

Focuses the form.

Return

Its own SecureForm instance.
cardForm.clear();

remove()

Removes form from the page.

Return

Its own SecureForm instance.
cardForm.remove();

3.4 Options

3.4.1 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.

Fonts table

Contains list of objects defining additional fonts, which will be added to every form using @font-face.

family and src attributes are required.

Attribute Permitted values
family [-_a-zA-Z0-9 '"]+
src url(.*?) format(.*?) may contain multiple entries separated by coma
display (auto|block|swap|fallback|optional)
style (normal|italic|oblique)
weight ([1-9]00|normal|bold)
unicodeRange [-U+A-Fa-f0-9?, ]*
{
    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'
        }
    ]
}

3.4.2 Form

All parameters are checked for their type and values correctness. Unknown and invalid parameters are ignored without information about error.

Parameter Type Description
style object Your own form style.
placeholder object Your own placeholder text in the form input fields.
lang string Two-character language code. Available languages are: pl en cs sk.
If language is not specified, it is retrieved from the browser. For languages that are not supported, en is used.
disabled boolean When set to true form will be blocked, otherwise it will be active.
cardIcon boolean When set to false, card icon, next to card number input field, is not displayed, otherwise it is displayed.
{
    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
}

Style object

Groups styles for different form behaviours in objects. Each group has its permitted styles.

Styles group Permitted styles Description
basic fontColor fontSize fontFamily fontWeight letterSpacing Form styles
invalid fontColor fontWeight Styles for the form with invalid values.
focus fontColor fontWeight Style for the form with active focus.
placeholder fontColor fontWeight Styles for the form placeholders.
disabled fontColor fontWeight Styles for the disabled form.

Style

Style Descritpion Permitted values
fontColor font color #[0-9a-f]{6}
fontSize font size (\d+|\d*\.\d+)(px|em|%)
fontFamily font family [0-9a-z\-\s]{1,50}
fontWeight font weight ([1-9]00|normal|bold|lighter|bolder|inherit|initial|unset)
letterSpacing spacing between letters normal|(-?)(\d+|\d*\.\d+)(px|em|%)

Placeholder object

Field Type Description
number string Placeholder text for the card number form.
date string Placeholder for the card expiration date form.
cvv string Placeholderfor the card CVV form.

3.5 Events

Forms emit events to which you can attach your own callback using the on method.

Event ready

This event is emitted after calling render method after the form is displayed.

Event focus

This event is emitted when the form is activated.

Event blur

This event is emitted when the form is deactivated.

Event change

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: true or false.
error Indicates if the data entered in the form is correct.
Possible values: false when the form contains correct data or array of objects with errors.
Possible error type is validation. Details can be found in Errors section.
brand Only for type number form.
Contains information about the brand of the card. Possible values: visa, mastercard lub maestro .

3.6 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.

3.7 Errors

error object contains an array of objects (messages), which contain detailed information about the errors.

Error object in messages array

Field Description
type Error type. Possible values:
  • validate - when the source of the error is the validation of the form fields values,
  • technical - for other errors.
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 languageof the form. In case of the technical type errors, description in always in english.
parameters Object containing changeable error fragments.

Error list

Error code Description
validate type errors
error.validation.card.empty Empty card number.
error.validation.card.length Invalid card number length.
error.validation.card.number Invalid card number.
error.validation.card.unsupported Card type is not supported. Supported card types: Visa, Mastercard and Maestro.
error.validation.expDate.empty Empty expiration date.
error.validation.expDate.past Expiration date is in the past.
error.validation.expDate.value Incorrect expiration date.
error.validation.cvv.empty Empty CVV.
error.validation.cvv.value Invalid CVV.
technical type errors
error.tokenization 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 Error has occured while sending CVV. Error information can be found in the parameters object in the error field.
error.network A network communication error has occured. Error information can be found in the parameters object in the error field.
{
    "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"
            }
        ]
    }
}

3.8 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]);
    }
});

4 Widget

This solution is deprecated. For new integrations use the Secure Form instead. If you are already using the widget and need documentation, please contact us.

5 Your own form

This solution is deprecated. For new integrations use the Secure Form instead. If you are already using the form and need documentation, please contact us.

6 Device fingerprint

A device fingerprint is information collected about a remote computing device for the purpose of identification. Fingerprints can fully or partially identify devices or individual users

Fingerprint value is generated by static function Fingerprint2.get, which replaced new Fingerprint2().get. Beacuse of this the result will not be hashed anymore.

Needed libiraries can be found Here.

Usage:
            var options = {}
            Fingerprint2.get(options, function (components) {
              // components is array of {key: 'foo', value: 'component value'}
              ...
            })
            
            // or
            
            Fingerprint2.getPromise(options).then(function (components) {
              // components is array of {key: 'foo', value: 'component value'}
              ...
            })
          
For creating hash fingerprint you can use murmur hash function:
            Fingerprint2.get(options, function (components) {
              var values = components.map(function (component) { return component.value })
              var murmur = Fingerprint2.x64hash128(values.join(''), 31)
            })
          

The hash value should be passed to PayU in OrderCreateRequest body, see example below.

7 Creating tokens

Multi-use token (TOKC_) is created after first use of single-use token (TOK_).

To obtain single-use token use Secure Form with MULTI passed as argument to tokenize method.

The multi-use token can either be created during purchase or separately. Below sections explain both ways in more details.

In case card is stored without making a purchase, you must not create order with total amount set to non-zero amount which is later canceled.

The above approach is forbidden by the card schemes (Visa and Mastercard). Instead, you should set total amount to 0 as described below.

7.1 Creating multi-use tokens during purchase

Creating token during purchase is the standard and most common way to store a card.

The following requirements apply to such approach:

  1. Order Create Request should be extended with buyer and payMethod sections where single-use token (TOK_) is used as a value parameter.
  2. cardOnFile should be set to FIRST (detailed descriptions of cardOnFile parameter values can be found in JSON properties section).
  3. Your POS must be configured to allow creating multi-use tokens.

Sample order with single-use token (TOK_):

                    curl -v -X POST https://secure.payu.com/api/v2_1/orders \
                    -H "Content-Type: application/json" \
                    -H "Authorization: Bearer 3e5cac39-7e38-4139-8fd6-30adc06a61bd" \
                    -d '{
                          "notifyUrl":"https://your.eshop.com/notify",
                          "customerIp":"127.0.0.1",
                          "merchantPosId":"145227",
                          "description":"Laptop",
                          "currencyCode":"PLN",
                          "totalAmount":"15000",
                          "cardOnFile": "FIRST",
                          "extOrderId":"[generateExtOrderId]",
                          "products":[
                             {
                                "name":     "Laptop",
                                "unitPrice":"15000",
                                "quantity": "1"
                             }
                          ],
                          "buyer": {
                              "email": "john.doe@example.com",
                              "firstName": "John",
                              "lastName": "Doe",
                              "language": "en"
                          },
                          "payMethods": {
                              "payMethod": {
                                   "value": "TOK_1IHRPT6HKSSS3H62K0GS8pElP862",
                                   "type":  "CARD_TOKEN"
                              }
                          },
                          "deviceFingerprint": "[generateFingerPrint2]"
                      }'
                

Authentication methods are described in: Signing API calls parameters.

Warning! POS used in the example does not have tokenization switched on.

Example for SUCCESS response

                    {
                        "status": {
                            "statusCode": "WARNING_CONTINUE_3DS",
                            "severity": "WARNING"
                        },
                        "redirectUri": "{redirectUri}",
                        "iframeAllowed": true,
                        "threeDsProtocolVersion": "3DS2"
                        "orderId": "ORDER_ID",
                        "payMethods": {
                            "payMethod": {
                                "card": {
                                    "number": "424242******4242",
                                    "expirationMonth": "12",
                                    "expirationYear": "2017"
                                },
                                "type": "CARD_TOKEN",
                                "value": "TOKC_KPNZVSLJUNR4DHF5NPVKDPJGMX7"
                            }
                        }
                    }
                

The above response assumes that there is need for additional payer authentication by means of 3DS. See Handling 3DS for more details.

PayU notifies you with payment status by submitting a notification to address provided in the notifyUrl parameter. To learn more about notifications, please check Notifications.

7.2 Creating multi-use tokens without purchase

Storing card without purchase is useful when you want the cardholder to store the card upfront, before any actual charge is made, like for example in case of free trial periods of a subscribed service.

This feature requires special arrangements to be made, before it is enabled in either sandbox or production enviroment. Please contact your sales representative in PayU first to find out if you can use this service.

The following requirements apply to such approach:

  1. Order Create Request should be extended with buyer and payMethod sections where single-use token (TOK_) is used as a value parameter.
  2. OrderCreateRequest has totalAmount set to 0 (note that currency still needs to be provided for the sake of API consistency).
  3. products object is not required.
  4. Zero-amount orders are always auto-received - even in case when card payments are otherwise configured not to be auto-received, for zero-amount always expect status transition from PENDING to either COMPLETED or CANCELED but never to WAITING_FOR_CONFIRMATION.
  5. Zero-amount orders are not possible for "shops" configured as marketplace where shoppingCarts object is required.
  6. cardOnFile should be set to FIRST (detailed descriptions of cardOnFile parameter values can be found in JSON properties section).
  7. Zero-amount orders are only possible for card payments.
  8. Your POS must be configured to allow creating multi-use tokens.
  9. Your "shop" must be configured to allow zero-amount orders.

Sample order with single-use token (TOK_):

                    curl -v -X POST https://secure.payu.com/api/v2_1/orders \
                    -H "Content-Type: application/json" \
                    -H "Authorization: Bearer 3e5cac39-7e38-4139-8fd6-30adc06a61bd" \
                    -d '{
                          "notifyUrl":"https://your.eshop.com/notify",
                          "customerIp":"127.0.0.1",
                          "merchantPosId":"145227",
                          "description":"Laptop",
                          "currencyCode":"PLN",
                          "totalAmount":"0",
                          "cardOnFile": "FIRST",
                          "extOrderId":"[generateExtOrderId]",
                          "buyer": {
                              "email": "john.doe@example.com",
                              "firstName": "John",
                              "lastName": "Doe",
                              "language": "en"
                          },
                          "payMethods": {
                              "payMethod": {
                                   "value": "TOK_1IHRPT6HKSSS3H62K0GS8pElP862",
                                   "type":  "CARD_TOKEN"
                              }
                          },
                          "deviceFingerprint": "[generateFingerPrint2]"
                      }'
                

Authentication methods are described in: Signing API calls parameters.

Warning! POS used in the example does not have tokenization switched on.

Example for SUCCESS response

                    {
                        "status": {
                            "statusCode": "WARNING_CONTINUE_3DS",
                            "severity": "WARNING"
                        },
                        "redirectUri": "{redirectUri}",
                        "iframeAllowed": true,
                        "threeDsProtocolVersion": "3DS2"
                        "orderId": "ORDER_ID",
                        "payMethods": {
                            "payMethod": {
                                "card": {
                                    "number": "424242******4242",
                                    "expirationMonth": "12",
                                    "expirationYear": "2017"
                                },
                                "type": "CARD_TOKEN",
                                "value": "TOKC_KPNZVSLJUNR4DHF5NPVKDPJGMX7"
                            }
                        }
                    }
                

The above response assumes that there is need for additional payer authentication by means of 3DS. See Handling 3DS for more details.

PayU notifies you with payment status by submitting a notification to address provided in the notifyUrl parameter. To learn more about notifications, please check Notifications.

8 Charging tokens

OrderCreateRequest should be extended by buyer and payMethod sections where multi-use token (TOKC_) is used as a value parameter. Order created via REST API is described in: Creating a new order.

In case of payment with multi-use token (TOKC_) it is necessary to set cardOnFile parameter, which informs about party initializing payment:
  • STANDARD_CARDHOLDER
  • STANDARD_MERCHANT
Detailed descriptions of cardOnFile parameter values can be found in JSON properties section.
Setting this parameter in the correct way can increase conversion for payment cards.

Sample order with multi-use token (TOKC_) initiated by merchant:

                    curl -v -X POST https://secure.payu.com/api/v2_1/orders \
                    -H "Content-Type: application/json" \
                    -H "Authorization: Bearer 3e5cac39-7e38-4139-8fd6-30adc06a61bd" \
                    -d '{
                        "notifyUrl":"https://your.eshop.com/notify",
                        "customerIp":"127.0.0.1",
                        "merchantPosId":"145227",
                        "description":"Laptop",
                        "currencyCode":"PLN",
                        "totalAmount":"15000",
                        "cardOnFile": "STANDARD_MERCHANT",
                        "extOrderId":"9xl0x8nr1wk7m0i3ltqbja",
                        "products":[
                            {
                                "name":     "Laptop",
                                "unitPrice":"15000",
                                "quantity": "1"
                            }
                        ],
                        "buyer": {
                            "email": "john.doe@example.com",
                            "firstName": "John",
                            "lastName": "Doe",
                            "language": "en"
                        },
                        "payMethods": {
                            "payMethod": {
                                "value": "TOKC_2IHRST6HKSST3H62K2GS8pElI862",
                                "type":  "CARD_TOKEN"
                            }
                        },
                        "deviceFingerprint": "0372098a4a90927db053463454491d78"
                    }'
                

Example for SUCCESS response

                    {
                        "orderId": "ORDER_ID",
                        "payMethods": {
                            "payMethod": {
                                "card": {
                                    "number": "424242******4242",
                                    "expirationMonth": "12",
                                    "expirationYear": "2017"
                                },
                                "type": "CARD_TOKEN",
                                "value": "TOKC_KPNZVSLJUNR4DHF5NPVKDPJGMX7"
                            }
                        },
                        "status": {
                            "statusCode": "SUCCESS",
                            "statusDesc": "Request successful"
                        }
                    }
                

This response means that there is no need for additional payer authentication. Please note that it is possible that 3DS or CVV may need to provided. See Handling 3DS and Handling CVV2 for more details.

PayU informs Shop about the payment by submitting a notification to the address provided in the orders notifyUrl parameter. To learn more about notifications, please read Notifications.

8.1 Handling 3DS

In case of WARNING_CONTINUE_3DS response, payer should be redirected to card issuer page (redirectUri parameter) for additional payment authentication in 3D Secure process.

Authentication is currently always performed via 3DS2 protocol, indicated by the value of threeDsProtocolVersion field.

To learn how to tackle 3DS2, please refer to 3DS 2 page.

Example of WARNING_CONTINUE_3DS response:

                    {
                        "orderId": "ORDER_ID",
                        "status": {
                            "statusCode": "WARNING_CONTINUE_3DS",
                            "severity": "WARNING"
                        },
                        "redirectUri": "{redirectUri}",
                        "iframeAllowed": true,
                        "threeDsProtocolVersion": "3DS2"
                    }
                
After 3DS authentication on card issuer page, payer is redirected back to page address that was passed as continueUrl in OrderCreateRequest. Additionally address in query string is extended by two parameters:
  • statusCode - values SUCCESS or WARNING_CONTINUE_CVV;
  • refReqId - random alfanumeric string of characters.
Example:
https://your.shop.com/payment?statusCode=SUCCESS&refReqId=5c867936fbb3cc2c373820b4550b4645

When the statusCode parameter adopts SUCCES value it means that order has been accepted without need for another authentication of the payer and you can wait for order status.

On the other hand whenstatusCode parameter adopts WARNING_CONTINUE_CVV value, then refReqId parameter should be taken:

refReqId=5c867936fbb3cc2c373820b4550b4645
And then passed depending on the integration type:

8.2 Handling CVV2

In case of WARNING_CONTINUE_CVV payer should be asked to provide CVV2/CVC2 code. To do this, value of redirectUri parameter should be passed depending on the integration type:

Example of WARNING_CONTINUE_CVV response:

                    {
                        "orderId": "ORDER_ID",
                        "status": {
                            "statusCode": "WARNING_CONTINUE_CVV",
                            "severity": "WARNING"
                        },
                        "redirectUri": "{redirectUri}"
                    }
                

Sample value of redirectUri parameter:

https://secure.payu.com/api/v2/token/token.json?refReqId=11ed628ebe88ef6837d90ebb26f1a8b9

Order status will be sent after CVV2/CVC2 code has been provided by the payer.

9 Retrieving tokens

Payment methods retrieve service description

Payment methods available for a given user should not be stored locally on merchant's server, but rather retrieved from PayU system for each payment. Retrieved are both the stored (tokenized) payments methods and generic payment methods. Using the retrieve service gives the following benefits:

- only payment methods available at the moment for the user are provided,

- payment methods stored for the user are always up to date and synchronized with user's active PayU Account.

In order to retrieve the payment methods, you need first to obtain OAuth access token.

Obtaining OAuth access token

To obtain OAuth access token, use the POST method to send request to endpoint /pl/standard/user/oauth/authorize.

Sample request:

curl -X POST https://secure.payu.com/pl/standard/user/oauth/authorize \
   -H "Cache-Control: no-cache" 
   -H "Content-Type: application/x-www-form-urlencoded" 
   -d 'grant_type=trusted_merchant&client_id=[provided by PayU]&client_secret=[provided by PayU]&email=[users email]&ext_customer_id=[Id of the customer used in merchant system]' 

                

ext_customer_id is unique customer identifier given by merchant, it is necessary in order to correctly generate the OAuth token.

Sample positive response (HTTP 200):
{
    "access_token": "4099c2c3-276f-488a-90e2-32620ac441dc",
    "token_type": "bearer",
    "expires_in": 43199,
    "grant_type": "trusted_merchant"
}
            

Retrieving payment methods

Insert the access token into header and use the GET method to send request to endpoint api/v2_1/paymethods .

Sample request:
curl -X GET https://secure.payu.com/api/v2_1/paymethods \
   -H "Authorization: Bearer 87ad751f-7ea5-4023-a16f-04b6647a07f5" 
   -H "Cache-Control: no-cache" 

                

Sample postive response (HTTP 200). Description of fields are below the sample:

{  
   "cardTokens":[  
      {  
         "cardExpirationYear":"2017",
         "cardExpirationMonth":"12",
         "cardNumberMasked":"411111******1111",
         "cardBrand":"VISA",
         "value":"TOKC_XATB7DF8ACXYTVQIPLWTVPFRKQE",
         "brandImageUrl":"http://static.payu.com/images/mobile/visa.png",
         "preferred":true,
         "status":"ACTIVE"
      },
      {  
         "cardExpirationYear":"2014",
         "cardExpirationMonth":"12",
         "cardNumberMasked":"424242******4242",
         "cardBrand":"VISA",
         "value":"TOKC_XATB7DF8ACXYTVQIPLWTVPFRKQE",
         "brandImageUrl":"http://static.payu.com/images/mobile/visa.png",
         "preferred":false,
         "status":"EXPIRED"
      }
   ],
   "pexTokens":[  
      {  
         "accountNumber":"5311...7744",
         "payType":"mtex",
         "value":"TOKE_XPJ4UKJGHVRPMQPGB6X1JJQCUSS",
         "name":"account name set by the user",
         "brandImageUrl":"http://static.payu.com/images/mobile/logos/pex_mbank.png",
         "preferred":false,
         "status":"ACTIVE"
      }
   ],
   "payByLinks":[  
      {  
         "value":"c",
         "name":"Płatność online kartą płatniczą",
         "brandImageUrl":"http://static.payu.com/images/mobile/logos/pbl_c.png",
         "status":"ENABLED",
         "minAmount": 50,
         "maxAmount": 100000
      },
      {  
         "value":"o",
         "name":"Pekao24Przelew",
         "brandImageUrl":"http://static.payu.com/images/mobile/logos/pbl_o.png",
         "status":"DISABLED",
         "minAmount": 50,
         "maxAmount": 100000
      },
      {  
         "value":"ab",
         "name":"Płacę z Alior Bankiem",
         "brandImageUrl":"http://static.payu.com/images/mobile/logos/pbl_ab.png",
         "status":"TEMPORARY_DISABLED",
         "minAmount": 50,
         "maxAmount": 100000
      }
   ]
}          
            

cardTokens

This section will be returned empty if the user does not have any active or expired card tokens.
Parameter Description
cardExpirationYear YYYY
cardExpirationMonth MM
cardNumberMasked First 6 and last 4 digits of the PAN (card number).
cardBrand Possible values: 'VISA', 'MASTERCARD', 'MAESTRO'. Other card types are not supported, moreover 'MAESTRO' is not supported in recurring payments. VISA describes various Visa card brands, incl. Visa Electron. MASTERCARD also includes MasterCard Debit.
value Card token value.
brandImageUrl Link to card brand graphic on PayU server.
preferred true/false; it is set to 'true' for a cardToken or bankToken used most recently by the user.
status Possible values: 'ACTIVE' and 'EXPIRED'.

'EXPIRED' tokens may be skipped or presented to the user with a prompt to update or add a new card.

If a token has been closed by the user or blocked for security reasons by PayU, it will not be provided in retrieve response.

pexTokens

This section will be returned empty if the user does not have any active pexTokens.

pexTokens relate to bank accounts tokenized through PayU|Express service.

Parameter Description
accountNumber First and last 4 digits of the bank account in the IBAN format.
payType Represents payType of the token.
name Name of the bank account set by the user.
value Bank token value.
brandImageUrl Link to bank logo graphic on PayU server.
preferred true/false; it is set to 'true' for a cardToken or bankToken used most recently by the user.
status Possible value: 'ACTIVE'.

If a token has been closed by the user or blocked for security reasons by PayU, it will not be provided in retrieve response.

If payType of the token is not configured on merchant's POS, the token will not be provided.

payByLinks

payByLinks are payment methods which always require redirection of the user. Therefore this section includes online bank transfers (pay-by-links), traditional bank transfer, installments and non-tokenized cards.
Parameter Description
value payType value. Available values are here.
name Name of payType set by PayU
brandImageUrl Link to payType logo graphic on PayU server.
status Possible values: 'ENABLED', 'DISABLED', 'TEMPORARY_DISABLED'.

10 Deleting tokens

Deleting a payment token

In case the buyer terminates the user account in your shop or chooses to remove the stored card from the user account, you need to delete the token.

In order to do it, simply send a DELETE message to https://secure.payu.com/api/v2_1/tokens/{tokenValue}

The header should contain a trusted.merchant OAuth token.

For example:
curl -X DELETE https://secure.payu.com/api/v2_1/tokens/TOKC_XATB7DF8ACXYTVQIPLWTVPFRKQE \
   -H "Authorization: Bearer cccbbc40-8113-443b-b4ea-c4b266272b22" 
   -H "Cache-Control: no-cache" 
            

11 Card data in text form

Warning! This integration type is available only for POSes meeting PCI DSS requirements and requires additional configuration. Therefore, please contact your sales representative in PayU before the integration.

Standard OrderCreateRequest should be extended by payMethods.payMethod section containing plain card data and cardOnFile parameter:

  • FIRST
  • STANDARD_CARDHOLDER
  • STANDARD_MERCHANT
Detailed descriptions of cardOnFile parameter values can be found in JSON properties section.

Only in case of one-time card payment this cardOnFile parameter can be skipped.

Setting this parameter in the correct way can increase conversion for payment cards and can guarantee transaction security.

Sample payMethods.payMethod section supplemented with plain card data


                    "payMethods": {
                        "payMethod": {
                            "card": {
                                "number":"5100052384536818",
                                "expirationMonth":"11",
                                "expirationYear":"2020",
                                "cvv":"123"
                            }
                        }
                    },

                

Sample payMethods.payMethod section supplemented with plain card data and first transaction identifier


                "payMethods": {
                    "payMethod": {
                        "card": {
                            "number":"5100052384536818",
                            "expirationMonth":"11",
                            "expirationYear":"2020",
                            "cvv":"123",
                            "firstTransactionId": "MCC0111LL1121"
                        }
                    }
                },

            

Also for plain card data payments you should be prepared for handling responses with: WARNING_CONTINUE_3DS or WARNING_CONTINUE_CVV.

12 External 3D Secure parameters

In case of already existing integration with provider of 3D Secure service (later called 3DS) you can pass parameters that have been returned from 3DS handling process in OrderCreateRequest. Standard OrderCreateRequest should be extended by payMethods.threeDsData section containing result data from 3DS process.

WARNING_CONTINUE_3DS will never be returned if the result of 3DS handling process will be delivered with Order.

Sample threeDsData section for successful 3DS2 authentication

                "payMethods": {
                    "payMethod": {
                        ...
                        },
                        "threeDsData": {
                            "status3Ds": "Y",
                            "status3DsDescription": "Authentication successful",
                            "dsTransactionId": "3b31b19d-1c06-4ea4-a85a-00af10c66588",
                            "eciCode": 5,
                            "cavv": "AAABBBEAUAAAABgICABQAAAAAAA="
                        }
                    }
                }
                

Sample threeDsData section for 3DS2 authentication attempt

                    "payMethods": {
                        "payMethod": {
                            ...
                            },
                            "threeDsData": {
                                "status3Ds": "A",
                                "status3DsDescription": "Authentication attempt",
                                "dsTransactionId": "3b31b19d-1c06-4ea4-a85a-00af10c66588",
                                "eciCode": 6,
                                "cavv": "BwABCJQnYgAAACdENCdiAAAAAAA="
                            }
                        }
                    }
                    

Parameters used in the threeDsData section

Parameter Parameter type Description
status3Ds ENUM 3DS status.
Following values are allowed to be used:
  • Y - successful 3DS2 authentication,
  • A - 3DS2 authentication attempt.
status3DsDescription string {1, 1024} Description related to 3DS result.

Optional field. However passing additional description with the MPI will allow better potential customer support from BOK.
xid string {1, 20} - for value in plain text,
string {28} - for Base64encoded value,
string {40} - for HEXencoded value.
XID - unique identifier of 3DS transaction given by the shop.

Field required within 3DS version 1 section. This field should not be sent when attempting 3DS2.x authentication.
dsTransactionId string {1, 36} Field required within 3DS2.x section. This field should not be sent when attempting 3DS version 1 authentication.
eciCode ENUM E-commerce Indicator / UCAF.

Permitted values (below values can also be passed with "0" e.g. "05", "04", etc.):
  • 5
  • 6
  • 7
  • 2
  • 1
  • 0
Optional field. It should be passed always if the MPI provided this information.
cavv string {1, 200} 3DS cryptogram.

Optional field.It should be passed always if the MPI provided this information.

13 Payment flows

Below you can find a handy reference of all card tokenization flow types.

13.1 First charge

  1. Obtain OAuth access token. Endpoint: /pl/standard/user/oauth/authorize. Method: POST
  2. Retrieve available payment methods. Endpoint: /api/v2_1/paymethods. Method: GET
  3. Collect full card data (PAN, expiry date, CVV2/CVC2) via widget or form. Retrieve card token.
  4. Prepare OrderCreateRequest (with cardOnFile or recurring param if required), insert one-time card token and submit the request. Endpoint: /api/v2_1/orders. Method POST.
  5. Handle the WARNING_CONTINUE_3DS status provided in OrderCreateResponse by redirecting the user to redirectUri provided in the response.
  6. Optionally, only when 3DS authentication took too long and CVV2/CVC2 is no longer cached by PayU: handle the WARNING_CONTINUE_CVV status added to continueUrl.
  7. Receive notification with order status sent to address specfied by you in notifyUrl.
  8. Optionally, only when you do not have auto-receive enabled for the given payment method: capture the order. Endpoint: /api/v2_1/orders/{orderId}/status. Method: PUT.

13.2 Subsequent charge without card authentication

  1. Obtain OAuth access token. Endpoint: /pl/standard/user/oauth/authorize. Method: POST
  2. Retrieve available payment methods, including multi-use card token. Endpoint: /api/v2_1/paymethods. Method: GET
  3. Prepare OrderCreateRequest, insert multi-use card token and submit the request. Endpoint: /api/v2_1/orders. Method POST.
  4. Receive notification with order status sent to address specfied by you in notifyUrl.
  5. Optionally, only when you do not have auto-receive enabled on your POS: capture the order. Endpoint: /api/v2_1/orders/{orderId}/status. Method: PUT.

13.3 Subsequent charge with full card authentication

  1. Obtain OAuth access token. Endpoint: /pl/standard/user/oauth/authorize. Method: POST
  2. Retrieve available payment methods, including multi-use card token. Endpoint: /api/v2_1/paymethods. Method: GET
  3. Prepare OrderCreateRequest, insert multi-use card token and submit the request. Endpoint: /api/v2_1/orders. Method POST.
  4. Handle the WARNING_CONTINUE_3DS status provided in OrderCreateResponse by redirecting the user to redirectUri provided in the response.
  5. Handle the WARNING_CONTINUE_CVV status added to continueUrl.
  6. Receive notification with order status sent to address specfied by you in notifyUrl.
  7. Optionally, only when you do not have auto-receive enabled on your POS: capture the order. Endpoint: /api/v2_1/orders/{orderId}/status. Method: PUT.

13.4 Subsequent charge with partial card authentication

  1. Obtain OAuth access token. Endpoint: /pl/standard/user/oauth/authorize. Method: POST
  2. Retrieve available payment methods, including multi-use card token. Endpoint: /api/v2_1/paymethods. Method: GET
  3. Prepare OrderCreateRequest, insert multi-use card token and submit the request. Endpoint: /api/v2_1/orders. Method POST.
  4. Handle the WARNING_CONTINUE_3DS or WARNING_CONTINUE_CVV status provided in OrderCreateResponse.
  5. Receive notification with order status sent to address specfied by you in notifyUrl.
  6. Optionally, only when you do not have auto-receive enabled on your POS: capture the order. Endpoint: /api/v2_1/orders/{orderId}/status. Method: PUT.