3.5. Parallel form integration

3.5.1. General parallel form payment process flow

Merchant initiates a transaction by sending HTTPS POST request to the specified URL of the Master endpoint. After that, the Master endpoint registers this request as a parallel form payment order, returns the response back to Merchant and redirects Merchant`s customer to parallel form payment page. Then, the parallel form activation process starts. Initially, parallel form initiates and activates iframe of payment method selected by default. Iframe method requests Apropay system to create new auxiliary order for payment method selected by default. Apropay system creates new auxiliary order and starts to process it. First of all, Apropay system returns to Merchant payment form for this order. If the auxiliary order requires external payment form, Apropay system transfers processing to relevant Gate, which requests Payment system for external payment form. After that, Apropay system returns external form for auxiliary payment order to iframe on parallel form and Merchant`s Customer sees parallel form with default payment method form. If the Customer doesn`t prefer payment method selected by default, he may click on another parallel form tab with the name of payment method. When the Customer clicks on new parallel form tab, he initiates new iframe activation and auxiliary order creation. So, Iframe requests Apropay system to create new auxiliary order for opened payment method tab. Then, Apropay system creates new auxiliary order and starts processing it as was written above. Based on the foregoing, orders scheme in the Apropay system looks the following way:

@startuml
package "Parallel form order" {
[Auxiliary order 1\nPayment system 1]
[Auxiliary order 2\nPayment system 2]
[Auxiliary order 3\nPayment system 3]
}
@enduml

After that, the Merchant`s customer fills one of the provided auxiliary order`s payment forms, submits it and initiates HTTPS POST request to perform a transaction. Apropay system registers this transaction request and transfers it to relevant Gate to continue transaction processing. Gate requests Payment system to process transaction through processor. Then, Payment system returns transaction processing response to Apropay system.

@startuml
participant Merchant
box "Apropay" #LightBlue
participant "Endpoints \n Em, E1, E2, En"
participant "Projects \n Pm, P1, P2, Pn"
participant "Gates \n G1,G2, Gn"
end box
participant "Payment system"
Merchant -> "Endpoints \n Em, E1, E2, En":Parallel form order request
activate "Endpoints \n Em, E1, E2, En"
"Endpoints \n Em, E1, E2, En" ->"Endpoints \n Em, E1, E2, En":
note right:Master endpoint (Em) registers\nparallel form order request and\nredirects Merchant`s customer\nto parallel form payment page
"Endpoints \n Em, E1, E2, En"->Merchant:Redirect to parallel form payment page
group Parallel form payment page
Merchant->Merchant:
note left:Parallel form initiates and\nactivates iframe of default\npayment method
end group
Merchant-> "Endpoints \n Em, E1, E2, En":iframe requests Apropay system to\ncreate new auxiliary order of payment\nmethod shown by default
"Endpoints \n Em, E1, E2, En"->"Endpoints \n Em, E1, E2, En"
note right:Apropay system creates new\nauxiliary payment order and initiates\nit`s processing
group If auxiliary order uses external payment form
"Endpoints \n Em, E1, E2, En" ->"Projects \n Pm, P1, P2, Pn":Apropay system transfers processing control\nto relevant Project strategy (P1,P2,Pn, etc.)
activate "Projects \n Pm, P1, P2, Pn"
"Projects \n Pm, P1, P2, Pn" ->"Projects \n Pm, P1, P2, Pn"
note right:Project strategy\ndefines required gate
"Projects \n Pm, P1, P2, Pn" -> "Gates \n G1,G2, Gn":Project strategy transfers control to relevant\nGate (G1,G2,Gn, etc.)
activate "Gates \n G1,G2, Gn"
"Gates \n G1,G2, Gn" -> "Payment system":Gate requests Payment system for\nexternal payment form through Processor
activate "Payment system"
"Payment system" -> "Gates \n G1,G2, Gn":Returns external payment form data
deactivate "Payment system"
"Gates \n G1,G2, Gn" -> "Endpoints \n Em, E1, E2, En":Apropay system returns external payment form for auxiliary payment method
deactivate "Gates \n G1,G2, Gn"
deactivate "Projects \n Pm, P1, P2, Pn"
end group
"Endpoints \n Em, E1, E2, En" -> Merchant:Apropay system returns to iframe\nauxiliary order payment form
group If the Merchant`s customer open another parallel form payment tab
group Parallel form payment page
Merchant ->Merchant
note left:iframe activation starts
end group
Merchant -> "Endpoints \n Em, E1, E2, En": iframe requests Apropay system to\ncreate new auxiliary order of opened\npayment method tab
"Endpoints \n Em, E1, E2, En" ->"Endpoints \n Em, E1, E2, En"
note right:Apropay system creates new\nauxiliary order and initiates\nit`s processing. If auxiliary order\nrequires external form, processing\ngoes as shown on scheme above
"Endpoints \n Em, E1, E2, En" ->Merchant:Apropay system returns to iframe\nauxiliary order payment form
end group
Merchant -> "Endpoints \n Em, E1, E2, En":Transaction request
"Endpoints \n Em, E1, E2, En" ->"Projects \n Pm, P1, P2, Pn": Relevant auxiliary endpoint transfers control\nto Project strategy
activate "Projects \n Pm, P1, P2, Pn"
"Projects \n Pm, P1, P2, Pn"->"Gates \n G1,G2, Gn":Project strategy transfers transaction\nprocessing to relevant Gate
activate "Gates \n G1,G2, Gn"
"Gates \n G1,G2, Gn" -> "Payment system":Gate requests Payment system for transaction processing\nthrough processor
activate "Payment system"
Merchant --> "Endpoints \n Em, E1, E2, En":Get order status by ID
"Payment system" -> "Gates \n G1,G2, Gn": Returns transaction processing response and status
deactivate "Payment system"
"Gates \n G1,G2, Gn" -> Merchant: Apropay system returns transaction processing response and status to Merchant
deactivate "Gates \n G1,G2, Gn"
deactivate "Projects \n Pm, P1, P2, Pn"
deactivate "Endpoints \n Em, E1, E2, En"
@enduml

3.5.2. Parallel form integration flow

Parallel form project schemes

Parallel form integration process depends on number of required payment methods and currencies. Initially, Manager should determine all payment methods and currencies which will be available on parallel form payment page. After that, the Manager can start the Project creation and configuration. System scheme may be organized and customized in different ways. For example, if the Merchant requires payment operations only in one currency, system scheme may look the following way:

    @startuml
package "Master Endpoint" {
[Card payment endpoint]
[Neteller endpoint]
[n - payment system endpoint]
}
package "Project USD" {
[Strategy]
}
[Card payment endpoint] --> [Strategy]
[Neteller endpoint] --> [Strategy]
[n - payment system endpoint] --> [Strategy]
node "Neteller Gate USD" {
[Neteller processor]
}
node "Card payment Gate USD" {
[Card payment processor]
}
node "n Gate USD" {
[n-processor]
}
[Strategy] --> [Neteller processor]
[Strategy] --> [Card payment processor]
[Strategy] --> [n-processor]
@enduml

If the Merchant requires payment operations in different currencies, the system scheme example may look as follows:

    @startuml
    package "Master Endpoint" {
[Card payment endpoint]
[AstroPay endpoint]
[Neteller endpoint]
[n - payment system endpoint]
}
package "Project USD" {
[Card Payment & AstroPay\nStrategy USD]
}
package "Project EUR" {
[Neteller\nStrategy EUR]
}
package "Project JPY" {
[n - payment system\nStrategy JPY]
}
node "Neteller Gate EUR" {
[Neteller processor]
}
node "Card payment Gate USD" {
[Card payment processor]
}
node "AstroPay Gate USD" {
[AstroPay processor]
}
node "n Gate JPY" {
[n-processor]
}
[Card payment endpoint] --> [Card Payment & AstroPay\nStrategy USD]
[AstroPay endpoint] --> [Card Payment & AstroPay\nStrategy USD]
[Neteller endpoint] --> [Neteller\nStrategy EUR]
[n - payment system endpoint] --> [n - payment system\nStrategy JPY]
[Card Payment & AstroPay\nStrategy USD] --> [Card payment processor]
[Card Payment & AstroPay\nStrategy USD] --> [AstroPay processor]
[Neteller\nStrategy EUR] --> [Neteller processor]
[n - payment system\nStrategy JPY] --> [n-processor]
@enduml

Master endpoint is mandatory element for both system schemes. It has auxiliary endpoints with different currencies for all required payment methods. If we have two payment methods with usage of one currency, as you may see on example above (AstroPay and Card Payment), we may combine them to one project (Project USD). Otherwise, we may create particular project for each payment method. All of these two variants will be correct.

Parallel form Master endpoint settings

In order to use parallel form correctly, the specialist should set the project settings in a proper way. You may find an instruction concerning special project settings below.

  1. Initially, Merchant should create a project. If he wants to integrate parallel form which includes payment methods nominated in different currencies, he should create at least one project for each currency. For example, if the Merchant wants to proceed payments in USD, EUR and JPY, he should create 3 different projects.
  2. After the projects were created, Merchant should create all required endpoints for provided payment methods and bind them to appropriate projects. All these endpoints will be auxiliary to Master endpoint which will be created on the next step.
  3. To create Master endpoint, Merchant should press (Settings -> Configuration -> Master endpoints -> +Master Endpoint). In the settings of Master endpoint Merchant should set Parallel form payment template(Master endpoint properties -> Common -> Edit -> Payment form template). Thus, when the Merchant sends request to Master endpoint, Apropay system returns to him parallel form payment template which is defined on the Master endpoint level. As well, the parallel form payment template or any other form template can be set on the Project settings level(Project properties -> Common -> Edit -> Payment form template). So, when the Merchant will send the sale request to Master endpoint without parallel form template, Master endpoint inherit parallel form template from the project settings. Such form template returning algorithm is used for all kinds of form templates: payment, waiting and finish templates. You may see the full algorithm on the scheme below (payment form example):

    @startuml
    participant Merchant
    box "Apropay" #LightBlue
    participant Endpoint
    participant Project
    participant Gate
    end box
    participant "Payment System"
Merchant -> Endpoint: payment form request
Endpoint -> Endpoint
note right: Endpoint\ndefines set payment form\ntemplate
group If payment form template is not set on endpoint
Endpoint -> Project: request the project for payment form template
group If payment form template is not set on Project
Project -> Gate: checks Gate settings for external\nform usage option
group If external form usage option enabled
Gate -> "Payment System": requires payment form template
"Payment System" -> Gate: returns payment form template
end group
Gate -> Project: returns payment form template
end group
Project -> Endpoint: returns payment form template
end group
Endpoint -> Merchant: shows Merchant`s customer\npayment form template
@enduml

  1. After that, the Merchant should set all the auxiliary endpoints in the Master endpoint settings(Master endpoint properties -> Auxiliary endpoints -> Edit). To add new auxiliary endpoint, Merchant should press “Add” button. After that he should fill a form with 3 fields: “Endpoint”, “Payment method” and “Payment method reference name”. In the “Endpoint” field Merchant should choose one of the available endpoints which were created before. The “Payment method” field defines the name of payment method which will be shown on the relevant parallel form tab. “Payment method reference name” field defines the internal reference name of this payment method. After the auxiliary endpoint was added, Merchant also may set the countries where the payment method of this auxiliary endpoint is available. To do that, the Merchant should press the button with three points which stays opposite of the auxiliary endpoint field.
  2. Then, the Merchant should set all another required parameters of system elements.

