NAV

For any question, we are one click away

Contact us

Getting Started

We offer multiple ways of adding payments to your website.

Simple Integration

First to consider are simple ways of integration that don't require any development effort on your part.

Invoicing from Merchant Portal

Every Merchant gets a login to their Personal Area of the Merchant Portal. There you can manage and monitor payment transactions, configure payment options, or send an invoice with a payment link directly to your customer's E-mail. So technically, you don't even need an online store running to start accepting payments. This method is also useful when you need to invoice a customer for an arbitrary amount.

CMS Plugins

We developed ready-made plugins for the most popular site management systems (CMSs). Install the plugin on your CMS and start accepting payments. Explore available plugins here.

Redirect Customer to Payment Page from Checkout

With this method, you get to provide your customers with a smooth and secure checkout process leveraging our payment page. The main advantage is that you don't need to collect and process card data on your website. You can even customize some elements of the payement page like using your logo, changing the page footer, etc.

Advanced integration

Consider advanced integration options if you need to create a tailored payment flow. This will require in-house or third-party coding expertise.

API

Use our Merchant API to create the payemnt flow you need. For example, you can design your own fully customized payment page and connect it to our Payment Gateway.

Also keep in mind that if your flow involves handling cardholder data, your business and infrastructure must be complient with strict security standards (SAQ-D, ASV Scan, AoC)

SDKs

Another way to create custom solutions and enchance your apps is to use our SDKs for Mobile and Web.

Mobile SDK

Mobile SDKs let you integrate payments right into your iOS or Android App.

Web SDK

Use the Web SDK to embed payments on your hardcoded (non-CMS) website.

Pay by link

You can issue an invoice to the buyer for payment for goods or services by e-mail. For this, use the Invoice to e-mail section ( in the navigation bar to the left). Once the invoice is issued, the buyer receives an e-mail and follows the link in it to the payment page.

To invoice a customer and send them a link to the payment page by email, follow these steps.

  1. Go to Invoice to e-mail section of the Personal Area. The page for entering the invoice parameters will be displayed:

  2. Configure the settings referring to the table below.

Setting Description
Payment type Choose from two options.
  • One-phase – after the payment has been made, no additional actions are required on your part.
  • Two-phase – after the client has confirmed the payment, you must complete the payment in your Personal Area. Before you do this, the money will be held (reserved) on the client's account until you confirm the payment or until the confirmation period expires.
    If you confirm the payment, the money will be transferred to your account.
    The reserved funds on client's account will be released if the reservation period expires before confirmation.
Client name Client's first name, last name, and patronymic. The data entered in this field is displayed in an email containing a link to the payment page.
E-mail The e-mail address to which the payment link will be sent.
Due date Indicate the date and time by which the payment can be made. After this date and time it will be impossible to pay the invoice.
Client ID Client number in your store’s system. If you specify this parameter, the client will see the Save my card check box on the payment page. If the client selects this check box, a binding will be created after the payment is completed, and the client will not have to enter the card data next time.
Description Free-form description of the payment.
Enter the amount Enter the payment amount here. If the order contains a shopping cart, the field value is populated automatically.
  1. Click the Send button. Upon successful dispatch, a link to the payment form will be displayed below:

You can view the payment page sent to the client by clicking on the Link to payment page button.

Adding a shopping cart to invoice

When generating an invoice you can add a shopping cart for the order. The Cart section is located under the area for creating a link to payment page:

  1. To add a goods item to the shopping cart, click on the Add product button. A row with the parameters of the product being added will be displayed.
  2. Fill in the required fields referring to the table below.
Field Description
ID Identifier of a goods item in the cart. Filled in automatically.
Name Product/service name.
Price Price of one product unit.
Qty The number of units of the product.
Measure Units of measurement, for example: L – liters, pcs. – pieces.
Amount The total amount for specified goods item. Calculated automatically when the Price and Qty fields are filled out.
Article The vendor code of the goods item.
  1. Repeat the required steps for each item in the shopping cart. If you need to delete the added row, click on the icon.

Having added all items to the shopping cart, invoice the client.

Making a test transaction

You can test the payment process on behalf of the client. To do so:

  1. Create an invoice for the client.
  2. Go to the payment page by clicking on the Link to payment page button in the invoice-issued-successfully message.
  3. Enter the details of one of the test cards. Leave the Cardholder name field blank.
  4. Select Save my card if you want to create a binding: in this case, you will not have to enter the card data next time.
  5. Click on the Pay button. To confirm the transaction, use the 3-D Secure code specified for the test card.

Redirect integration

Redirect integration

  1. A customer selects a product in the online store, and then clicks Buy.
  2. The online store server receives a purchase request.
  3. The online store server contacts the payment gateway server.
  4. The payment gateway server creates an order, generates a payment link, and send it to the online store server.
  5. The online store redirects the customer to the received URL.
  6. The payment gateway opens the payment URL.
  7. The customer enters his or her card number, expiration date, and CVV/CVC, and clicks Pay.
  8. The payment gateway processes the payment request and displays confirmation of the successful payment to the customer.
  9. The customer returns to the online store page or closes the page.

Purchases with redirect

An example of how to register an order.

