Components

Version 17.05.2021

Content

HTTPS requirements

All submissions of payment info using Components are made via a secure HTTPS connection. However, to protect yourself from certain forms of man-in-the-middle attacks, and to prevent your customers from seeing Mixed Content warnings in modern browsers, you must serve the page containing the payment form over HTTPS as well.

In short, the address of the page containing Components must start with https:// rather than just http://. If you are not familiar with the process of buying SSL certificates and integrating them with your server to enable a secure HTTPS connection, check out our security documentation for more information.

Creating New Payment on Merchant's Backend

This step is preferably executed when you have enough information to create customer's order.

You can find a demo on this link Demo Components

Check Payment API integration for more details.

Confirm payment on merchant's application

After you've created payment on a backend and sent client_secret back to your application you need to confirm payment using Monri Components.

Steps:

  • ensure you have valid client_secret (created on backend using payment/new)

  • create a custom payment form

  • confirm payment using monri.confirmPayment

  • handle ConfirmPaymentResponse

Creating a custom payment form

Creating a custom payment form with Components requires two steps

  1. Set up Monri Components

  2. Create your payment form

Step 1: Set up Monri Components

Components is available as part of Monri.js . To get started, include the following script on your pages. This script must always load directly from monri.com in order to remain PCI compliant—you can’t include it in a bundle or host a copy of it yourself.

<script src="https://ipgtest.monri.com/dist/components.js"></script>

Next, create an instance of Components:

var monri = Monri('<authenticity-token>');
var components = monri.components({"clientSecret": "<client-secret>"});

Replace <authenticity-token> with value provided in merchant dashboard. Replace <client-secret> with value obtained in step Creating New Payment on Merchant's Backend

When you’re ready to accept live card payments, replace the authenticity_token and merchant_key with your production authenticity_token and merchant_key.

Monri Options

Additional options can be passed as optional second parameter to Monri constructor, which additionally can customise Monri Components. Currently supported options are:

  • locale locale which will be used (details below),

  • fonts list of fonts that will be used for custom styling (also explained below)

Step 1.1: localise components

Components can be localised via specifying locale in Monri Options. For example, to use hr locale in Monri Components (and all underlying components), {locale: 'hr'} can be specified as a second parameter.

var monri = Monri('authenticity-token', {locale: 'hr'});

As of now, supported locales are:

  • hr locale for Croatia (ICU hr_HR)

  • en locale for USA (ICU en_US)

  • sr locale for Serbia (ICU sr_SR)

By "locale" here is assumed "language" only. Number format, date format, etc., as of time of writing, are not supported. By default, en locale is used.

Step 1.2: style components

Components can be stylised via additionally provided fonts in Monri Options. Fonts are provided as an array of FontFace objects, with these properties:

  • family Family of the font face.

  • src Path to the font source. Path can be absolute (only http and https URI schemes are supported) or relative to the hostname of the hosting/parent web site

  • display Specifies how font files are loaded and displayed by browser. Supported values are auto, block, swap , fallback and optional. If this property is omitted, auto is used by default. For more information about these values please see this link.

  • weight The weight of the font

  • style Specifies the font style. Supported values are normal, italic and oblique. If omitted, normal is used.

  • stretch Specifies front stretch property.

  • unicode-range The unicode range from font which browser will select to use. If omitted, all characters of font will be selected and thus available for use.

The family and src properties are required, others are optional and have default values.

List of fonts is passed as fonts property in Monri Options, like:

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',
                weight: '900'
            }
        ]
    }
);

Localization options and style option can be, of course, combined, like:

var monri = Monri('<authenticity-token>', {
        locale: 'hr',
        fonts: [...]
    }
);

Step 2: Create your payment form

To securely collect card details from your customers, Components creates UI components for you that are hosted by Monri. They are then placed into your payment form, rather than you creating them directly.

To determine where to insert these components, create empty DOM elements (containers) with unique IDs within your payment form. We recommend placing your container within a <label> or next to a <label> with a for attribute that matches the unique id of the Element container. By doing so, the Element automatically gains focus when the customer clicks on the corresponding label.

For example:

<form action="" method="post" id="payment-form">
    <div class="form-row">
        <label for="card-element">
            Credit or debit card
        </label>
        <div id="card-element">
            <!-- A Monri Component will be inserted here. -->
        </div>

        <!-- Used to display Component errors. -->
        <div id="card-errors" role="alert"></div>
    </div>

    <button>Submit Payment</button>