3.5.3. Parallel form payment request

For integration purposes use staging environment sandbox.apropay.com instead of production gate.apropay.com. Parallel form payment requests are initiated through HTTPS POST request by using URL in the following format:

https://gate.apropay.com/paynet/api/v2/sale-form/ENDPOINTID – request of parallel form

Parallel form payment request parameters

In order to initiate a payment transaction through the parallel form, Merchant sends an HTTPS POST request with the following parameters:

Request parameter name Length/Type Comment Necessity*
client_orderid 128/String Merchant order identifier. Mandatory
order_desc 64k/String Brief order description. Mandatory
first_name 50/String Customer’s first name. Mandatory
last_name 50/String Customer’s last name. Mandatory
ssn 32/Numeric Last four digits of the customer’s social security number. Optional
birthday 8/Numeric Customer’s date of birth, in the format YYYYMMDD. Optional
address1 50/String Customer’s address line 1. Mandatory
city 50/String Customer’s city. Mandatory
state 2/String Customer’s state (two-letter state code). Please see Reference for a list of valid state codes. Mandatory for USA, Canada and Australia. Conditional
zip_code 10/String Customer’s ZIP code. Mandatory
country 2/String Customer’s country(two-letter country code). Please see Reference for a list of valid country codes. Mandatory
phone 15/String Customer’s full international phone number, including country code. Mandatory
cell_phone 15/String Customer’s full international cell phone number, including country code. Optional
email 50/String Customer’s email address. Mandatory
amount 10/Numeric Amount to be charged. The amount has to be specified in the highest units with . delimiter. 10.5 for USD means 10 US Dollars and 50 Cents. Mandatory
currency 3/String Currency the transaction is charged in (three-letter currency code). Sample values are: USD for US Dollar EUR for European Euro. Mandatory
ipaddress 45/String Customer’s IP address, included for fraud screening purposes. Mandatory
site_url 128/String URL the original sale is made from. Optional
control 40/String Checksum generated by SHA-1. See Request authorization through control parameter for more details. Mandatory
redirect_url 128/String URL the cardholder will be redirected to upon completion of the transaction. Please note that the cardholder will be redirected in any case, no matter whether the transaction is approved or declined. You should not use this parameter to retrieve results from Apropay gateway, because all parameters go through client’s browser and can be lost during transmission. To deliver the correct payment result to your backend use server_callback_url instead. Mandatory if both redirect_success_url and redirect_fail_url are missing
redirect_success_url 1024/String URL the cardholder will be redirected to upon completion of the transaction. Please note that the cardholder will be redirected only in case if the transaction is approved. You should not use this parameter to retrieve results from Apropay gateway, because all parameters go through client’s browser and can be lost during transmission. To deliver the correct payment result to your backend use server_callback_url instead. Mandatory if redirect_url parameter is missing
redirect_fail_url 1024/String URL the cardholder will be redirected to upon completion of the transaction. Please note that the cardholder will be redirected only in case if the transaction is declined or filtered. You should not use this parameter to retrieve results from Apropay gateway, because all parameters go through client’s browser and can be lost during transmission. To deliver the correct payment result to your backend use server_callback_url instead. Mandatory if redirect_url parameter is missing
server_callback_url 1024/String URL the transaction result will be sent to. Merchant may use this URL for custom processing of the transaction completion, e.g. to collect sales data in Merchant’s database. See more details at Merchant Callbacks. Optional
* acquirer can redefine the necessity of some fields so they become mandatory instead of optional.
* leading and trailing whitespace in input parameters will be omitted.