register.do

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/register.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data amount=2000 \
  --data currency=978 \
  --data userName=test_user \
  --data password=test_user_password \
  --data returnUrl=finish.html \
  --data description=my_first_order \
  --data language=en
{
  "orderId": "0179018d-8f96-7fbe-bc2b-4b7e00a7d8c0",
  "formUrl": "https://dev.bpcbt.com/payment/merchants/rbs/payment_en.html?mdOrder=0179018d-8f96-7fbe-bc2b-4b7e00a7d8c0"
}

Alternatively, you can hold the amount on account before the charge by using the registerPreAuth.do call. For more details about hold and capture, click here.

The merchant operator periodically (manually) checks the order status via the merchant portal to identify the payment result.

Apple Pay, Google Pay, Samsung Pay - Redirect Integration

The Payment Gateway supports tokenized payments using Apple Pay, Google Pay, and Samsung Pay wallets.

To use wallet payments in Redirect Integration, you have to set them up in your Personal Area on Merchant Portal. See the docs below:

Direct Payment

Purchase

Make a purchase and save the card by creating a binding.

Direct integration

  1. A customer selects a product in the online store, and then clicks Buy.
  2. The online store server receives a purchase request and opens a payment page.
  3. The customer enters their card details on the online store payment page.
  4. The online store server collects the card data.
  5. The online store server registers an order with clientId and sends card data to a payment gateway.
  6. The payment gateway communicates with the Directory Server to reach the ACS. It returns all the data necessary for the ACS redirect to the online store.
  7. The online store server redirects the customer to the payment gateway.
  8. The payment gateway redirects the customer to the ACS.
  9. The cardholder confirms the order and the ACS redirects him or her to the payment gateway.
  10. The customer returns to the online store page or closes the page.
  11. The payment gateway sends an asynchronous callback notification to the online store server.
  12. The online store server checks the order status to get bindingId for further recurring payments.

Register with clientId

An example of how to register an order. register.do

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/register.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data amount=2000 \
  --data currency=978 \
  --data userName=test_user \
  --data password=test_user_password \
  --data returnUrl=finish.html \
  --data description=my_first_order \
  --data language=en
{
  "orderId": "0179018d-8f96-7fbe-bc2b-4b7e00a7d8c0",
  "formUrl": "https://dev.bpcbt.com/payment/merchants/rbs/payment_en.html?mdOrder=0179018d-8f96-7fbe-bc2b-4b7e00a7d8c0"
}

Alternatively, you can hold the amount on account before the charge by using the registerPreAuth.do call. For more details about hold and capture, click here.

paymentOrder method

paymentOrder.do

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/paymentorder.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data userName=test_user \
  --data password=test_user_password \
  --data MDORDER=019dbf02-e9f4-7fe2-b1c2-d50500a7d8c0 \
  --data '$PAN=4012001038166662' \
  --data '$CVC=123' \
  --data YYYY=2024 \
  --data MM=12 \
  --data 'TEXT=TEST CARDHOLDER' \
  --data 'ip=185.230.240.201' \
  --data language=en
{
  "info": "Your order is proceeded, redirecting...",
  "errorCode": 0,
  "acsUrl": "https://web.rbsuat.com/acs/auth/start.do",
  "paReq": "eJxVUtFu4jAQ/BWU92DHcSCpFle946ryAEd7FKl9OZl4gbSNA05ypP36s0NSWsmSd8br3fGO4brJ3wb/0JRZoSdeMKTeAHVaqEzvJt7j6taPvWsBq71BnP7BtDYoYI5lKXc4yNTEG48kj5KN8jfxOPH5NqZ+kiTURxYlSEMaxtvUE7C8ecCjgK6RsH2GDEgPbUWT7qWuBMj0+GO2EJyNR5QC6SDkaGZTEfGQhRzIGYGWOYpSarUpmr95VwJIS0Na1Loy72LEQyA9gNq8iX1VHa4IqbCshmmRA3EkkIuGZe2i0hZpMiUWH/en39NZs3j5xearHZ+vnk6LD7tPnyZAXAYoWaFglAWUB8mAjq/simIgLQ8yd93tefugM4CD63Hz9eQrA3bQxvrQy+8RYHMoNLo7QD5jeHDGCNgaPNZtXgTkAgC1OmdYiZwGNLB3ewpIv19e/fPO+ZBWdsYvxamWr6rcnNaqWMuQrbF+zqLlXbQ7OHfaJKcqs9NlPDjLcgCIK0M640n3Z2z07S/9Bypv08k=",
  "termUrl": "https://dev.bpcbt.com/payment/rest/finish3ds.do?lang=en"
}

Redirect to ACS

If 3-D Secure is required, then, after receiving a paymentOrder response, the customer must be redirected to ACS. There are two ways to do that: regular and simplified.

Regular redirect

If a payment is made with 3-D Secure, merchants must redirect their customers to ACS using the address specified in acsUrl. The request body must be MD=mdorder&PaReq=pareq&TermUrl=termUrl, where:

It must be a POST request (not GET).

Depending on the configuration agreed with your bank, the customer after ACS authentication will be redirected either to the store or to the payment gateway.

Example of a POST request for regular redirect:

<html>
<head><title>ACS Redirect</title></head>
<body onload="document.forms['acs'].submit()">
ACS Redirect
<form id="acs" method="post" action="[result.acsUrl]">
    <input type="hidden" id="MD" name="MD" value="[MD]"/>
    <input type="hidden" id="PaReq" name="PaReq" value="[result.PaReq]"/>
    <input type="hidden" id="TermUrl" name="TermUrl" value="[result.TermUrl]"/>
