This documentation provides a comprehensive guide to integrating Monri Components into your web application for secure and flexible payment processing.
1. Overview
Monri Components are a set of UI elements provided by Monri.js that allow you to securely collect sensitive payment information (like card details or cryptocurrency payment initiation) directly from your customers' browsers without compromising PCI DSS compliance.
By using Components, you embed hosted fields directly into your payment form, ensuring that sensitive data never touches your servers.
Key Benefits:
- PCI DSS Compliance: Sensitive data is handled directly by Monri.
- Customizable UI: Components can be styled to match your brand.
- Simplified Integration: Streamlined process for card and crypto payments.
2. Requirements
2.1. HTTPS
All submissions of payment information using Monri Components are made via a secure HTTPS connection. To ensure maximum security and prevent Mixed Content warnings in modern browsers, the page containing your payment form MUST also be served over HTTPS (https://) rather than just http://.
For more information on SSL certificates and enabling HTTPS, please refer to our security documentation.
2.2. Components script loading from the source
Components script must always load directly from monri.com. For more information please refer to 3.2.1. Set Up Monri Components below.
3. Core Integration: Card Payments
This section details the primary integration steps for accepting card payments using Monri Components.
3.1. Creating a New Payment on Your Backend
This is the initial step, ideally executed once you have sufficient information to create a customer's order. You will typically generate a client_secret on your backend which is then sent to your frontend for use with Monri Components.
For detailed backend integration, refer to the Payment API documentation.
Demo: See a live demonstration of Components integration here: Demo Components
3.2. Confirming Payment on Your Application (Frontend)
After generating the client_secret on your backend and sending it to your frontend application, you will use Monri Components to confirm the payment.
Steps:
- Ensure you have a valid
client_secret(obtained from your backend viapayment/newAPI call). - Set up Monri Components (initialize
Monri.js). - Create the necessary HTML containers for your custom payment form.
- Confirm payment using
monri.confirmPayment. - Handle the
ConfirmPaymentResponse.
3.2.1. Set Up Monri Components
Components are part of the Monri.js library. To get started, include the following script on your pages. This script must always load directly from monri.com to remain PCI compliant; you cannot bundle it or host a copy yourself.
<script src="[https://ipgtest.monri.com/dist/components.js](https://ipgtest.monri.com/dist/components.js)"></script>
Next, create an instance of Monri and components:
var monri = Monri('<authenticity-token>');
var components = monri.components({"clientSecret": "<client-secret>"});
- Replace
<authenticity-token>with the value provided in your merchant dashboard. - Replace
<client-secret>with the value obtained in the "Creating New Payment on Merchant's Backend" step.
When ready to accept live payments, ensure you replace theauthenticity-tokenandclient-secretwith your production values.
Monri Constructor Options:
TheMonriconstructor accepts an optional second parameter for customization:
locale: Sets the language for components (details below).
fonts: An array ofFontFaceobjects for custom styling (explained below).
Localization:
Components can be localized by specifying the locale option. For example, to use the Croatian (hr) locale:
var monri = Monri('authenticity-token', {locale: 'hr'});
Currently supported locales are:
hr(Croatian - ICUhr_HR)en(English - ICUen_US, default)sr(Serbian - ICUsr_SR)
"Locale" currently refers to language only; number and date formats are not supported.
Custom Fonts:
Components can be styled using custom fonts by passing an array of FontFace objects to the fonts property in Monri options:
var monri = Monri('<authenticity-token>', {
fonts: [
{
family: 'Rubik-Light',
src: '/static/fonts/rubik-light.ttf'
},
{
family: 'Rubik-Regular',
src: '[https://some-site.com/fonts/roboto.ttf](https://some-site.com/fonts/roboto.ttf)',
weight: '900'
}
]
});
The family and src properties are required. Optional properties include display, weight, style, stretch, and unicode-range. For display values, refer to MDN web docs.
Localization and font options can be combined:
var monri = Monri('<authenticity-token>', {
locale: 'hr',
fonts: [...] // Your font array
});
3.2.2. Create Your Payment Form
To securely collect card details, Monri Components create UI elements that are hosted by Monri and then embedded into your form.
Create empty DOM elements (containers) with unique IDs within your payment form. We recommend using a <label> with a for attribute matching the container's id for improved accessibility (automatic focus when the label is clicked).
Example HTML Structure:
<form action="" method="post" id="payment-form">
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element">
</div>
<div id="card-errors" role="alert"></div>
</div>
<button>Submit Payment</button>
</form>
If your inserted payment form is invisible, it might be a CSS issue. Try removing classes like form-row for diagnostics.
After your form loads, create an instance of a Component and mount it to its container:
// Custom styling can be passed to options when creating an Component.
var style = {
base: {
// Add your base input styles here. For example:
fontSize: '16px',
color: '#663399',
}
};
// Create an instance of the card Component.
var card = components.create('card', {style: style});
// Add an instance of the card Component into the `card-element` <div>.
card.mount('card-element');
The card Component simplifies the form by providing a single, flexible input field for all necessary card details.
In addition to the card component, saved_card and cvv components are also available:
var savedCard = components.create('saved_card', {style: style});
// Mount savedCard...
var cvvComponent = components.create('cvv', {style: style});
// Mount cvvComponent...
For the cvv component, you can change the default payment method using _setActivePaymentMethod and providing a valid token for the saved card.
3.2.3. Validation & Listening to Changes
Components validate user input as it is typed. Listen to change events on the card Component to display validation errors to your customers.
Listening to change Events:
card.onChange(function (event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
Reacting to Specific Input Element Changes - addChangeListener:
You can add listeners for specific input elements using the addChangeListener method:
card.addChangeListener('<input_element>', function (event) {
console.log(event.data);
console.log(event.message);
console.log(event.valid);
console.log(event.element);
});
Supported input elements for addChangeListener are: card_number, expiry_date, and cvv.
Card Number Change Listener
card.addChangeListener('card_number', function (event) {
console.log(event.data);
console.log(event.data.bin);
console.log(event.data.brand);
console.log(event.message);
console.log(event.valid);
console.log(event.element);
});
Event Details:
key:card_numbereventobject:data: objectbin:String | null(min-length: 6, max-length: 6). Available only if at least 6 digits are entered, otherwisenull.brand:String(e.g.,visa,master,amex).
element:String(card_number).message:String | null(nullif valid, message if invalid).valid:boolean(falseif input is invalid).
Example card_number Event Data:
{
"data": {
"bin": "411111",
"brand": "visa"
},
"element": "card_number",
"message": null,
"valid": true
}
Save Card Change Listener
card.addChangeListener('save_card', function (event) {
console.log(event.data);
console.log(event.data.checked); // true if user clicked on save card
console.log(event.valid); // always true
});
Event Details:
key:save_cardeventobject:data: objectchecked:boolean.
element:String(save_card).message:String | null(nullif valid).valid:boolean(alwaystruefor this event).
Example save_card Event Data:
{
"data": {
"checked": true
},
"element": "save_card",
"message": null,
"valid": true
}
Expiry Date Change Listener
card.addChangeListener('expiry_date', function (event) {
console.log(event.data);
console.log(event.data.month);
console.log(event.data.year);
console.log(event.message);
console.log(event.valid);
console.log(event.element);
});
Event Details:
key:expiry_date- event object:
data: objectmonth:Number(1-12).year:Number(e.g., 2024).
element:String(expiry_date).message:String | null(nullif valid, message if expiry date is in the past or invalid).valid:boolean(falseif input is invalid).
Example expiry_date Event Data:
{
"data": {
"month": 11,
"year": 2021
},
"element": "expiry_date",
"message": null,
"valid": true
}
CVV Change Event
card.addChangeListener('cvv', function (event) {
console.log(event.data);
console.log(event.message);
console.log(event.valid);
console.log(event.element);
});
Event Details:
key:cvveventobject:data:object(empty object).element:String(cvv).message:String | null(nullif valid, message if invalid).valid:boolean(falseif input is invalid).
Example cvv Event Data:
{
"data": {},
"element": "cvv",
"message": null,
"valid": true
}
Installments Change Event
card.addChangeListener('installments', function (event) {
console.log(event.data);
console.log(event.data.selectedInstallment);
console.log(event.message);
console.log(event.valid);
console.log(event.element);
});
Event Details:
key:installmentseventobject:data: objectselectedInstallment:Number.
element:String(installments).message:String | null(nullif valid, message if invalid).valid:boolean(falseif input is invalid).
Example installments Event Data:
{
"data": {
"selectedInstallment": 11
},
"element": "cvv",
"message": null,
"valid": true
}
3.2.4. Authorization
Although you can easily collect payment result directly in application via onSuccess call it’s better to implement callback listener (WebHook) on your backend.
For request authentication we use Authorization header created from:
authorization schema: String =WP3-v2authenticity_token: String = value from merchant’s configurationtimestamp: Integer = unix timestamp (eg PHP’stime())body_as_string: String = Json encoded request body, egjson_encode($data)digest: String =sha512(merchant_key + timestamp + authenticity_token + body_as_string)
You can check digest on this link Calculate Digest
Parts above are joined by space, so Authorization header should be in this form:
Authorization: schema authenticity_token timestamp digest
Example: Authorization: WP3-v2 abc...def 1585229134 314d32d1...0b49
Request endpoint is <base_url>/v2/payment/new where base_url is:
https://ipgtest.monri.comfor TEST environmenthttps://ipg.monri.comfor PROD environment
TIP: Parametrize merchant_key, authenticity_token and base_url so it can be easily changed when you are ready for
production environment.
Payment/new response contains:
status: String: approved | declined -id: String - Unique payment identifier used to track payment flow on Monri’s
side. Useful for debugging if something goes wrong. Save this value in your database.client_secret: String - Value you’ll send to your application which then will use this secret to confirm payment
using Monri Components.
Request example in PHP:
$data = [
'amount' => 100, //minor units = 1EUR
// unique order identifier
'order_number' => 'random' . time(),
'currency' => 'EUR',
'transaction_type' => 'purchase',
'order_info' => 'Create payment session order info',
'scenario' => 'charge'
'supported_payment_methods' => ['67f35b84811188a5c581b063c4f21bd6760c93b2a04d7ac4f8845dd5bbb3f5c6']
];
$body_as_string = Json::encode($data); // use php's standard library equivalent if Json::encode is not available in your code
$base_url = 'https://ipgtest.monri.com'; // parametrize this value
$ch = curl_init($base_url . '/v2/payment/new');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $body_as_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$timestamp = time();
$digest = hash('sha512', $key . $timestamp .$authenticity_token. $body_as_string);
$authorization = "WP3-v2 $authenticity_token $timestamp $digest";
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($body_as_string),
'Authorization: ' . $authorization
)
);
$result = curl_exec($ch);
if (curl_errno($ch)) {
curl_close($ch);
$response = ['client_secret' => null, 'status' => 'declined', 'error' => curl_error($ch)];
} else {
curl_close($ch);
$response = ['status' => 'approved', 'client_secret' => Json::decode($result)['client_secret']];
}
var_dump($response);
3.2.5. Confirm Payment using Monri Components
When the payment details are ready, invoke monri.confirmPayment to finalize the transaction. While confirmPayment can be called at any time, it's best practice to intercept the form's submit event and then call it.
confirmPayment accepts two arguments:
component: The component instance you created (e.g.,card).transactionParams: An object containing buyer and order information.
All transactionParams fields are validated against the rules defined in "Variables - Names, Lengths, and Formats" (see section 7).
MonriError and PaymentResult Types:
type MonriError = {
message: string
}
type Result<PaymentResult> = {
result: PaymentResult | null,
error: MonriError | null
}
type PaymentResult = {
status: string, // approved or declined
currency: string,
amount: number, // amount in minor units, eg 10.24 USD is 1024
order_number: string,
pan_token: string | null, // pan token representing tokenized card
created_at: string,
transaction_type: string, // authorize or purchase, depending on trx type used in payment/new
payment_method: SavedCardPaymentMethod | null, // available if card is tokenized for future payments, null if not
errors: Array<string> | null // errors if transaction is declined
}
type SavedCardPaymentMethod = {
type: string,
data: SavedCardPaymentMethodData
}
type SavedCardPaymentMethodData = {
brand: string,
issuer: string,
masked: string,
expiration_date: string,
token: string
}
Important: 3D Secure (3DS) authentication is automatically handled by the Monri Components library.
Card Component Example:
// Confirm payment or display an error when the form is submitted.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function (event) {
event.preventDefault();
const transactionParams = {
address: "Adresa",
fullName: "Test Test",
city: "Sarajevo",
zip: "71000",
phone: "+38761000111",
country: "BA",
email: "tester+components_sdk@monri.com",
orderInfo: "Testna trx"
}
monri.confirmPayment(card, transactionParams).then(function (result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
handlePaymentResult(result.result)
}
});
});
3.2.6. Handle Payment Result (Frontend)
The final step on the frontend is to handle the PaymentResult. This depends entirely on your application's use case. The response can be submitted to your merchant's backend or handled directly within the client-side application.
For a secure and stable transaction processed notification, we highly recommend implementing a callback listener (WebHook) on your backend (see section 6).
function handlePaymentResult(paymentResult) {
// Handle PaymentResult
if (paymentResult.status == 'approved') {
alert("Transaction approved")
} else {
alert("Transaction declined")
}
}
3.3. Getting Payment Result on Merchant’s Backend (WebHook)
While you can collect payment results on the client-side via the onSuccess callback, it is highly recommended to implement a Callback listener (WebHook) on your backend for secure and stable transaction notifications.
Requirements for your WebHook Endpoint:
- Must be publicly available over the internet.
- Must be secured (HTTPS).
- Must be configured in your merchant's settings on the Monri dashboard (contact support if you need assistance setting this value).
How it Works:
- Upon successful transaction processing and approval, Monri will send an HTTP POST request to your configured callback endpoint.
- Your backend should validate the received request to ensure it originates from Monri.
- Update or deliver the order based on the transaction status.
Example POST Request Body Sent to Callback Endpoint:
{
"id": 214,
"acquirer": "integration_acq",
"order_number": "3159daf002e3809",
"amount": 100,
"currency": "EUR",
"ch_full_name": "John Doe",
"outgoing_amount": 100,
"outgoing_currency": "EUR",
"approval_code": "687042",
"response_code": "0000",
"response_message": "approved",
"reference_number": "000003036888",
"systan": "000214",
"eci": "06",
"xid": null,
"acsv": null,
"cc_type": "visa",
"status": "approved",
"created_at": "2020-03-26T11:09:17.959+01:00",
"transaction_type": "purchase",
"enrollment": "N",
"authentication": null,
"pan_token": null,
"masked_pan": "411111-xxx-xxx-1111",
"issuer": "xml-sim",
"number_of_installments": null,
"custom_params": "{a:b, c:d}"
}
Example Request Headers:
| Header | Value |
|---|---|
accept-encoding |
gzip;q=1.0,deflate;q=0.6,identity;q=0.3 |
authorization |
WP3-callback d5e4528ad8a0e0f4262e518c663d5ff83cd4a8f381db68f9d30f99961409ceebb719c16d423757fc36c532b902c987012f5825dc8d32dde3a9b7ed95876be77a |
content-type |
application/json |
http_authorization |
WP3-callback d5e4528ad8a0e0f4262e518c663d5ff83cd4a8f381db68f9d30f99961409ceebb719c16d423757fc36c532b902c987012f5825dc8d32dde3a9b7ed95876be77a |
user-agent |
Faraday v0.15.4 |
content-length |
621 |
connection |
keep-alive |
The authorization and http_authorization headers are generated as:
digest = sha512(merchant_key + body)
(You can check the digest on this link: Calculate Digest)
authorization_header_value = WP3-callback digest
To validate if the request is from Monri, you should:
- Check if the authorization header schema is
WP3-callback. - Extract the digest (the second part of the header value).
- Verify the extracted digest against a locally computed digest using your
merchant_keyand the receivedbody.
4. Crypto Currencies: PayCek Payments
Monri Components also support integration with PayCek for cryptocurrency payments.
4.1. Set Up PayCek Component
The PayCek component is available via Monri.js. As with other components, it must be loaded directly from monri.com.
Test Environment:
<script src="https://ipgtest.monri.com/dist/components.js"></script>
Production Environment:
<script src="https://ipg.monri.com/dist/components.js"></script>
Initialize Monri and components instances:
var monri = Monri('<authenticity-token>');
var components = monri.components({"clientSecret": "<client-secret>"});
- Replace
<authenticity-token>with your merchant dashboard value. - Replace
<client-secret>with the value from your backend's "Creating New Payment" step.
Monri Options:
Additional options can be passed to the Monri constructor, such as locale. For localization details, refer to section 3.2.1.
4.2. Create Your PayCek Payment Form
Similar to card components, create an empty DOM container with a unique ID for the PayCek component within your payment form.
Example HTML:
<form action="" method="post" id="pay-cek-payment-form-form">
<div class="form-row">
<div id="pay-cek-element">
</div>
</div>
<button>Submit Payment</button>
</form>
If your inserted payment form is invisible, it might be a CSS issue. Try removing classes like form-row for diagnostics.
Once the form is loaded, create and mount the PayCek Component:
// Custom styling can be passed to options when creating PayCek Component.
var options = {
payCekOptions: {size: "small"}
};
// Create an instance of the PayCek Component.
var payCek = components.create("pay-cek", options)
.onStartPayment(() => {
// This is invoked after user clicks on PayCek button
// Here you can:
// 1. Collect user's info such as name, email address
// 2. Invoke confirmPayment with PayCek
const transactionParams = {
address: "Adresa",
fullName: "Test Test",
city: "Sarajevo",
zip: "71000",
phone: "+38761000111",
country: "BA",
email: "tester+components_sdk@monri.com",
orderInfo: "Testna trx"
}
monri
// confirmPayment opens a popup window for crypto currency selection
// then displays a QR code with wallet address
// finally, returns an Approved or Declined transaction response as a Promise
.confirmPayment(payCek, transactionParams) // Changed 'params' to 'transactionParams' for consistency
.then(e => {
if (e.error) {
// Inform the customer that there was an error.
alert(e.error.message)
} else {
// Handle approved or declined result
// For secure and stable result, handle on backend via WebHook (section 6)
}
})
.catch(e => {
alert(e);
})
});
// Add an instance of the PayCek component into the `pay-cek-element` <div>.
payCek.mount("pay-cek-element");
5. Customizing Components
Monri Components offer various options for styling and specific functionalities.
5.1. Styling Components
Components can be styled via the style property in the second parameter of the create method (as shown in section 3.2.2).
The style object consists of four properties representing component element states, which override the base style if specified:
base: Defines the default style applied to each component element.complete: Style applied when a component element is filled with a valid value.empty: Style applied when a component element is empty and loses focus.invalid: Style applied when a component element contains an invalid value and loses focus.
Additionally, style properties for label, input, rememberCardLabel, and selectPaymentMethod elements can be set explicitly.
Styles are applied to all component elements that have received focus at least once.
Supported CSS Properties (all string type, all optional):
| Attribute | CSS attribute | Description |
|---|---|---|
fontSize |
font-size |
Size of the font |
color |
color |
Component element color |
fontFamily |
font-family |
Family of the font |
fontSmoothing |
font-smoothing |
Selected font smoothing |
fontVariant |
font-variant |
Variant of the font |
fontWeight |
font-weight |
Font weight |
letterSpacing |
letter-spacing |
Font letter spacing |
textDecoration |
text-decoration |
Component element text decoration |
textShadow |
text-shadow |
Component element text shadow |
textTransform |
text-transform |
Component element text transform |
border |
border |
Component element border |
borderTop |
border-top |
Component element top border |
borderRight |
border-right |
Component element right border |
borderBottom |
border-bottom |
Component element bottom border |
borderLeft |
border-left |
Component element left border |
borderRadius |
border-radius |
Component element border radius |
padding |
padding |
Component element padding |
margin |
margin |
Component element margin |
lineHeight |
line-height |
Component element line height |
textIndent |
text-indent |
Component element text indent |
position |
position |
Component element position |
top |
top |
Component element top |
bottom |
bottom |
Component element bottom |
left |
left |
Component element left |
right |
right |
Component element right |
width |
width |
Component element width |
backgroundColor |
background-color |
Component element background color |
height |
height |
Component element height |
boxShadow |
box-shadow, moz-box-shadow, webkit-box-shadow |
Component element box shadow |
Example of Custom Style Object:
var style = {
base: {
fontFamily: 'Rubik-Regular'
},
invalid: {
color: 'red'
},
complete: {
color: 'blue'
},
label: {
base: {
color: 'blue',
textTransform: 'none'
},
invalid: {
color: 'gray'
},
complete: {
color: 'green'
}
},
input: {
base: {
fontSize: '15px',
color: "#663399",
borderBottom: "1px solid purple"
}
},
rememberCardLabel: {
base: {
fontSize: '15px',
color: "#663399"
}
},
selectPaymentMethod: {
base: {
fontSize: '15px',
color: "#663399"
}
}
};
Style Object Structure (empty fields can be omitted):
var style = {
base: {},
invalid: {},
complete: {},
empty: {},
label: {
base: {},
invalid: {},
complete: {},
empty: {}
},
input: {
base: {},
invalid: {},
complete: {},
empty: {}
},
rememberCardLabel: {
base: {},
invalid: {},
complete: {},
empty: {}
},
selectPaymentMethod: {
base: {},
invalid: {},
complete: {},
empty: {}
}
}
5.2. Component-Specific Options
Card Component Options
Card component options extend common component options with:
| Option | Type | Description | Default Value |
|---|---|---|---|
tokenizePan |
boolean | Tokenizes the PAN when the client enters card info. | false |
tokenizePanOffered |
boolean | Offers the client the option to tokenize their PAN. | false |
showInstallmentsSelection |
boolean | Shows the installments selection dropdown if enabled. | false |
tokenizePan Option:
If true, the PAN is tokenized upon transaction approval, and the pan_token value is populated in the transaction response.
var style = {} // Define styling options for card component
var card = components.create("card", {
style: style,
tokenizePan: true // This will tokenize the PAN upon transaction approval
});
tokenizePanOffered Option:
If true, a "save card for future payments" checkbox is presented to the customer. If checked, the PAN is tokenized upon transaction approval, and pan_token is populated.
var style = {} // Define styling options for card component
var card = components.create("card", {
style: style,
tokenizePanOffered: true // This enables the 'save card for future payments' checkbox in the form
});
Important Notes:
- If
tokenizePanistrue,tokenizePanOfferedis ignored. - Setting
tokenizePantotruerequires prior user consent (e.g., through accepted terms and conditions).
showInstallmentsSelection Option:
If true and installments are enabled for your merchant account, a dropdown for installment selection will be displayed.
var style = {} // Define styling options for card component
var card = components.create("card", {
style: style,
showInstallmentsSelection: true // This enables installments selection
});
Important Note: If showInstallmentsSelection is true but the dropdown doesn't appear, it means installments are disabled for your merchant account. Contact support@monri.com to enable them.
6. Transactions API: Variables, Lengths, and Formats
This section defines the variables and their properties used in API calls, particularly for JSON documents.
Buyer's Profile Fields
| Name | Length | Format | Additional Info |
|---|---|---|---|
ch_full_name |
3-30 | alphanumeric | Buyer's full name |
ch_address |
3-100 | alphanumeric | Buyer's address |
ch_city |
3-30 | alphanumeric | Buyer's postal code (ZIP) |
ch_zip |
3-9 | alphanumeric | Buyer's postal code (ZIP) |
ch_country |
2-3 | alphanumeric | Buyer’s country in alpha2, alpha3 letter code, or 3-digit ISO numeric code |
ch_phone |
3-30 | alphanumeric | Buyer's phone number |
ch_email |
3-100 | alphanumeric | Buyer's email address |
Order Details Fields
| Name | Length | Format | Additional Info |
|---|---|---|---|
order_info |
3-100 | alphanumeric | Short description of the order being processed |
order_number |
1-40 | printable characters | Unique identifier for the order |
amount |
3-11 | integer | Amount in minor units (e.g., 10.24 USD is sent as 1024) |
currency |
predefined | alphabetic | Possible values are USD, EUR, or BAM |
7. Viewport Meta Tag Requirements
To ensure an optimal user experience for 3D Secure (3DS) authentication across all devices, you should set your page’s viewport width to device-width using the viewport meta tag. Other viewport settings can be configured as needed, but width=device-width is crucial.
Example:
<meta name="viewport" content="width=device-width, initial-scale=1"/>
If this tag is already present on your page and includes width=device-width, no further action is required.