Parallel form payment request example

client_orderid=902B4FF5
&order_desc=Test Order Description
&first_name=John
&last_name=Smith
&birthday=19820115
&address1=100 Main st
&city=Seattle
&state=WA
&zip_code=98102
&country=US
&phone=+12063582043
&cell_phone=+19023384543
&amount=10
&email=john.smith@gmail.com
&currency=USD
&ipaddress=65.153.12.232
&site_url=www.google.com
&purpose=user_account1
&redirect_url=http://doc.apropay.com/doc/dummy.htm
&server_callback_url=https://httpstat.us/200
&merchant_data=VIP customer
&control=5fdc17c7fd70e01d55396de4de34ab95434578df

Parallel form payment request debug

endpointid or groupid input your ENDPOINTID or ENDPOINTGROUPID
client_orderid make it or use your internal invoice ID
order_desc
first_name
last_name
birthday
address1
city
state
zip_code
country
phone
cell_phone
amount
email
currency
ipaddress
site_url
purpose
merchant_control input your Control Key
redirect_url
redirect_success_url
redirect_fail_url
server_callback_url
merchant_data

String to sign
Signature
				  
				
			
		
			
		
			
		

3.5.4. Parallel form response

Parallel form response parameters

Response parameters Description
type The type of response. May be async-response, validation-error, error. If type equals validation-error or error, error-message and error-code parameters contain error details.
serial-number Unique number assigned by Apropay server to particular request from the Merchant.
merchant-order-id Merchant order id.
paynet-order-id Order id assigned to the order by Apropay.
redirect-url URL of the parallel form the customer will be redirected to.
error-message If status is error this parameter contains the reason for decline or error details.
error-code The error code is case of error status.