</form>
</body>
</html>

Simplified redirect

Alternatively, the online store can use the gateway acsRedirect method, which will perform the same cardholder redirect to the issuer ACS.

Get status for bindingId

getOrderStatusExtended.do

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/getOrderStatusExtended.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data userName=test_user \
  --data password=test_user_password \
  --data orderId=017908cc-57c6-739a-ad25-df0d00a7d8c0 \
  --data language=en
{
  "errorCode": "0",
  "errorMessage": "Success",
  "orderNumber": "11044",
  "orderStatus": 1,
  "actionCode": 0,
  "actionCodeDescription": "",
  "amount": 2000,
  "currency": "978",
  "date": 1618815949170,
  "orderDescription": "my_second_order",
  "ip": "185.230.240.201",
  "merchantOrderParams": [
    {
      "name": "browser_language_param",
      "value": "en"
    },

    {
      "name": "recurringExpiry",
      "value": "20240101"
    },
    {
      "name": "recurringFrequency",
      "value": "5"
    },

    {
      "name": "browser_os_param",
      "value": "UNKNOWN"
    },
    {
      "name": "user_agent",
      "value": "curl/7.75.0"
    },
    {
      "name": "browser_name_param",
      "value": "DOWNLOAD"
    }
  ],
  "transactionAttributes": [],
  "attributes": [
    {
      "name": "mdOrder",
      "value": "017908cc-57c6-739a-ad25-df0d00a7d8c0"
    }
  ],
  "cardAuthInfo": {
    "maskedPan": "401200**6662",
    "expiration": "202412",
    "cardholderName": "TEST CARDHOLDER",
    "approvalCode": "123456",
    "pan": "401200**6662"
  },
  "bindingInfo": {
    "clientId": "659753456",
    "bindingId": "0162d467-bbfe-77f3-9c21-415c00a7d8c0"
  },
  "authDateTime": 1618816213981,
  "terminalId": "123456",
  "authRefNum": "012851192298",
  "paymentAmountInfo": {
    "paymentState": "APPROVED",
    "approvedAmount": 2000,
    "depositedAmount": 0,
    "refundedAmount": 0
  },
  "bankInfo": {
    "bankCountryCode": "UNKNOWN",
    "bankCountryName": "&ltUnknown&gt"
  }
}

Recurring payment

Merchant initiates a monthly recurring payment

Recurrent payment

  1. The online store server registers an order and conducts a payment with bindingId.
  2. The online store can check the payment status or wait for a signed callback.

Register subsequent recurring payment

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/register.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data userName=test_user \
  --data password=test_user_password \
  --data amount=2000 \
  --data currency=978 \
  --data clientId=259753456 \
  --data description=my_first_order \
  --data returnUrl=finish.html \
  --data language=en \
  --data features=AUTO_PAYMENT
{
  "orderId": "01791274-d9ca-7103-b148-7dc000a7d8c0",
  "formUrl": "https://dev.bpcbt.com/payment/merchants/rbs/payment_en.html?mdOrder=01791274-d9ca-7103-b148-7dc000a7d8c0"
}

Ignore formUrl in register response. You don't need it for recurrent payment. Next call paymentOrderBinding.do from your server to make a recurrent payment.

Recurring payment with bindingId

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/paymentOrderBinding.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data userName=test_user \
  --data password=test_user_password \
  --data mdOrder=01791274-d9ca-7103-b148-7dc000a7d8c0 \
  --data bindingId=01491394-63a6-7d45-a88f-7bce00a7d8c0 \
  --data ip=1d0d:db8:6:1::77 \
  --data language=en
{
  "redirect": "https://dev.bpcbt.com/payment/merchants/rbs/finish.html?orderId=01791274-d9ca-7103-b148-7dc000a7d8c0&lang=en",
  "info": "Your order is proceeded, redirecting...",
  "errorCode": 0
}

Check subsequent recurring order status

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/getOrderStatusExtended.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data userName=test_user \
  --data password=test_user_password \
  --data orderId=01791274-d9ca-7103-b148-7dc000a7d8c0 \
  --data language=en
{
  "errorCode": "0",
  "errorMessage": "Success",
  "orderNumber": "11045",
  "orderStatus": 2,
  "actionCode": 0,
  "actionCodeDescription": "",
  "amount": 2000,
  "currency": "978",
  "date": 1618816612879,
  "orderDescription": "my_first_order",
  "ip": "1d0d:db8:6:1::77",
  "merchantOrderParams": [
    {
      "name": "browser_language_param",
      "value": "en"
    },
    {
      "name": "browser_os_param",
      "value": "UNKNOWN"
    },
    {
      "name": "user_agent",
      "value": "curl/7.75.0"
    },
    {
      "name": "browser_name_param",
      "value": "DOWNLOAD"
    }
  ],
  "transactionAttributes": [],
  "attributes": [
    {
      "name": "mdOrder",
      "value": "01791274-d9ca-7103-b148-7dc000a7d8c0"
    }
  ],
  "cardAuthInfo": {
    "maskedPan": "555555**5599",
    "expiration": "202412",
    "cardholderName": "TEST CARDHOLDER",
    "approvalCode": "123456",
    "pan": "555555**5599"
  },
  "bindingInfo": {
    "clientId": "259753456",
    "bindingId": "01491394-63a6-7d45-a88f-7bce00a7d8c0"
  },
  "authDateTime": 1618816705914,
  "terminalId": "123456",
  "authRefNum": "947633173729",
  "paymentAmountInfo": {
    "paymentState": "DEPOSITED",
    "approvedAmount": 2000,
    "depositedAmount": 2000,
    "refundedAmount": 0
  },
  "bankInfo": {
    "bankCountryCode": "UNKNOWN",
    "bankCountryName": "UNKNOWN"
  }
}