</form>

(Note: if inserted payment form is invisible, this may be a CSS issue. Start diagnostics by removig class form-row, the only one CSS in example)

When the form above has loaded, create an instance of an Component and mount it to the Component container created above:

// 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 and minimises the number of fields required by inserting a single, flexible input field that securely collects all necessary card details.

In addition to the card component, we also offer a saved card component and cvv component. They can be easily created like as the card mentioned above. For example:

var savedCard = components.create('saved_card', {style: style});
var cvvComponent = components.create('cvv', {style: style});

Default payment method is provided via supported payment_methods to change it on cvv component you can call setActivePaymentMethod where you have to provide valid token for saved card.

Styling components

Components can be styled via style property of second parameter in create method, as shown above in example. For all styling options please see section Components - style

Validation & listening to changes

Validating component

Components validates user input as it is typed. To help your customers catch mistakes, you should listen to change events on the card Component and display any errors:

card.onChange(function (event) {
    var displayError = document.getElementById('card-errors');
    if (event.error) {
        displayError.textContent = event.error.message;
    } else {
        displayError.textContent = '';
    }
});

Reacting to input element change - addChangeListener

We support adding changeListener via addChangeListener method. To add change listener simply invoke:

card.addChangeListener('<input_element>', function (event) {
    console.log(event.data)
    console.log(event.message)
    console.log(event.valid)
    console.log(event.element)
});

It's possible to add change listener for:

  • Card number by using card_number

  • Expiry date by using expiry_date

  • Cvv by using cvv


Card Number

To add card number change listener execute:

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_number

  • event

    • data: object

      • bin: String | null, min-length: 6, max-length: 6, only available if user has entered at least 6 digits, null otherwise

      • brand: String, one of visa, master, amex etc

    • element: String - in this case it's card_number

    • message: String | null - non null if card number input is invalid

    • valid: boolean - false if input is invalid

Example event data:

{
  "data": {
    "bin": "411111",
    "brand": "visa"
  },
  "element": "card_number",
  "message": null,
  "valid": true
}

Save Card

To add save card change listener execute:

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_card

  • event

    • data: object

      • checked: boolean

    • element: String - in this case it's save_card

    • message: String | null - non null if card number input is invalid

    • valid: boolean - always true for this event

Example event data:

{
  "data": {
    "checked": true
  },
  "element": "save_card",
  "message": null,
  "valid": true
}

Expiry Date

To add expiry date change listener execute:

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

    • data: object

      • month: Number, 1 - 12

      • year: Number, eg 2024

    • element: String - in this case it's expiry_date

    • message: String | null - non null if expiry date is in past or invalid

    • valid: boolean - false if input is invalid

Example event data:

{
  "data": {
    "month": 11,
    "year": 2021
  },
  "element": "expiry_date",
  "message": null,
  "valid": true
}

CVV Change Event

To add cvv change listener execute:

card.addChangeListener('cvv', function (event) {
    console.log(event.data)
    console.log(event.message)
    console.log(event.valid)
    console.log(event.element)
});

Event details

  • key: cvv

  • event

    • data: object - empty object

    • element: String - in this case it's cvv

    • message: String | null - non null if cvv is invalid

    • valid: boolean - false if input is invalid

Example event data:

{
  "data": {},
  "element": "cvv",
  "message": null,
  "valid": true
}

Installments Event

To add selected installment change listener execute:

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

  • event

    • data: object

      • selectedInstallment: Number

    • element: String - in this case it's installments

    • message: String | null - non null if cvv is invalid

    • valid: boolean - false if input is invalid

Example event data:

{
  "data": {
    "selectedInstallment": 11
  },
  "element": "cvv",
  "message": null,
  "valid": true
}

Confirm Payment using Monri Components

Step 1: Invoke confirmPayment when you are ready to confirm order

The payment details collected using Components can be used to confirm payment.

Although payment can be confirmed at any moment it is a good practice to intercept form submit and then invoke monri.confirmPayment.

confirmPayment accepts two arguments:

  • component - component you've created using components.create

  • transaction params

    • address

    • fullName

    • city

    • zip

    • phone

    • country

    • email

    • orderInfo

All transaction params fields are validated using rules defined in Variables - names, lengths and formats