Parallel form response example

type=async-form-response
&serial-number=00000000-0000-0000-0000-000001c46d4b
&merchant-order-id=007
&paynet-order-id=2625009
&redirect-url=https://gate.apropay.com/paynet/form/init/BB624D58465A2F6A67677534686B414D53396234794C625A7047627A38534B31532F473455445865457469493D

3.5.5. Parallel form status request

Merchant must use Order status API call to get the customer’s parallel form order or auxiliary order status. After any type of transaction is sent to Apropay server and order id is returned, Merchant should poll for transaction status. When transaction is processed on Apropay server side it returns it’s status back to Merchant and at this moment the Merchant is ready to show the customer transaction result, whether it’s approved or declined.

Status API URL

For integration purposes use staging environment sandbox.apropay.com instead of production gate.apropay.com. Status API calls are initiated through HTTPS POST request by using URL in the following format:

The End point ID is an entry point for incoming Merchant’s transactions for single currency integration.
https://gate.apropay.com/paynet/api/v2/status/ENDPOINTID

Order status call parameters

Status Call Parameter Description
login Merchant login name.
client_orderid Merchant order identifier of the transaction for which the status is requested.
orderid Order id assigned to the order by Apropay.
control Checksum used to ensure that it is Apropay (and not a fraudster) that initiates the callback for a particular Merchant. This is SHA-1 checksum of the concatenation login + client-order-id + paynet-order-id + merchant-control. See Order status API call authorization through control parameter for more details about generating control checksum.
by-request-sn Serial number from status request.

Order Status Response