Apple / Google Pay / Samsung Pay - Direct Integration

The Payment Gateway supports tokenized payments using Apple Pay, Google Pay, and Samsung Pay wallets.

Secure card data transfer

If you collect card data on your side and don't want it to be present on your server, you should use seToken.

Please note that seToken can be generated via SDK.

Click here to get more information about seToken.

After the payment

Once a payment is made, you can manage it in your Personal Area on Merchant Portal or over the API. Click on the links below to learn more.

Issuing a refund

Partial refund

Refund money

  1. An online store employee selects an order in an online store dashboard.
  2. The online store dashboard sends a refund request to its server.
  3. The online store server calls refund.do.

refund.do

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/refund.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data userName=test_user \
  --data password=test_user_password \
  --data orderId=017908cc-57c6-739a-ad25-df0d00a7d8c0 \
  --data amount=2000 \
  --data language=en
{
  "errorCode": "0",
  "errorMessage": "Success"
}

Reversing a payment

In case of a two-phase payment flow, you can reverse a payment, that is - release the funds that were put on hold.

Capturing a payment

In case of a two-phase payment flow, the funds are first put on hold, and only after that the charge is made. Capturing can be set up automatically according to configurable rules, or can be done manually on Merchant Portal or over the API.

Initiate funds capture when goods are actually shipped

Capture money

  1. An online store employee selects an order in an online store dashboard.
  2. The online store dashboard sends a capture request to its server.
  3. The online store server calls deposit.do.

deposit.do

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/deposit.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data userName=test_user \
  --data password=test_user_password \
  --data amount=2000 \
  --data orderId=017908cc-57c6-739a-ad25-df0d00a7d8c0 \
  --data language=en
{
  "errorCode": "0",
  "errorMessage": "Success"
}

Getting the order status

The status of the order is available on the Merchant Portal and can also be retrieved over the API.

Callback notifications

The payment gateway API allows you to receive callback notifications on changes of payment statuses.

General information

Events that can trigger notifications

You can receive notifications about changes in order payment status and other events in the Payment Gateway.

The most common notifications describe changes in order status, such as:

More advanced integrations may make use of additional callback triggers like:

The trigger type is passed in the operation parameter of the callback (see details below). For convenience, the callbacks for addional triggers can be directed to another URL by using the dynamicCallbackUrl parameter in order registration requests.

Integration with callback

Instead of the last step of the Redirect integration you may choose to use one of the following approaches.

Make use of returnUrl