Create an event handler that handles the submit event on the form. The handler invokes confirmPayment which confirms transaction and returns Result<PaymentResult>.

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 3DS authentication is automatically handled by Monri Components library.

Card Component

// 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)
        }
    });
});

Step 2: Handle Payment Result

The last step is to handle payment result. This step completely depends on application use case. Response can be submitted to the merchant's backend or handled in application.

If you want secure and stable transaction processed notification continue to the section Getting payment result on merchant's backend

function handlePaymentResult(paymentResult) {
    // Handle PaymentResult
    if (paymentResult.status == 'approved') {
        alert("Transaction approved")
    } else {
        alert("Transaction declined")
    }
}

Crypto Currencies

Paycek payments

Step 1: Set up PayCek Component

PayCek component is available as part of Monri.js. To get started include the following script on your pages. This script must always load directly from monri.com in order to remain PCI compliant you can’t include it in a bundle or host a copy of it yourself.

Test Environment

<script src="https://ipgtest.monri.com/dist/components.js"></script>

Production Environment

<script src="https://ipg.monri.com/dist/components.js"></script>

Next, create an instance of Components:

var monri = Monri('<authenticity-token>');
var components = monri.components({"clientSecret": "<client-secret>"});

Replace <authenticity-token> with value provided in merchant dashboard. Replace <client-secret> with value obtained in step Creating New Payment on Merchant's Backend

When you’re ready to accept live payments, replace the authenticity_token and merchant_key with your production authenticity_token and merchant_key.

Monri Options

Additional options can be passed as optional second parameter to Monri constructor, which additionally can customise Monri Components. Currently supported options are:

  • locale locale which will be used (details below)

Step 1.1: localize components

Components can be localized via specifying locale in Monri Options. For example, to use hr locale in Monri Components (and all underlying components), {locale: 'hr'} can be specified as a second parameter.

For more details check localize components

Step 2: Create your payment form

To determine where to insert these components, create empty DOM elements (containers) with unique IDs within your payment form. For example:

<form action="" method="post" id="pay-cek-payment-form-form">
    <div class="form-row">
        <div id="pay-cek-element">
            <!-- A Monri PayCek Component will be inserted here. -->
        </div>
    </div>

    <button>Submit Payment</button>
</form>

(Note: if inserted payment form is invisible, this may be a CSS issue. Start diagnostics by removing class form-row, the only one CSS in example)

When the form above has loaded, create an instance of PayCek Component and mount it to the PayCek Component container created above:

// Custom styling can be passed to options when creating PayCek Component.
var options = {
    payCekOptions: {size: "small"}
};
// Create an instance of the card 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
            // Confirm payment does few things
            // 1. it opens a popup window where and option to pick between supported Crypto currencies is shown
            // 2. after user selects one of currencies QR code with wallet address is shown
            // 3. Approved or declined transaction response is then send as Promise
            .confirmPayment(payCek, params)
            .then(e => {
                if (e.error) {
                    // Inform the customer that there was an error.
                    alert(e.error.message)
                } else {
                    // Handle approved or declined result
                }
            })
            .catch(e => {
                alert(e);
            })
                        
    })
// Add an instance of the PayCek component into the `pay-cek-element` <div>.
payCek.mount("pay-cek-element")

Confirm Payment

Step 1: Invoke confirmPayment when you are ready to confirm order

Although payment can be confirmed at any moment it is a good practice to invoke monri.confirmPayment.

confirmPayment accepts two arguments:

  • component - component you've created using components.create

  • transaction params

    • address

    • fullName

    • city

    • zip

    • phone

    • country

    • email

    • orderInfo

All transaction params fields are validated using rules defined in Variables - names, lengths and formats

Create an event handler that handles the submit event on the form. The handler invokes confirmPayment which confirms transaction.

const transactionParams = {
    address: "Adresa",
    fullName: "Test Test",
    city: "Sarajevo",
    zip: "71000",
    phone: "+38761000111",
    country: "BA",
    email: "tester+components_sdk@monri.com",
    orderInfo: "Testna trx"
}
payCek.onStartPayment(() => {
    monri.confirmPayment(payCek, transactionParams)
        .then(e => {
            if (e.error) {
                // Inform the customer that there was an error.
                alert(e.error.message)
            } else {
                handlePaymentResult(e.result)
            }
        })
        .catch(e => {
            alert(e);
        })
    
})