Status Response Parameter Description
type The type of response. May be status-response.
status See Status List for details.
amount Amount of the initial transaction.
currency Currency of the initial transaction.
paynet-order-id Order id assigned to the order by Apropay.
merchant-order-id Merchant order id.
phone Customer phone.
html HTML code of 3DS authorization form, encoded in application/x-www-form-urlencoded MIME format. Merchant must decode this parameter before showing the form to the Customer. The Apropay System returns the following response parameters when it gets 3DS authorization form from the Issuer Bank. It contains auth form HTML code which must be passed through without any changes to the client’s browser. This parameter exists and has value only when the redirection HTML is already available. For non-3DS this never happens. For 3DS HTML has value after some short time after the processing has been started.
serial-number Unique number assigned by Apropay server to particular request from the Merchant.
last-four-digits Last four digits of customer credit card number.
bin Bank BIN of customer credit card number.
card-type Type of customer credit card (VISA, MASTERCARD, etc).
gate-partial-reversal Processing gate support partial reversal (enabled or disabled).
gate-partial-capture Processing gate support partial capture (enabled or disabled).
transaction-type Transaction type (sale, reversal, capture, preauth).
processor-rrn Bank Receiver Registration Number.
processor-tx-id Acquirer transaction identifier.
receipt-id Electronic link to receipt https://gate.apropay.com/paynet/view-receipt/ENDPOINTID/receipt-id/.
cardholder-name Cardholder name.
card-exp-month Card expiration month.
card-exp-year Card expiration year.
card-hash-id Unique card identifier to use for loyalty programs or fraud checks.
email Customer e-mail.
bank-name Bank name by customer card BIN.
terminal-id Acquirer terminal identifier to show in receipt.
paynet-processing-date Acquirer transaction processing date.
approval-code Bank approval code.
order-stage The current stage of the transaction processing. See Order Stage for details.
loyalty-balance The current bonuses balance of the loyalty program for current operation. if available
loyalty-message The message from the loyalty program. if available
loyalty-bonus The bonus value of the loyalty program for current operation. if available
loyalty-program The name of the loyalty program for current operation. if available
descriptor Bank identifier of the payment recipient.
error-message If status in declined, error, filtered this parameter contains the reason for decline.
error-code The error code is case status in declined, error, filtered.
by-request-sn Serial number from status request, if exists in request. Warning parameter amount always shows initial transaction amount, even if status is requested by-request-sn.
verified-3d-status See 3-D Secure Status List for details.
verified-rsc-status See Random Sum Check Status List for details.
auxiliary-sessions This parameter contains a list of all initiated by customer on the form auxiliary transactions, which are connected to the master (cashier) transaction. Format: URL encoded JSON array [{“sessionId”:value,”sessionStatus”:”value”},...].
transaction-date Date of final status assignment for transaction.
orig-amount Contains the original request amount if it was converted on auxiliary endpoint in Parallel form integration.
orig-currency Contains the original request currency if it was converted on auxiliary endpoint in Parallel form integration.

Order Status Response Example

type=status-response
&serial-number=00000000-0000-0000-0000-000001c473e3
&merchant-order-id=902B4FF5
&paynet-order-id=2625444
&status=processing
&amount=10.42
&currency=USD
&transaction-type=sale
&receipt-id=a0ad593e-9f45-38dc-b334-54a853faf634
&name=Unknown+holder
&cardholder-name=Unknown+holder
&card-exp-month=12
&card-exp-year=2018
&email=john.smith%40gmail.com
&order-stage=sale_starting
&merchantdata=VIP+customer
&last-four-digits=9999
&bin=999999
&card-type=PARALLEL_FORM
&phone=12063582043
&paynet-processing-date=2017-05-26+16%3A22%3A55+MSK
&by-request-sn=00000000-0000-0000-0000-000001c473d9
&card-hash-id=1226718
&purpose=user_account1
&auxiliary-sessions=%5B%7B%22sessionId%22%3A6781331%2C%22sessionStatus%22%3A%22declined%22%7D%2C%7B%22sessionId%22%3A6781346%2C%22sessionStatus%22%3A%22approved%22%7D%2C%7B%22sessionId%22%3A6781340%2C%22sessionStatus%22%3A%22declined%22%7D%5D
&transaction-date=2023-01-10+12%3A46%3A28+MSK

Status request authorization through control parameter

The checksum is used to ensure that it is Merchant (and not a fraudster) that sends the request to Apropay. This SHA-1 checksum, the parameter control, is created by concatenation of the parameters values in the following order:

  • login
  • client_orderid
  • orderid
  • merchant_control

For example, assume these parameters have the values as listed below:

Parameter Name Parameter Value
login PARL_TEST_Merchant
client_orderid 902B4FF5
orderid 2625444
merchant_control 2DB0DF52-7379-4276-AABF-4E774DEDDCF9

The complete string example may look as follows:

PARL_TEST_Merchant902B4FF526254442DB0DF52-7379-4276-AABF-4E774DEDDCF9

Encrypt the string using SHA-1 algorithm. The resultant string yields the control parameter which is required for authorizing the callback. For the example control above will take the following value:

fbddc45a8cdb0f59199ac9e0c11ea3d6113964d1

Order status debug

endpointid or groupid input your ENDPOINTID or ENDPOINTGROUPID
login input your Login
client_orderid input your Invoice Number
orderid
merchant_control input your Control Key
by-request-sn

String to sign
Signature
              
            
 


3.5.6. Parallel form templates

Parallel form template sample

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
    <!-- country selector -->
    <span id="countryIsoCode" style="display: none;">$!CUSTOMER_IP_COUNTRY_ISO_CODE</span>
    <div class="container">
        <input name="customer_language_code" id="iso" type="hidden" value="$CUSTOMER_LANGUAGE"/>
        #if (!$HAS_PARALLEL_FORM_PAYMENT_METHODS)
        <select id="countrySelector" onchange="onCountrySelected(this);">
            <option value="EU">Europe</option>
                            <!-- You may add other countries for selection to this list -->
        </select>
        #end

        #if ($HAS_PARALLEL_FORM_PAYMENT_METHODS)
        <div class="form-tabs">
            <ul id="formTabs" class="form-tabs-ul">
                #foreach ($paymentMethod in $PARALLEL_FORM_PAYMENT_METHODS)
                <li id="$!{paymentMethod.identifier}-FORM-button" class="form-tab-button#if
                ($velocityCount == 1) form-tab-button-active form-tab-button-active-$!{paymentMethod.identifier}
                #end"#if($paymentMethod.iframe) onclick="chooseIframe('$!{paymentMethod.identifier}');"#end>
                    $!{paymentMethod.name}
                </li>
                #end
            </ul>
            <select id="countrySelector" onchange="onCountrySelected(this);">
                <option value="EU">Europe</option>
                                    <!-- You may add other countries for selection to this list -->
            </select>
        </div>
        #foreach ($paymentMethod in $PARALLEL_FORM_PAYMENT_METHODS)
        <div class="ssl-header ssl-header-$!{paymentMethod.identifier}" id="merchant-description-$!{paymentMethod.identifier}"
        #if ($velocityCount > 1) style="display: none;"#end>
            <span class="ssl-text">${MERCHANT}</span>
            <div>
                <span class="flag-EN" id="flag-$!{paymentMethod.identifier}"></span>
                <select id="langSelector-$!{paymentMethod.identifier}" class="langSelector langSelector-$!{paymentMethod.identifier}"
                onchange="selectLang('$!{paymentMethod.identifier}');">
                    <option value="EN">English</option>
                                            <!-- You may add other languages for selection to this list -->
                </select>
            </div>
        </div>
        <script>
            merchantDescriptionIds.push("merchant-description-$!{paymentMethod.identifier}");
            paymentMethodsCountries["$!{paymentMethod.identifier}"] = "$!{paymentMethod.countries}";
        </script>
        #end
        #end

        #if ($HAS_PARALLEL_FORM_PAYMENT_METHODS)
            #foreach ($paymentMethod in $PARALLEL_FORM_PAYMENT_METHODS)
            #if ($paymentMethod.iframe)
            <div class="frame-container-$!{paymentMethod.identifier} payment-method-iframe"
            id="$!{paymentMethod.identifier}-FORM" pneopen="#if ($velocityCount == 1)true#{else}
            false#end" pnesrc="$!paymentMethod.initSessionUrl" #if ($velocityCount > 1) style="display: none;"#end>
                <iframe src="#if ($velocityCount == 1)$!paymentMethod.initSessionUrl#end" scrolling="#if
                ($!{paymentMethod.identifier} == 'QIWI' || $!{paymentMethod.identifier} == 'ASTROPAY')yes#{else}no#end">
                 </iframe>
            </div>
            #end
            #end

            <form id="waitForm" action="$!WAIT_FORM_URL">
                #foreach( $p in $WAIT_FORM_PARAMETERS )
                <input type="hidden" name="$p.key" value="$!p.value">
                #end
                <!--$!{INTERNAL_SECTION}-->
            </form>
        #end
    </div>
</body>
</html>

The full lists of country and language codes are located in Reference.

Parallel form template macros