When your web-site code located at returnUrl (for example, https://mybestmerchantreturnurl.com/?back&orderId=61c33664-85a0-7d6b-af26-09ee009c4000&lang=en) identifies a cardholder being redirected back from the gateway after a payment attempt, you can check the order status using the API request getOrderStatusExtended.
This option is the easiest one but it is not completely reliable because the cardholder redirect may fail (for example, as a result of a broken connection or the cardholder closing the browser) and returnUrl may not get the "trigger" to proceed with getOrderStatusExtended.

getOrderStatusExtended.do

curl --request POST \
  --url https://dev.bpcbt.com/payment/rest/getOrderStatusExtended.do \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data userName=test_user \
  --data password=test_user_password \
  --data orderId=016b6f47-4628-7ea2-80f5-6c6e00a7d8c0 \
  --data language=en
{
  "errorCode": "0",
  "errorMessage": "Success",
  "orderNumber": "11008",
  "orderStatus": 2,
  "actionCode": 0,
  "actionCodeDescription": "",
  "amount": 2000,
  "currency": "978",
  "date": 1618577250840,
  "orderDescription": "my_first_order",
  "merchantOrderParams": [
    {
      "name": "browser_language_param",
      "value": "en"
    },
    {
      "name": "browser_os_param",
      "value": "UNKNOWN"
    },
    {
      "name": "user_agent",
      "value": "curl/7.75.0"
    },
    {
      "name": "browser_name_param",
      "value": "DOWNLOAD"
    }
  ],
  "transactionAttributes": [],
  "attributes": [
    {
      "name": "mdOrder",
      "value": "016b7747-c4ed-70b3-bc36-fdd400a7d8c0"
    }
  ],
  "cardAuthInfo": {
    "maskedPan": "555555**5599",
    "expiration": "202412",
    "cardholderName": "TEST CARDHOLDER",
    "approvalCode": "123456",
    "pan": "555555**5599"
  },
  "authDateTime": 1618577288377,
  "terminalId": "123456",
  "authRefNum": "931793605827",
  "paymentAmountInfo": {
    "paymentState": "DEPOSITED",
    "approvedAmount": 2000,
    "depositedAmount": 2000,
    "refundedAmount": 0
  },
  "bankInfo": {
    "bankCountryCode": "UNKNOWN",
    "bankCountryName": "&ltUnknown&gt"
  }
}

Make use of a signed gateway callback

If you know how to handle digital certificates and signatures, you can use a digitally signed callback with a checksum that the gateway may be configured to send. A checksum is used for verification and security purposes. After the callback signature has been verified on your side, there is no need to send getOrderStatusExtended because the callback includes the order status.

https://mybestmerchantreturnurl.com/callback/?mdOrder=1234567890-098776-234-522&orderNumber=0987&checksum=DBBE9E54D42072D8CAF32C7F660DEB82086A25C14FD813888E231A99E1220AB3&operation=deposited&status=1

Types of notifications

Notifications without checksums

These notifications contain only information about the order, so potentially, the merchant risks accepting a notification sent by an attacker as genuine.

Notifications with checksums

These notifications contain an authentication code in addition to order information. The authentication code is a checksum of order data. This checksum allows to make sure that the callback notification is genuine and was sent by the payment gateway.
There are two methods of implementing callback notifications with checksums:


The public key can be downloaded from the payment gate Web console. For more security, it is recommended to use asymmetric cryptography.
To enable notifications with checksums as well as to get the relevant cryptographic key, please, contact our technical support.

Requirements for SSL certificates on the store's website

If an HTTPS connection is used to access a store that receives callback notifications, the certificate of the site where the store is located must meet the following requirements (see the table below).

Requirement Description
Signature algorithm. Not lower than SHA-256..
Supported certification authorities.. Below are examples of organizations that register digital certificates:
  • Thawte Consulting cc – https://www.thawte.com/;
  • VeriSign – https://www.verisign.com/;
  • DigiCert Inc – https://www.digicert.com/;
  • COMODO CA Limited – https://www.comodo.com/;
  • GeoTrust Inc. – https://www.geotrust.com/;
  • GlobalSign – https://www.globalsign.com/;
  • Trustis Limited – http://www.trustis.com/;
  • UniTrust – http://www.unitrust.co.uk/.

There are also opportunities to register digital certificates via providers.
Self signed certificates are not allowed. The certificate must be signed by a trusted certification authority (see the above list).

URL format for callback notifications

Notification without a checksum

https://myshop.com/callback/?mdOrder=
1234567890-098776-234-522&orderNumber=0987&operation=deposited&
callbackCreationDate=Mon Jan 31 21:46:52 UTC 2022&status=0 

Notification with a checksum

https://mybestmerchantreturnurl.com/callback/?mdOrder=1234567890-098776-234-522&
orderNumber=0987&checksum=DBBE9E54D42072D8CAF32C7F660DEB82086A25C14FD813888E231A99E1220AB3&
operation=deposited&callbackCreationDate=Mon Jan 31 21:46:52 UTC 2022&status=0

The passed parameters are shown in the table below.

The table contains only basic parameters. You can add other parameters you want to receive in your personal cabinet.

Parameter Description
mdOrder Unique order number stored in the payment gateway.
orderNumber Unique order number (identifier) in merchant's system.
checksum Authentication code (checksum) resulting from received parameters.
operation Type of event that triggered notification:
  • approved - funds are put on hold on buyer's account;
  • deposited - order deposited;
  • reversed - payment was reversed;
  • refunded - order was refunded;
  • binding created - payer's card has been saved (a binding was created);
  • binding_activity_changed - an existing binding was disabled/enabled;
  • declined_by_timeout - payment was declined because it timed out;
  • declined_cardpresent - a declined card-present transaction (payment with physical card).
status Indicates if an operation was successfully processed:
  • 1 - success;
  • 0 - fail.

Custom headers for callback notifications

In the Admin Panel, in the merchant settings, you can set custom headers for callback notifications. For example:

'http://mybestmerchantreturnurl.com/callback.php', headers={Authorization=token, Content-type=plain
/text}, params={orderNumber=349002, mdOrder=5ffb1899-cd1e-7c1e-8750-e98500093c43, operation=deposited, status=1}

where {Authorization=token, Content-type=plain/text} is a custom header.

Examples

Example of a notification URL without a checksum

https://mybestmerchantreturnurl.com/callback/?mdOrder=1234567890-098776-234-522&orderNumber=0987&operation=deposited&status=0

Example of a notification URL with a checksum

https://mybestmerchantreturnurl.com/callback/?mdOrder=1234567890-098776-234-522&orderNumber=0987&checksum=DBBE9E54D42072D8CAF32C7F660DEB82086A25C14FD813888E231A99E1220AB3&operation=deposited&status=0

Algorithm for processing callback notifications

Sections below contain notification processing algorithms depending on notification type.

Notification without a checksum

  1. The payment gateway sends to the merchant's server the following request.
    https://mybestmerchantreturnurl.com/callback/?mdOrder=1234567890-098776-234-522&orderNumber=0987&operation=deposited&status=0
  2. The merchant's server returns HTTP 200 OK to the payment gateway.

Notification with a checksum

  1. The payment gateway sends the following HTTPS request to the merchant's server - please, note that:

    • when using symmetric cryptography, the checksum is generated using a key common for the payment gateway and the merchant;
    • when using asymmetric cryptography, the checksum is generated using a private key known only to the payment gateway.
      https://mybestmerchantreturnurl.com/path?amount=123456&orderNumber=10747&checksum=DBBE9E54D42072D8CAF32C7F660DEB82086A25C14FD813888E231A99E1220AB3&mdOrder=3ff6962a-7dcc-4283-ab50-a6d7dd3386fe&operation=deposited&status=1
      The order of the parameters in a notification can be arbitrary.
  2. On the merchant's side checksum parameter is removed from the notification parameter string, and the value of this parameter (checksum) is saved for verifying the notification's authenticity.

  3. The parameters and their values that are left are used for creating the following string.
    parameter_name1;paramenter_value1;parameter_name2;paramenter_value2;…;parameter_nameN;paramenter_valueN;
    In this case pairs name_parameter;value_parameter must be sorted in direct alphabetical order (ascending) by parameter names.
    Here is an example of a generated parameter string
    amount;123456;mdOrder;3ff6962a-7dcc-4283-ab50-a6d7dd3386fe;operation;deposited;orderNumber;10747;status;1;

  4. The checksum is calculated on the merchant's side, the method of calculation depends on the method of its formation:

    • when using symmetric cryptography - with the help of HMAC-SHA256 algorithm and a private key shared with the payment gateway;
    • when using asymmetric cryptography - with the help of a hashing algorithm that depends on how the key pair is created and a public key that is associated with a private key located in the payment gateway.
  5. In the resulting checksum string, all lower-case letters are replaced by upper-case letters.

  6. The resulting value must be compared with the checksum extracted earlier from checksum parameter.

  7. If the checksums match, the server sends an HTTP code 200 OK to the payment gateway.

If the checksums match, this notification is authentic and was sent by the payment gateway. Otherwise, it is likely that the attacker is trying to pass off his notification as a payment gateway notification.

When notifications fail

If a response other than 200 OK is returned to the payment gateway, the notification is considered unsuccessful. In this case, the payment gateway repeats the notification at intervals of 30 seconds until one of the following conditions is met:

When one of the above conditions is met, attempts to send a callback notification about an event stop.

Code examples

Symmetric cryptography

Java
package net.payrdr.test;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.Map;
import java.util.stream.Collector;

public class SymmetricCryptographyExample {

    private static final String secretToken = "ooc7slpvc61k7sf7ma7p4hrefr";
    private static final Map<String, String> callbackParams = Map.of(
            "checksum", "EAF2FB72CAB99FD5067F4BA493DD84F4D79C1589FDE8ED29622F0F07215AA972",
            "mdOrder", "06cf5599-3f17-7c86-bdbc-bd7d00a8b38b",
            "operation", "approved",
            "orderNumber", "2003",
            "status", "1"
    );

    public static void main(String[] args) throws Exception {
        String signedString = callbackParams.entrySet().stream()
                .filter(entry -> !entry.getKey().equals("checksum"))
                .sorted(Map.Entry.comparingByKey(Comparator.naturalOrder()))
                .collect(Collector.of(
                        StringBuilder::new,
                        (accumulator, element) -> accumulator
                                .append(element.getKey()).append(";")
                                .append(element.getValue()).append(";"),
                        StringBuilder::append,
                        StringBuilder::toString
                ));

        byte[] mac = generateHMacSHA256(secretToken.getBytes(), signedString.getBytes());
        String signature = callbackParams.get("checksum");

        boolean verified = verifyMac(signature, mac);
        System.out.println("signature verification result: " + verified);
    }

    private static boolean verifyMac(String signature, byte[] mac) {
        return signature.equals(bytesToHex(mac));
    }

    public static byte[] generateHMacSHA256(byte[] hmacKeyBytes, byte[] dataBytes) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(hmacKeyBytes, "HmacSHA256");

        Mac hMacSHA256 = Mac.getInstance("HmacSHA256");
        hMacSHA256.init(secretKey);

        return hMacSHA256.doFinal(dataBytes);
    }

    private static String bytesToHex(byte[] bytes) {
        final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
        byte[] hexChars = new byte[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars, StandardCharsets.UTF_8);
    }
}

