JavaScript SDK
Use our native JavaScript SDK to integrate the Client API quickly and securely, with built-in validation and encryption.
Our native SDK helps you communicate with the Client API. It offers:
- Convenient wrappers for API responses.
- Handling of all the details concerning the encryption of payment details.
- Caching of payment product logos and images to offer additional information about payment products.
- User-friendly formatting of payment data, such as card numbers and expiry dates.
- Input validation.
- Checks to determine to which issuer a card number is associated.
Our example app simulates the user interface for the whole payment flow based on the interaction between the app and our platform. Find the source code of the SDK and the example app on GitHub, including installation instructions.
To understand how to use this SDK, look at the following documentation:
- Mobile/Client Integration – Familiarise yourself with various concepts.
- Client API Reference – The SDK wraps the Client API and (among other things) exposes the responses of the web service calls as objects. Understanding the Client API will help you understand these SDK objects as well.
- The SDK on GitHub – The SDK contains a working example application, which can help you understand how to best use it.
- This current document will help you understand the global flow when creating payment pages using the SDK.
Why use the JavaScript SDK
Our JavaScript SDK helps you integrate payments faster and with less effort. It handles many technical details for you, so you do not have to work directly with the Client API for common tasks. The main advantages of using the SDK are:
- Less code to write and maintain – The SDK includes ready-made functionality, which reduces development time and ongoing maintenance.
- Easy authentication – The SDK takes care of authentication and security-related logic, making setup faster and safer.
If you require tight dependency control, minimal features, or a lightweight setup, the SDK may add code and functionality you do not need. In these cases, working directly with the API is simpler and more efficient.
SDK integration
Requirements
The minimum supported browser versions are based on the latest implemented feature of "private class fields":
- Chrome 74+
- Edge 79+
- Safari 14.1+
- Firefox 90+
- Chrome for Android 109+
- Safari on iOS 14.8+
- Opera Mobile 72+
- Android Browser 109+
- Firefox for Android 107+
Installation
Install this SDK using your preferred node package manager npm, yarn, or pnpm.
npm install onlinepayments-sdk-client-js
Distributed packages
You can use the SDK either as a UMD module or as an ES module.
Usage Universal Module Definition (UMD)
The SDK is available under the global namespace onlinepaymentssdk and can be used in the following way:
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
<script src="./node_modules/onlinepayments-sdk-client-js/dist/onlinepayments-sdk-client-js.umd.js"></script>
<script>
const sdk = window.onlinepaymentssdk.init({
...
})
</script>
</body>
</html>
Usage ES module (ESM)
Most bundlers (webpack, rollup, parcel, etc.) support ES Modules. You can import the SDK as follows:
import * as OnlinePaymentsSdk from 'onlinepayments-sdk-client-js';
From the root of the project, run npm ci to install the required dependencies.
Then, run npm run build. As a result, /dist/ (a distributable folder) will be created, containing both an original and a minified version of onlinepaymentsdk.js – a fully bundled SDK source with the encryption components.
When you include the SDK, it will automatically add the onlinepaymentsdk object to the global namespace. You can access all functionalities of the JavaScript SDK via this object.
After you successfully integrate the SDK with your project, you can proceed to integrate it with the entire payment system. The complete payment process consists of these steps:
- Initialisation of the SDK
- Fetching possible payment methods
- Fetching and displaying payment method details
- Validation of the provided data
- Encryption and transfer of payment data
- Finalising transaction
1. Initialise SDK
Firstly, you need to create an instance of the OnlinePaymentsSdk, enabling communication between the Server API and the client. Your app must have its own server, acting as an intermediary between our Client and Server API.
Since the customer initiates the payment in their app, the Client application asks the Server application to create a Session. When a Server application receives a request, it can create a Session via CreateSession from the Server SDK.
Try our API Explorer to send a CreateSession request.
After configuring and connecting your application to the Server API, you receive a response containing information about the created Session. A typical response looks like this:
{
clientSessionId: '47e9dc332ca24273818be2a46072e006',
customerId: '9991-0d93d6a0e18443bd871c89ec6d38a873',
clientApiUrl: 'https://clientapi.com',
assetUrl: 'https://asset.com',
tokens: []
}
Each Session has a fixed 3-hour lifespan. If it expires, you need to create a new Session.
Now pass assetUrl, clientApiUrl, clientSessionId, and customerId to the Client application. Once the application receives a response from the Server application with information about the Session, create an instance of the SDK object on the Client application side:
import * as OnlinePaymentsSdk from 'onlinepayments-sdk-client-js';
// this is the same as receiver from the create session request
const sessionData = {
clientSessionId: '...',
customerId: '...',
clientApiUrl: '...',
assetUrl: '...',
}
const sdk = OnlinePaymentsSdk.init(
sessionData,
{
appIdentifier: 'MyShopIntegration', // this identifies your application
},
);
2. Fetch possible payment methods
The next step is to get and display the possible payment options. Use the previously created sdk instance to invoke the getBasicPaymentProducts method.
Have a look at the code sample showing how to get the BasicPaymentProducts list.
const paymentContext: PaymentContextWithAmount = {
countryCode: 'BE',
amountOfMoney: { amount: 1000, currencyCode: 'EUR' },
isRecurring: false,
};
sdk.getBasicPaymentProducts(paymentContext)
.then(({ paymentProducts, accountsOnFile }) => {
// Display the payment products and/or accounts on file.
})
.catch((error) => {
// handle error state
});
You can skip this step if you want to use a specific payment product.
3. Fetch and display payment method details
Payment items are instances of BasicPaymentProduct. Your app can use these items to create a screen that lists them all. Use our convenient example application as a basis for your own implementation.
For certain payment products, customers can opt for our platform to store their credentials for recurring payments. We refer to the stored data as an account on file (Card On File) or a token. You can reuse this account on file/token for subsequent payments if your customers chose the same payment method. The sdk.getBasicPaymentProducts will return a list of accounts on file associated with the current session if the said session was created with tokens.
Depending on the method the customer chooses, consider cases of different data flows:
For payments with a third-party payment provider, you receive data with the redirection address in the payment properties. Redirect your customers in their browser to the third-party payment portal to continue the payment process. After the successful payment, your app needs to handle the redirection to the Client app. If a specific payment method requires additional data (like Google Pay), the data may already be provided with the received PaymentProduct.
The standard payment process is a card payment. Once your customers select a payment item or a stored account on file, the Client SDK can request the information your customers need to provide for the payment.
sdk.getPaymentProduct(1, paymentContext)
.then((paymentProduct) => {
const {
getFields, // array of all the fields the user needs to fill out.
getRequiredFields, // array of all the required fields the user needs to fill out.
getField, // returns a single PaymentProductField by id
} = paymentProduct;
// Display the form with fields to your user.
// Use the field helper functions to format and validate data.
})
.catch((error) => {
// handle error state
});
Use our example app for inspiration to create your screen.
4. Validate provided data
Now your application needs to validate the data your customers enter in your application's interface. You will need to perform validation on the PaymentRequestField and validate both the field values and the payment request.
The data entry interface must be fully transparent and understandable for your customers. So if there are validation errors, you should provide the customer with feedback about them. The error information is provided during the validation of a payment field or the validation of the payment request, so you can use it to display appropriate error messages.
5. Encrypt and transfer payment data
Based on the collected data, you need to create a PaymentRequest instance. This class has a tokenize property used to indicate whether the app should store the customer's credentials for recurring payments.
Use the following code sample for payment requests without accounts on file:
import { PaymentRequest } from 'onlinepayments-sdk-client-js';
// paymentProduct is retrieved in the previous step.
const paymentRequest = new PaymentRequest(paymentProduct);
Alternatively, adapt the code sample by supplying both the account on file and the corresponding payment product:
paymentRequest.setAccountOnFile(accountOnFile);
Once you configure a payment request, supply the values for the payment product fields. Use the identifiers of the fields, such as "cardNumber", "cvv", and "expiryDate", to set the field values for the payment request:
paymentRequest.setValue('cardNumber', '1245 1254 4575 45');
paymentRequest.setValue('cvv', '123');
paymentRequest.setValue('expiryDate', '12/2027');
Note that the format of the expiry date for the Credit Card payment products depends on settings in your merchant account, so it can be either MM/yyyy or MM/yy. The exact format is returned from the API, and the field validation and payment request validation will ensure that the format is correct. See the validation section below for PaymentProductField for more info.
Now, you can validate the payment request using the available list of errors. For any validation error, you need to provide feedback to the customer. For more information, read this dedicated chapter.
const validationResult = paymentRequest.validate();
if (validationResult.isValid) {
// The payment request is valid; you can encrypt and send it to our platform via your server.
} else {
// Notify the user that some fields contain invalid data.
var errors = validationResult.errors;
}
After the PaymentRequest validation, encrypt the request and send it to your Server application. Have a look at the code sample showing how to encrypt the request:
sdk.encryptPaymentRequest(paymentRequest)
.then((encryptedRequest) => {
/*
* encryptedRequest is the encrypted payment request, which can safely be sent to your
* server. It consists of two parts: encryptedCustomerInput and encodedClientMetaInfo.
*/
})
.catch((err) => {
// payment request can not be encrypted, handle error state
});
See a more detailed description of the encryption process in this dedicated chapter.
6. Finalise transaction
After encrypting the customer data, the Client SDK’s job is done. Now, send the encrypted object to your server and use it to make a CreatePayment request with the Server SDK. Then, provide it with the encrypted data to finalise the payment.
The response of the CreatePayment request may require additional actions from the Client, specified in the MerchantAction object. In most cases, this involves redirecting the customer to an external party (i.e. for a 3-D Secure check). Once your customers complete this check, our platform processes the actual transaction. Read the Server SDK documentation for more information.
Finally, you have to pass the information to your Client application to display the transaction result to your customers.
Find a full overview of the payment flow in the Mobile/Client Integration guide.
SDK objects
The JavaScript SDK includes several objects. Choose the object of your interest from the list below to read more about it:
- OnlinePaymentSdk
- PaymentContext
- BasicPaymentProduct
- PaymentProduct
- PaymentProductField
- AccountOnFile
- PaymentRequest
- PaymentRequestField
- CreditCardTokenRequest
- Masking
OnlinePaymentSdk
An instance of OnlinePaymentSdk is required for all interactions with the SDK. The following code fragment shows how OnlinePaymentsSdk is initialised. You obtain session data by performing a Create Client Session call via the Server API. You can also include an optional SdkConfiguration that includes appIdentifier, an identifier for your app.
import * as OnlinePaymentsSdk from 'onlinepayments-sdk-client-js';
const sdk = OnlinePaymentsSdk.init(
{
clientSessionId: '47e9dc332ca24273818be2a46072e006',
customerId: '9991-0d93d6a0e18443bd871c89ec6d38a873',
clientApiUrl: 'https://clientapi.com',
assetUrl: 'https://asset.com',
},
{
appIdentifier: 'MyShopIntegration', // this identifies your application
},
);
PaymentContext
The PaymentContext is an object that contains the context/settings of the upcoming payment. Some methods of the OnlinePaymentsSdk instance require it as an argument. This object can contain the following details:
export interface PaymentContext {
countryCode: string; // ISO 3166-1 alpha-2 country code
amountOfMoney: {
amount?: number; // Total amount in the smallest denominator of the currency
currencyCode: string; // ISO 4217 currency code
};
isRecurring?: boolean; // Set `true` when payment is recurring. Default false.
}
You can also import this interface as a type when using TypeScript:
import type { PaymentContext } from 'onlinepayments-sdk-client-js';
const paymentContext: PaymentContext = {
// ...
};
BasicPaymentProduct
The SDK carries information about payment products in two ways: BasicPaymentProduct and PaymentProduct. Instances of BasicPaymentProduct contain only the information required to display a simple list of payment products. When displayed, the user can select an individual payment product to show additional information about it.
Below is an example of how to display names and assets for the Visa product.
const basicPaymentProduct = basicPaymentProducts.paymentProducts.find((p) => p.id === 1);
basicPaymentProduct.label; // VISA
basicPaymentProduct.logo; // https://www.domain.com/path/to/visa/logo.gif
// this is valid only if there is a saved account on file
basicPaymentProduct.accountsOnFile[0].label; // e.g. 4242 **** **** 4242
PaymentProduct
When the customer selects a payment item or an account on file, they must enter additional information, like:
- Bank account number
- Credit card number
- Expiry date
Without this data, the payment cannot be processed.
Each payment item can have several fields that need to be completed to process a payment. The instance of the PaymentProduct class contains a list of fields the user must fill in to complete the payment. There are several helper methods for retrieving the PaymentProductField.
sdk.getPaymentProduct(1, paymentContext)
.then((paymentProduct) => {
const {
getField, // array of all the fields available in the payment product.
getRequiredFields, // array of all the required fields the user needs to fill out.
getFields, // returns a single PaymentProductField by id
} = paymentProduct;
})
.catch((error) => {
// handle error state
});
PaymentProductField
Each payment product field is represented by an instance of PaymentProductField. Each field has:
- An identifier
- A type
- A definition of restrictions that apply to the field's value
- A set of helper methods for formatting and validating an input value
In the code fragment below, the field with identifier expiryDate is retrieved from a payment product. Methods are available to determine whether the field is required or optional, and whether its values should be obfuscated in the user interface.
const field = paymentProduct.getField('expiryDate');
field.isRequired(); // true if value is required.
field.shouldObfuscate(); // true if needs to be obfuscated.
field.applyMask('0628'); // returns 06/28
field.removeMask('06/28'); // returns 0628
field.validate('06/28'); // returns a ValidationResult with information whether the validation passed and a list of errors, if any
AccountOnFile
An instance of AccountOnFile (AOF) represents information about a stored card product for the current user. Account on file data for the current session is available if the CreateSession call on the server side had the saved tokens provided. You can find more information in the API reference.
The code fragment below shows how to retrieve the display data for an account on file. You can show a label to the customer, along with the logo of the corresponding payment product.
// This contains all unique saved payment accounts from across all available payment products
const aof = paymentProduct.accountsOnFile[0];
// get display value of a field
accountOnFile.label; // returns a user-friendly label, usually a masked card number
accountOnFile.getValue('cardNumber'); // returns masked card number
accountOnFile.getValue('cardholderName'); // returns the cardholder name, if set
accountOnFile.getValue('expiryDate'); // returns the expiry date, if set
PaymentRequest
Once the user selects a payment product and an instance of PaymentProduct is retrieved, a payment request can be constructed. You must use this class as a container for all the values the customer provided.
import { PaymentRequest } from 'onlinepayments-sdk-client-js';
// paymentProduct is an instance of the PaymentProduct class (not BasicPaymentProduct).
const paymentRequest = new PaymentRequest(paymentProduct);
Methods like masking and unmasking values, validation, and encryption will work only when the payment product is instantiated.
Setting values is done through the instances of the PaymentRequestField class.
Tokenise payment request
A PaymentRequest has a property tokenize, which indicates whether a payment request should be stored as an account on file. The code fragment below shows how to construct a payment request when it should not be stored as an account on file.
import { PaymentRequest } from 'onlinepayments-sdk-client-js';
// create payment request, if tokenization is not provided, its default value is false.
const paymentRequest = new PaymentRequest(paymentProduct, null, true);
// OR
paymentRequest.setTokenize(true);
If the customer selected an account on file, this instance needs to be set on the payment request either when instantiating an object or with a dedicated setter. You can retrieve the instances of AccountOnFile from instances of BasicPaymentProduct and PaymentProduct.
import { PaymentRequest } from 'onlinepayments-sdk-client-js';
// providing paymentProduct and accountOnFile via constructor.
const paymentRequest = new PaymentRequest(paymentProduct, accountOnFile);
// or using setAccountOnFile method:
paymentRequest.setAccountOnFile(accountOnFile);
Note that setting an account on file and tokenise makes no sense.
PaymentRequestField
Payment request fields are represented by instances of PaymentRequestField. Each field provides methods to:
- Set and retrieve values
- Get the field label
- Obtain masked values for display
- Validate user inputs against the field's restrictions
Set field values for the payment request
Once you create a payment request, you can supply the values for the payment request fields as follows:
paymentRequest.getField('cardNumber').setValue('1245 1254 4575 45');
paymentRequest.getField('cvv').setValue('123');
Validate field values
Once a value is set, it can be validated. The system will validate the value using predefined data restrictions set on each field. That ensures only valid values can be encrypted for the payment request.
const field = paymentRequest.getField('cardNumber');
field.setValue('1245 1254 4575 45');
if (field.validate().isValid) {
// the value is in the correct format.
}
// or use chained methods
paymentRequest.getField('cvv').setValue('123').validate().isValid;
Validate payment request
Once all values have been supplied, the payment request can be validated. The PaymentRequest calls validation on each of its PaymentRequestField instances. These use their internal validation logic to verify that field values meet all requirements for a specific card type and merchant settings.
After the validation, a list of errors is returned, showing which requirements are missing for each field. If there are no errors, you can encrypt the payment request and send it to our platform via your e-commerce server.
If there are validation errors, you should provide the customer with feedback about these errors as explained above. Each ValidationErrorMessage contains the error message and error type for each field to make displaying appropriate feedback easier.
const validationResult = paymentRequest.validate();
if (validationErrorMessages.length) {
console.log('the following fields are invalid', validationErrorMessages);
}
Validations are defined in the PaymentProductField (contained within each PaymentRequestField) and return ValidationErrorMessage, such as:
paymentRequest.setValue('cardNumber', '456735000042797');
const result = paymentRequest.validate();
/*
* result.errors[0] will have this:
* {
* errorMessage: "Card number is in invalid format.",
* paymentProductFieldId: "cardNumber",
* type: "luhn"
* }
*/
AccountOnFile with READ_ONLY fields
When no AccountOnFile is selected for the specific PaymentRequest, all payment request fields (such as cardNumber) are writable and can be set normally. When you set an AccountOnFile on the PaymentRequest, the SDK enforces the following behaviour:
- All previously set unwritable field values are cleared from the PaymentRequest.
- You cannot manually set read-only fields anymore. Calling setter will throw InvalidArgumentError.
- Calling paymentRequest.getField(readOnlyFieldId).getValue() will return undefined.
- You can use the AccountOnFile instance to retrieve a value
This ensures only values that can be changed are submitted.
Encrypt payment request
When the PaymentRequest is initialised, you can call sdk.encryptPaymentRequest(request) to encrypt the following:
- The payment product field values
- The selected account on file (optional)
- Tokenisation info (optional)
Although you can use your own encryption algorithms to encrypt a payment request, we advise you to use the encryption functionality offered by the SDK.
When the sdk.encryptPaymentRequest runs, the system first validates the PaymentRequest for potential issues with the data. That ensures we are not encrypting invalid data, which our platform cannot process in the Server API.
CreditCardTokenRequest
This class is used to create a CardTokenization request. It contains the essential credit card fields: card number, cardholder name, expiry date, cvv, and payment product id.
const tokenRequest = new CreditCardTokenRequest();
tokenRequest.setCardholderName('test');
tokenRequest.setExpiryDate('122026');
tokenRequest.setCardNumber('12451254457545');
tokenRequest.setSecurityCode('123');
tokenRequest.setProductPaymentId(1);
Note that no validation rules are applied for values set in the token request since it is detached from the instance of the PaymentProduct. You should use this class as a helper for encrypting data required to create a token using the Server SDK. However, if invalid data is provided, the CreateToken request will fail.
You should provide raw values, not masked ones (e.g. "1226" instead of "12/26"). You can still use an instance of a PaymentProduct to format and validate values.
Encrypt token request
sdk.encryptTokenRequest(tokenRequest)
.then((encryptedRequest) => {
/*
* encryptedRequest is the encrypted token request, which can safely be sent to your
* server.
* It consists of two parts: encryptedCustomerInput and encodedClientMetaInfo.
*/
})
.catch((err) => {
// token request can not be encrypted, handle error state
});
Masking
To help format field values based on masks, the SDK offers a base set of masking functions in PaymentProductField.
const field = paymentProduct.getField('cardNumber');
// applying a mask on a field.
field.applyMask('1234123412341234'); // returns “1234 1234 1234 1234”
// removing mask from a field.
field.removeMask('1234 1234 1234 1234'); // returns “1234123412341234”
// getting masked value from `PaymentRequestField`
const maskedValue = paymentRequest.getField('cardNumber').getMaskedValue();
Additional features
The SDK has a lot more to offer. Have a look at the following features, as they will help you build the perfect solution.
Encrypt sensitive data
One of the biggest assets of the SDK is its encryption tool. It offers great security when transferring sensitive data (i.e. card numbers, expiry date, CVC code). An entire encryption/transfer flow looks like this:
You can encrypt all the provided payment information with sdk.encryptPaymentRequest. When sending the request, your application forwards the encrypted result to your e-commerce server, which sends it to the Server API.
import { PaymentRequest } from 'onlinepayments-sdk-client-js';
const paymentRequest = new PaymentRequest(paymentProduct);
// get field value from your input component
paymentRequest.getField('cardholderName').setValue('John Do');
// set other fields...
const validationErrorMessages = paymentRequest.validate().errors;
if (validationMessages.length) {
// display errors to the user.
} else {
sdk.encryptPaymentRequest(paymentRequest)
.then((encryptedRequest: EncryptedRequest) => {
// encryptedRequest.encryptedCustomerInput can be used to send the encrypted input data
// to the Server SDK to create a payment
})
.catch(console.error);
}
The SDK does all the heavy lifting, including:
- Requesting a public key from the Client API
- Performing the encryption
- BASE-64 encoding the result into one string
You only need to ensure that the PaymentRequest object contains all the information entered by the user. The encrypted payload needs to be sent to your e-commerce server, where it can be forwarded to the Server API.
Validate data
Each PaymentProductField has appropriate DataRestrictions. The DataRestrictions object contains information about all mandatory fields and validates whether the values entered meet the correctness condition. Together with a list of abstract validators, it also has a property isRequired. This property informs whether given restrictions are required or not.
You can validate a particular input just as easily as through the PaymentRequest validation. In case of any errors, the Errors field will display a list of errors.
It contains the following validators:
- Expiration Date: Checks whether the entered card expiration date is not earlier than the current date and whether it is not beyond the range of twenty-five years ahead.
- Email Address: Checks the format of the email address the customer has provided.
- Fixed List: Checks whether the entered value is on the list of possibilities.
- IBAN: Validates the IBAN the customer has provided.
- Length: Checks if the entered value is longer than the minimum value and if it is not longer than the maximum value.
- Luhn: The checksum formula used to validate a variety of identification numbers, such as credit card numbers.
- Range: Checks if the value is greater than the minimum value and if it is not greater than the maximum value.
- Regex: Validates that the entered value matches the regular expression.
- TermsAndConditions: The boolean validator for the terms and conditions accept field.
Each validator returns an appropriate error, indicating a field that does not meet the conditions, and a message you can easily translate.
Apply IIN check
The first six digits of a payment card number are known as the Issuer Identification Number (IIN). You can use the sdk.getIinDetails() call to retrieve the payment product and network associated with the provided IIN, as an instance of IinDetailsResponse.
This class has a property status that indicates the result of the check and a property paymentProductId that indicates which payment product is associated with the IIN, if recognised.
The property status can have several values:
- "SUPPORTED" indicates that the IIN is associated with a payment product supported by our platform.
- "UNKNOWN" indicates that the IIN is not recognised.
- "NOT_ENOUGH_DIGITS" indicates that fewer than six digits were provided, and that it is impossible to perform the IIN check.
- "EXISTING_BUT_NOT_ALLOWED" indicates that the provided IIN is recognised, but that the corresponding product is not allowed for the current payment or merchant.
const partialCreditCardNumber = '456735';
const paymentContext: PaymentContextWithAmount = {
countryCode: 'BE',
amountOfMoney: { amount: 1000, currencyCode: 'EUR' },
isRecurring: false,
};
sdk.getIinDetails(partialCreditCardNumber, paymentContext)
.then((response) => {
// response is an instance of `IinDetailsResponse`
const isSupported = response.status === IinDetailsStatus.SUPPORTED;
// the list of co-brands, if available:
const coBrands = response.coBrands;
})
.catch((error) => {
// handle error state
});
Some cards are co-branded and can be processed as either a local card (with a local brand) or an international card (with an international brand). If you are not set up to process these local cards, this API call will not return that card type in its response.
As soon as the system captures the first six digits of the card number, you can use the method sdk.getIinDetails() to verify the card type and check if you can accept this card. You can use the returned paymentProductId to retrieve the payment product and provide visual feedback to the user by showing the appropriate payment product logo.