Field Name Macro Field Value Macro Description
$!CUSTOMER_IP_COUNTRY_ISO_CODE n/a Customer country defined by IP Address.
$!CUSTOMER_COUNTRY_CODE n/a Billing country of customer sent in incoming API request.
$CUSTOMER_LANGUAGE n/a Customer language send by merchant via input parameters or defined by browser settings if first is not set.
!$HAS_PARALLEL_FORM_PAYMENT_METHODS n/a Determines the availability of parallel form payment methods.
$paymentMethod n/a Payment method object.
$PARALLEL_FORM_PAYMENT_METHODS n/a Array with available parallel form payment methods.
$!{paymentMethod.identifier} n/a Payment method identifier.
$velocityCount n/a Sequence number of the payment method.
$paymentMethod.iframe n/a Iframe of payment method.
$!{paymentMethod.name} n/a Payment method name.
${MERCHANT} n/a End point display name.
$!{paymentMethod.countries} n/a Countries which are set for this payment method.
$!paymentMethod.initSessionUrl n/a URL for payment method session initialization.
$!WAIT_FORM_URL n/a Waiting form URL.
$p n/a Waiting form parameter.
$WAIT_FORM_PARAMETERS n/a Waiting form parameters array.
$p.key n/a Waiting form parameter key.
$!p.value n/a Waiting form parameter value.
$!{INTERNAL_SECTION} n/a Internal for iFrame integration.

Warning

If needed to determine the customer billing country on the data sent via the API, $! CUSTOMER_COUNTRY_CODE is used. If needed to determine the customer billing country on the IP address from the customer browser, use $! CUSTOMER_IP_COUNTRY_ISO_CODE, billing country will also change according to IP.

Parallel form scripts