Asymmetric cryptography

Java
package net.payrdr.test;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Comparator;
import java.util.Map;
import java.util.stream.Collector;

public class AsymmetricCryptographyExample {

    private static final Map<String, String> callbackParams = Map.of(
            "amount", "35000099",
            "sign_alias", "SHA-256 with RSA",
            "checksum", "163BD9FAE437B5DCDAAC4EB5ECEE5E533DAC7BD2C8947B0719F7A8BD17C101EBDBEACDB295C10BF041E903AF3FF1E6101FF7DB9BD024C6272912D86382090D5A7614E174DC034EBBB541435C80869CEED1F1E1710B71D6EE7F52AE354505A83A1E279FBA02572DC4661C1D75ABF5A7130B70306CAFA69DABC2F6200A698198F8",
            "mdOrder", "12b59da8-f68f-7c8d-12b5-9da8000826ea",
            "operation", "deposited",
            "status", "1");

    private static final String certificate =
            "MIICcTCCAdqgAwIBAgIGAWAnZt3aMA0GCSqGSIb3DQEBCwUAMHwxIDAeBgkqhkiG9w0BCQEWEWt6" +
                    "bnRlc3RAeWFuZGV4LnJ1MQswCQYDVQQGEwJSVTESMBAGA1UECBMJVGF0YXJzdGFuMQ4wDAYDVQQH" +
                    "EwVLYXphbjEMMAoGA1UEChMDUkJTMQswCQYDVQQLEwJRQTEMMAoGA1UEAxMDUkJTMB4XDTE3MTIw" +
                    "NTE2MDEyMFoXDTE4MTIwNTE2MDExOVowfDEgMB4GCSqGSIb3DQEJARYRa3pudGVzdEB5YW5kZXgu" +
                    "cnUxCzAJBgNVBAYTAlJVMRIwEAYDVQQIEwlUYXRhcnN0YW4xDjAMBgNVBAcTBUthemFuMQwwCgYD" +
                    "VQQKEwNSQlMxCzAJBgNVBAsTAlFBMQwwCgYDVQQDEwNSQlMwgZ8wDQYJKoZIhvcNAQEBBQADgY0A" +
                    "MIGJAoGBAJNgxgtWRFe8zhF6FE1C8s1t/dnnC8qzNN+uuUOQ3hBx1CHKQTEtZFTiCbNLMNkgWtJ/" +
                    "CRBBiFXQbyza0/Ks7FRgSD52qFYUV05zRjLLoEyzG6LAfihJwTEPddNxBNvCxqdBeVdDThG81zC0" +
                    "DiAhMeSwvcPCtejaDDSEYcQBLLhDAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAfRP54xwuGLW/Cg08" +
                    "ar6YqhdFNGq5TgXMBvQGQfRvL7W6oH67PcvzgvzN8XCL56dcpB7S8ek6NGYfPQ4K2zhgxhxpFEDH" +
                    "PcgU4vswnhhWbGVMoVgmTA0hEkwq86CA5ZXJkJm6f3E/J6lYoPQaKatKF24706T6iH2htG4Bkjre" +
                    "gUA=";