Getting payment result on merchant's backend

Although you can easily collect payment result directly in application via onSuccess call it's better to implement callback listener (WebHook) on your backend.

Requirements:

  • it must be available over the Internet

  • it must be secured (HTTPS)

  • it must be set in merchant's setup on Monri's dashboard (if you are not able to set this value contact support@monri.com)

How it works:

  • upon transaction processing and approval we'll send POST request to callback endpoint defined in merchant's settings

  • validate received request to check if it's from us

  • update/deliver order

Example of POST request sent to callback endpoint:

Body:

{
  "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}"
}

Headers:

headervalue

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

Where authorization and http_authorization headers are created as:

digest = sha512(merchant_key + body)

You can check digest on this link Calculate Digest

authorization_header_value = WP3-callback digest

To check if request is valid check:

  • if authorization header schema is WP3-callback

  • extract digest as second part

  • verify digest

Viewport meta tag requirements

In order to provide a great user experience for 3D Secure on all devices, you should set your page’s viewport width to device-width with the the viewport meta tag. There are several other viewport settings, and you can configure those based on your needs. Just make sure you include width=device-width somewhere in your configuration.

For instance the following will work with Components:

<meta name="viewport" content="width=device-width, initial-scale=1"/>

If you already have this tag on your page and it includes width=device-width, then you are all set.

Components

All Components accept a common set of options, and then some Component-specific options.

Style

Customize appearance using CSS properties. Styles are passed via the style property of options.

Style property consist of four properties which represent the states of the component elements (e.g. card fields). There is base property which defines style that is applied to each component element, and there are three additional properties which, if specified, will override the base style. These properties are:

  • complete style applied when component element is completed e.g. filled with valid value

  • empty style applied when component element is empty (focus is moved away but element remained without entered value)

  • invalid style applied when component element contains invalid value. Style is applied only when element loses focus

Additionaly, as shown in example below, style property of label elements, input elements, remember card label element and select payment method element can be set explicitly.

Styles are applied to all component elements based on their state which had focus at least once. Currently, available style properties are as follows, all of string type and all optional:

AttributeCSS attributeDescription

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 height

Example of custom style:

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 has structure like the one below, where 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: {}
    }
}

Component specific options

Card Component Options

Card component options extends shared component options with:

optiontypedescriptiondefault value

tokenizePan

boolean

tokenize PAN when the client enters card info

false

tokenizePanOffered

boolean

offer the client to tokenize his PAN

false

showInstallmentsSelection

boolean

show installments select if installments are enabled for merchant

false

Option: tokenizePan

If enabled, PAN is tokenizen upon transaction approval and pan_token value is populated in transaction response.

Example:

var style = {} // define styling options for card component
var card = components.create("card", {
	style: style,
	tokenizePan: true // this will tokenize pan upon transaction approval
});

Option: tokenizePanOffered

If enabled save card for future payments checkbox is presented to a customer. If user checks the checkbox, PAN is tokenized upon transaction approval and pan_token value is populated in transaction response.

Example:

var style = {} // define styling options for card component
var card = components.create("card", {
	style: style,
	tokenizePanOffered: true // this will enable 'save card for future payments' checkbox in form
});

NOTICE - if tokenizePan is set to true then tokenizePanOffered is ignored. NOTICE - setting tokenizePan to true requires user consent beforehand, in form of accepting terms and conditions or alike.

Option: showInstallmentsSelection

If enabled & merchant has enabled installments then dropdown for installments selection will be shown.

Example:

var style = {} // define styling options for card component
var card = components.create("card", {
	style: style,
	showInstallmentsSelection: true // this will enable installments selection
});

NOTICE - if set to true and not shown then installments for merchant are disabled. Contact [support@monri.com](mailto:support@monri.com?subject=Monri Components Installments-Enable for merchant)

Transactions API

Variables - names, lengths and formats

Here are the variables and their definitions used when generating JSON documents for API calls:

Buyer's profile

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

ch_zip

3-9

alphanumeric

buyer's 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

ch_email

3-100

alphanumeric

buyer's email

Order details

namelengthformatadditional info

order_info

3-100

alphanumeric

short description of order being processed

order_number

1-40

printable characters

unique identifier

amount

3-11

integer

amount is in minor units, ie. 10.24 USD is sent as 1024

currency

predefined

alphabetic

possible values are USD, EUR or BAM

Last updated