Here you may find two parallel form scripts which are mandatory needed for it`s operating. The first script should be added into <head> tag of html document:

<script type="text/javascript">
var merchantDescriptionIds = [];
var paymentMethodsCountries = {};
function isCCValid(r) {
    var n = r.length;
    if (n > 19 || 13 > n) return !1;
    for (i = 0, s = 0, m = 1, l = n; i < l; i++) d = parseInt(r.substring(l - i - 1, l - i), 10) * m, s += d >= 10 ? d % 10 + 1 : d, 1 == m ? m++ : m--;
    return s % 10 == 0 ? !0 : !1
}

function runPayment(t) {
    if (isCCValid(t)) {
        return !0;
    } else {
        document.getElementById('cardnumber').style.borderColor = '#fb860f';
        return !1;
    }
}

function chooseIframe(paymentMethodName) {
    var id = paymentMethodName + '-FORM';
    var iframes = document.getElementsByTagName('IFRAME');
    for (var i = 0; i < iframes.length; i++) {
        var iframe = iframes[i].parentNode;
        var isCurrent = iframe.id == id;
        iframe.style.display = isCurrent ? 'block' : 'none';
        if (isCurrent && iframe.getAttribute("pneopen") == 'false') {
            iframe.firstElementChild.src = iframe.getAttribute("pnesrc") + "?country=" + document.getElementById("countryIsoCode").innerText;
            iframe.setAttribute("pneopen", 'true');
        }
        var buttonElem = document.getElementById(iframe.id + '-button');
        buttonElem.className = (iframe.id == id) ? 'form-tab-button form-tab-button-active form-tab-button-active-' + paymentMethodName : 'form-tab-button';
    }
    var descriptionId = 'merchant-description-' + paymentMethodName;
    for (var i = 0; i < merchantDescriptionIds.length; i++) {
        var isCurrent = merchantDescriptionIds[i] == descriptionId;
        document.getElementById(merchantDescriptionIds[i]).style.display = isCurrent ? 'flex' : 'none';
    }
}

function pneInit() {
    window.pneMasterSessionProcessed = function() {
        document.getElementById('waitForm').submit()
    }
    foreach( $paymentMethod in $PARALLEL_FORM_PAYMENT_METHODS )
        if( $paymentMethod.default )chooseIframe('$!{paymentMethod.identifier}-FORM');
        break
    end
    end
}
</script>

Second script should be added to html code before the </body> close tag.

<script type="text/javascript">
function updateTabsVisibility() {
    var countryCode = getSelectedCountryCode();
    var paymentMethods = getPaymentMethods();
    var someIframeShown = false;
    for (var i = 0; i < paymentMethods.length; i++) {
        var paymentMethod = paymentMethods[i];
        var visible = isPaymentMethodVisible(paymentMethod, countryCode);
        updateTabVisibility(paymentMethod, visible);
        if (visible && !someIframeShown) {
            chooseIframe(paymentMethod);
            someIframeShown = true;
        }
    }
}

function getSelectedCountryCode() {
    return document.getElementById('countryIsoCode').innerText;
}

function setSelectedCountryCode(countryCode) {
    document.getElementById('countryIsoCode').innerText = countryCode;
}

function getPaymentMethods() {
    var lis = document.getElementById("formTabs").children;
    var result = [];
    for (var i = 0; i < lis.length; i++) {
        var li = lis[i];
        var id = li.id;
        if (id != null) {
            result.push(id.substring(0, id.indexOf("-FORM-button")));
        }
    }
    return result;
}

function isPaymentMethodVisible(paymentMethodId, countryCode) {
    if (paymentMethodsCountries[paymentMethodId] == "") {
        return true;
    } else {
        return paymentMethodsCountries[paymentMethodId].indexOf(countryCode) > -1;
    }
}

function updateTabVisibility(paymentMethod, visible) {
    document.getElementById(paymentMethod + '-FORM-button').style.display = visible ? 'inline-block' : 'none';
}

function onCountrySelected(selector) {
    setSelectedCountryCode(selector.value);
    updateTabsVisibility();
}

document.addEventListener('DOMContentLoaded', function() {
    pneInit();
    updateTabsVisibility();
    document.getElementById('countrySelector').value = getSelectedCountryCode();
});

function syncLangSelectors(ISO) {
    var methods = getPaymentMethods();
    for (var i = 0; i < methods.length; i++) {
        document.getElementById('flag-' + methods[i]).className = "flag-" + ISO;
        document.getElementById('langSelector-' + methods[i]).value = ISO;
    }
}

var ISO = document.getElementById('iso').value.toUpperCase();
ISO = 'EN';
document.getElementById('iso').value = ISO;
syncLangSelectors(ISO);

document.addEventListener('DOMContentLoaded', function() {
    //l10n();
});

function selectLang(method) {
    var ISO = document.getElementById('langSelector-' + method).value.toUpperCase();
    document.getElementById('iso').value = ISO;

    syncLangSelectors(ISO);
    //l10n();
}
</script>

Waiting form template

<html>
<head>
    <script type="text/javascript">
      function fc(t) {
        document.getElementById("seconds-remaining").innerHTML = t;
        (t > 0) ? setTimeout(function(){fc(--t);}, 1000) : document.checkform.submit();}
    </script>
</head>
<body onload="fc($!refresh_interval)">
    <h3>Order #$!MERCHANT_ORDER_ID - $!ORDERDESCRIPTION</h3>
    <h3>Total amount: $!AMOUNT $!CURRENCY to $!MERCHANT</h3>
    Please wait, your payment is being processed, remaining <span id="seconds-remaining">&nbsp;</span> seconds.
    <form name="checkform" method="post">
        <input type="hidden" name="tmp" value="$!uuid"/>
        $!{INTERNAL_SECTION}
        <input type="submit" value="Check" />
    </form>
</body>
</html>

Waiting form template macros

Field Name Macro Field Value Macro Description
$!refresh_interval n/a Refresh interval recommended by system.
$!MERCHANT_ORDER_ID n/a Merchant order id.
$!ORDERDESCRIPTION n/a Order description.
$!AMOUNT n/a Amount.
$!CURRENCY n/a Currency.
$!MERCHANT n/a End point display name.
$!uuid n/a Internal.
$!{INTERNAL_SECTION} n/a Internal for iFrame integration.

Finish form template

<html>
    <head>
    </head>
    <body>
        <h3>Processing of the payment has finished</h3>
        <h3>Order Invoice: $!{MERCHANT_ORDER_ID}</h3>
            <h3>Order ID: $!{PAYNET_ORDER_ID}</h3>
            <h3>Status: $!{STATUS}</h3>

        #if($ERROR_MESSAGE)
            <h3>Error: $!{ERROR_MESSAGE}</h3>
        #end
    </body>
</html>

Finish form template macros

Macros for the master and auxiliary finishing forms are the same.

Field Name Macro Field Value Macro Description
$!{MERCHANT_ORDER_ID} n/a Merchant order id.
$!{PAYNET_ORDER_ID} n/a Apropay order id.
$!{STATUS} n/a Order status.
$!{ERROR_MESSAGE} n/a Error message.
${CUSTOMER_REDIRECT_URL} n/a URL the cardholder will be redirected to upon completion of the transaction.

Auxiliary finish form template

<html>
    <head>
    </head>
    <body>
        <div class="container">
            <div class="main">
                <h2 class="summary__title">Deposit <span class="status-title">${STATUS}</span></h2>
                <div class="back">
                    <a class="link" target="_parent" href="${CUSTOMER_REDIRECT_URL}">Back to merchant website</a>
                </div>
            </div>
        </div>
    </body>
</html>