    public static void main(String[] args) throws Exception {

        String signedString = callbackParams.entrySet().stream()
                .filter(entry -> !entry.getKey().equals("checksum") && !entry.getKey().equals("sign_alias"))
                .sorted(Map.Entry.comparingByKey(Comparator.naturalOrder()))
                .collect(Collector.of(
                        StringBuilder::new,
                        (accumulator, element) -> accumulator
                                .append(element.getKey()).append(";")
                                .append(element.getValue()).append(";"),
                        StringBuilder::append,
                        StringBuilder::toString
                ));

        InputStream publicCertificate = new ByteArrayInputStream(Base64.getDecoder().decode(certificate));
        String signature = callbackParams.get("checksum");

        boolean verified = checkSignature(signedString.getBytes(), signature.getBytes(), publicCertificate);
        System.out.println("signature verification result: " + verified);
    }

    private static boolean checkSignature(byte[] signedString, byte[] signature, InputStream publicCertificate) throws Exception {
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        X509Certificate x509Cert = (X509Certificate) certFactory.generateCertificate(publicCertificate);

        Signature signatureAlgorithm = Signature.getInstance("SHA512withRSA");
        signatureAlgorithm.initVerify(x509Cert.getPublicKey());
        signatureAlgorithm.update(signedString);

        return signatureAlgorithm.verify(decodeHex(new String(signature)));
    }

    private static byte[] decodeHex(String hex) {
        int l = hex.length();
        byte[] data = new byte[l / 2];
        for (int i = 0; i < l; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }
}

Symmetric cryptography

PHP
<?php

$data = 'amount;123456;mdOrder;3ff6962a-7dcc-4283-ab50-a6d7dd3386fe;operation;deposited;orderNumber;10747;status;1;';
$key = 'yourSecretToken';
$hmac = hash_hmac ( 'sha256' , $data , $key);

echo "[$hmac]\n";
?>
  1. Assign the string value to data variable.
  2. Assign the private key value to the key variable.
  3. hash_hmac function ( 'sha256', $data, $key) calculates the checksum of the passed string using the private key and SHA-256 algorithm.
  4. Save the function output in hmac variable.
  5. Use echo function to create an output.
  6. Compare this value with the one passed in the callback notification.

Asymmetric cryptography

PHP
<?php
// data from response
$data = 'amount;35000099;mdOrder;12b59da8-f68f-7c8d-12b5-9da8000826ea;operation;deposited;status;1;';
$checksum = '9524FD765FB1BABFB1F42E4BC6EF5A4B07BAA3F9C809098ACBB462618A9327539F975FEDB4CF6EC1556FF88BA74774342AF4F5B51BA63903BE9647C670EBD962467282955BD1D57B16935C956864526810870CD32967845EBABE1C6565C03F94FF66907CEDB54669A1C74AC1AD6E39B67FA7EF6D305A007A474F03B80FD6C965656BEAA74E09BB1189F4B32E622C903DC52843C454B7ACF76D6F76324C27767DE2FF6E7217716C19C530CA7551DB58268CC815638C30F3BCA3270E1FD44F63C14974B108E65C20638ECE2F2D752F32742FFC5077415102706FA5235D310D4948A780B08D1B75C8983F22F211DFCBF14435F262ADDA6A97BFEB6D332C3D51010B';

// your public key (e.g. SHA-512 with RSA)
// if you have a CERT, please see openssl_get_publickey()
$publicKey = <<<EOD
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwtuGKbQ4WmfdV1gjWWys
5jyHKTWXnxX3zVa5/Cx5aKwJpOsjrXnHh6l8bOPQ6Sgj3iSeKJ9plZ3i7rPjkfmw
qUOJ1eLU5NvGkVjOgyi11aUKgEKwS5Iq5HZvXmPLzu+U22EUCTQwjBqnE/Wf0hnI
wYABDgc0fJeJJAHYHMBcJXTuxF8DmDf4DpbLrQ2bpGaCPKcX+04POS4zVLVCHF6N
6gYtM7U2QXYcTMTGsAvmIqSj1vddGwvNGeeUVoPbo6enMBbvZgjN5p6j3ItTziMb
Vba3m/u7bU1dOG2/79UpGAGR10qEFHiOqS6WpO7CuIR2tL9EznXRc7D9JZKwGfoY
/QIDAQAB
-----END PUBLIC KEY-----
EOD;

$binarySignature = hex2bin(strtolower($checksum));
$isVerify = openssl_verify($data, $binarySignature, $publicKey, OPENSSL_ALGO_SHA512);
if ($isVerify == 1) {
    echo "signature ok\n";
} elseif ($isVerify == 0) {
    echo "bad (there's something wrong)\n";
} else {
    echo "error checking signature\n";
}
?>

Additional functionality

Hold and Capture

Types of payment

A company may use two types of payments, depending on the specifics of its business:

The amount to be debited may differ from the holding amount to a greater or lesser extent.

Two-phase payments should be used if some time elapses between the buyer's decision to pay and delivery of the selected good or service

For the payment to be a two-phase payment, the order must be registered via registerPreAuth.do request, not register.do.

Two-phase payment is suitable for any method of integration:

Captures

A capture of a pre-authorized amount happens in the second phase of the two-phase payment, when the funds are debited from card holder's account. Once the capture occurs, the order becomes completed and goes in the DEPOSITED status. The amount captured can be greater or less than the pre-authorization amount, and partial capture in increments is available as well.

There are two ways to make a capture:

Autocompletion and Autoreversal

You can set up your payment integration so that orders would be completed and/or reversed automatically after a specific time period by making use of autocompletion and autoreversal. This means that you don't have to process each order manually in the Merchant Portal (and in case of API integration, there's no need to call deposit.do and/or reverese.do methods).

Bindings

A binding is a unique secure token generated by the Payment Gateway that links the payer's card number (PAN) to their ID in the store system (for example, to payer's login). Bindings facilitate payments with saved cards.

Creating a binding

You can create a binding via API or via the Merchant Portal UI for any type of integration. The main requirement is passing the client ID in the store system to the Payment Gateway. See the details below.

Creating a binding during payment via API

To create a binging during payment, it is enough to pass the clientId parameter in any payment request. A binding will be created when the payment is completed.

Creating a binding during payment via UI

To create a binding during payment via UI, go to the Personal Area, issue the invoice via the e-mail with specifying the Client ID parameter. As a result, the client will see the Save my card check box on the payment page. If the client selects this check box, the binding will be created: the card data will be saved for this client and the client will not have to enter the card data next time. Read more here.

Creating a binding with no charge

If you have a special permission, you can create a binding via API with no charge.

To do this, pass the value VERIFY in the features block of any payment request together with the clientId parameter. In this case, the cardholder will not be charged any amount. The response will contain the identifier of the created binding in the bindingId parameter. This binding ID can be used in subsequent requests instead of the saved card details.

Read more about the VERIFY feature here.

Forced binding creation

If you pass the value FORCE_CREATE_BINDING in the features block of the payment request, the binding will be created forcefully – even if the client has chosen not to save card data on the payment page.

TheFORCE_CREATE_BINDINGvalue cannot be passed in a request with an existing bindingId or bindingNotNeeded = true (will cause validation error). Passing this value also requires passing the clientId parameter.

If both the FORCE_CREATE_BINDING and the VERIFY values are passed in the features block, the order will be created for binding creation ONLY (without payment).

Using a binding

Bindings API

Once a binding is created, you can handle it over the Bindings API (subject to Merchant-level permission). The following methods are available:

Using bindings in recurrent payments

You can use bindings for recurring payments. In this case, the bindingId parameter is used in regular order registration request. Read more here.

Using bindings in wallet payments

You can also create bindings during tokenized payments using Apple Pay, Google Pay, and Samsung Pay wallets. To do this, pass the clientId parameter in a payment request or in an order registration request (see the description of API requests for wallets).

In this case, a binding will link the payer's tokenized card number (DPAN) to their ID in the store system (for example, to payer's login). Such a binding cannot be used for displaying a card number on a payment page (because the card number is tokenized). However, this binding can be used in recurring payments.

Cardholder verification

You can verify a cardholder without charging any amount. To do this, pass theVERIFY value in the features block of an order registration or payment request.

When theVERIFY feature is used, the payment card will be verified to make sure it is used by its legitimate owner. If 3-D Secure is available for the card, then 3-D Secure verification will be performed. The amount parameter of the verification request can be 0. Even if some amount is passed in the request, no charge will be made. After a successful registration, order status is changed to REVERSED.

If the VERIFY feature is passed together with the clientId parameter, it can be used to create a binding without payment. Read more in the Bindings section.

Test cards

For testing purposes you can use the following test cards.

Card number (SSL) 4000 0011 1111 1118
Expiry 12/30
CVC 123
Card number (3DS1) 6777 7700 0000 0006
Expiry 12/30
CVC 123
3-D Secure verification code 12345678
Card number (3DS2) 5000 0011 1111 1115
Expiry 12/30
CVC 123