Callback notifications
The bank 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 bank.
The most common notifications describe changes in order status, such as:
- debiting of funds
- holding of funds
- payment reversal
- refund
More advanced integrations may make use of additional callback triggers like:
- saving of a card (i.e., storing a credential)
- enabling/disabling an existing stored credential
- payments being declined, etc.
The trigger type is passed in the operation parameter of the callback (see details below). For convenience, the callbacks for additional triggers can be directed to another URL by using the dynamicCallbackUrl parameter in order registration requests.
Types of notifications
Notifications without checksums
These notifications contain only information about the order, so potentially, the Partner 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:
- using symmetric cryptography — same (symmetric) cryptographic key is used by the payment gateway to create a checksum and by the Partner to validate it;
- using asymmetric cryptography — to create a checksum the payment gateway uses its private key known only to the payment gateway, while for validation of the created checksum the corresponding public key is used, this public key can be distributed openly.
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 a callback is delivered over HTTPS connection, the identity of the Partner's website must be verified with an SSL certificate issued and signed by a trusted certificate authority (check the table below). Self-signed certificates are not allowed.
| Requirement | Description |
|---|---|
| Signature algorithm | Not lower than SHA-256. |
| Supported certification authorities | Below are examples of organizations that register digital certificates: |
URL format for callback notifications
POST and GET requests can be sent.
Below is an example for a GET request. The parameters are received in the query.
Notification with a checksum (GET)
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=0Notification without a checksum (GET)
https://mybestmerchantreturnurl.com/callback/?mdOrder=
1234567890-098776-234-522&orderNumber=0987&operation=deposited&
callbackCreationDate=Mon Jan 31 21:46:52 UTC 2022&status=0For POST callbacks, you will receive the same parameters in HTTP body (instead of query parameters).
Notification with a checksum (POST)
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=0Notification without a checksum (POST)
https://mybestmerchantreturnurl.com/callback/
mdOrder=
1234567890-098776-234-522&orderNumber=0987&operation=deposited&
callbackCreationDate=Mon Jan 31 21:46:52 UTC 2022&status=0The passed parameters are shown in the table below.
The table contains only basic parameters. You can also use additional parameters if they are configured in bank.
| Parameter | Description |
|---|---|
mdOrder |
Unique order number stored in the bank. |
orderNumber |
Unique order number (identifier) in Partner's system. |
operation |
Type of event that triggered notification:
|
status |
Indicates if an operation was successfully processed:
|
Custom headers for callback notifications
You can request the technical support service to 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 with a checksum
https://mybestmerchantreturnurl.com/callback/?mdOrder=1234567890-098776-234-522&orderNumber=0987&checksum=DBBE9E54D42072D8CAF32C7F660DEB82086A25C14FD813888E231A99E1220AB3&operation=deposited&status=0Example of a notification URL without a checksum
https://mybestmerchantreturnurl.com/callback/?mdOrder=1234567890-098776-234-522&orderNumber=0987&operation=deposited&status=0Algorithm for processing status callback notifications
Sections below contain notification processing algorithms depending on notification type.
Notification with a checksum
-
The payment gateway sends the following HTTPS request to the Partner's server - please, note that:
- when using symmetric cryptography, the checksum is generated using a key common for the payment gateway and the Partner;
- 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.
On the Partner's side
checksumparameter is removed from the notification parameter string, and the value of this parameter (checksum) is saved for verifying the notification's authenticity.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 pairsname_parameter;value_parametermust be sorted in direct alphabetical order (ascending) by parameter names.
Here is an example of a generated parameter stringamount;123456;mdOrder;3ff6962a-7dcc-4283-ab50-a6d7dd3386fe;operation;deposited;orderNumber;10747;status;1;-
The checksum is calculated on the Partner'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.
In the resulting checksum string, all lower-case letters are replaced by upper-case letters.
The resulting value must be compared with the checksum extracted earlier from
checksumparameter.If the checksums match, the server sends an HTTP code
200 OKto 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.
Notification without a checksum
- The payment gateway sends to the Partner's server the following request.
https://mybestmerchantreturnurl.com/callback/?mdOrder=1234567890-098776-234-522&orderNumber=0987&operation=deposited&status=0 - The Partner's server returns HTTP
200 OKto the payment gateway.
Payment status notification
In order to detect whether the payment run successfully or not you need to:
- Check the signature (
checksumparameter in callback); - Check two callback parameters:
operationandstatus.
If the operation value is approved or deposited, then the callback refers to the payment.
- Approved Successfully → operation = approved & status = 1 (Successful Operation)
- Approval was Declined → operation = approved & status = 0 (Failed Operation)
- Deposited Successfully → operation = deposited & status = 1 (Successful Operation)
- Deposit was Declined → operation = deposited & status = 0 (Failed Operation)
When notifications fail
If a response other than 200 OK is returned to the bank, the notification is considered unsuccessful. In this case, the bank repeats the notification at intervals of 30 seconds until one of the following conditions is met:
- the bank receives
200 OK, OR - there are 3 successive notification failures.
When one of the above conditions is met, attempts to send a callback notification about an event stop.
Additional callback parameters
In callback notifications, you can use the following additional parameters if they are configured in the Payment Gateway. If you need them, contact our support team.
| Parameter | Description | Type of event |
|---|---|---|
bindingId |
UUIID of created/updated stored credential. | BINDING_CREATED, BINDING_ACTIVITY_CHANGED |
email |
Client's email. | BINDING_CREATED |
phone |
Client's phone number. | BINDING_CREATED |
panMasked |
Masked PAN of the client's card. | BINDING_CREATED |
panCountryCode |
Client's country code. | BINDING_CREATED |
enabled |
Whether a store credential is active (true/false). |
BINDING_ACTIVITY_CHANGED |
currentReverseAmountFormatted |
Formatted amount of the reversal operation. | REVERSED |
currentRefundAmountFormatted |
Formatted amount of the refund operation. | REFUNDED |
operationRefundedAmountFormatted |
Formatted amount of the refund operation. | REFUNDED |
operationRefundedAmount |
Refund amount in minor currency units (e.g. in cents etc.). | REFUNDED |
externalRefundId |
External identifier of the refund operation. | REFUNDED |
callbackCreationDate |
Callback notification creation date. Special merchant setting is required. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT, BINDING_CREATED, BINDING_ACTIVITY_CHANGED |
status |
Operation status: 1 - success, 0 - failure | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
operation |
Callback type. Possible values: deposited, approved, reversed, refunded, bindingCreated, bindingActivityChanged, declinedByTimeout, declinedCardpresent
|
DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT, BINDING_CREATED, BINDING_ACTIVITY_CHANGED |
finishCheckUrl |
URL for receipt generation | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
cardholderName |
Cardholder name. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
amount |
Registered order amount in minor currency units. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
paymentAmount |
Registered order amount in minor currency units. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
amountFormatted |
Formatted registered order amount. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
feeAmount |
Fee amount in minor currency units. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
approvedAmount |
Preauthorized amount in minor currency units. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
depositedAmount |
Deposited amount in minor currency units. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
refundedAmount |
Refund amount in minor currency units. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
approvedAmountFormatted |
Formatted preauthorized amount. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
depositedAmountFormatted |
Formatted deposited amount. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
refundedAmountFormatted |
Formatted refunded amount. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
totalAmountFormatted |
Formatted total order amount (registered amount + fee). | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
depositedTotalAmountFormatted |
Formatted total deposited amount (all deposited amounts + all refunded amounts + fee). | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
approvalCode |
Payment authorization code received from processing. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
authCode |
Authorization code. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
bankName |
Name of the bank that issued the client's card. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
currency |
Order currency. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
depositFlag |
The flag that specifies the type of the operation.
|
DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
eci |
Electronic commerce indicator. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
ip |
Client's IP address. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
ipCountryCode |
Country code of the client's IP address. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
maskedPan |
Masked number of the client's card. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
mdOrder |
Order number in the payment gateway. Unique within the payment gateway. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
mdorder |
Order number in the payment gateway. Unique within the payment gateway. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
merchantFullName |
Merchant's full name. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
merchantLogin |
Merchant's login. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
orderDescription |
Order description. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
orderNumber |
Order number (ID) in the merchant's system. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
threeDSType |
Type of transaction in terms of 3 DS. Possible values: SSL, THREE_DS1_FULL, THREE_DS1_ATTEMPT, THREE_DS2_FULL, THREE_DS2_FRICTIONLESS, THREE_DS2_ATTEMPT, THREE_DS2_EXEMPTION_GRANTED
|
DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
date |
Date of the order creation. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
clientId |
Customer number (ID) in the merchant's system. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT,BINDING_CREATED, BINDING_ACTIVITY_CHANGED |
actionCode |
Code of the operation execution result. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
actionCodeDescription |
Description of the code of the operation execution result. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
paymentRefNum |
Reference Retrieval Number - transaction ID assigned by Acquiring Bank. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
paymentState |
Order status. Possible values: started, payment_approved, payment_declined, payment_void, payment_deposited, refunded, pending, partly_deposited
|
DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
paymentWay |
Order payment way. Find more possible values of the parameter here. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
processingId |
Identifier of the customer in processing. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
refNum |
Reference Retrieval Number - transaction ID assigned by Acquiring Bank. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
refnum |
Reference Retrieval Number - transaction ID assigned by Acquiring Bank. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
terminalId |
Terminal identifier in the system that processes the payment. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
paymentSystem |
Payment system name. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
currencyName |
ISO 3-Letter Currency Code. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
transactionAttributes |
Order attributes. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
paymentDate |
Order payment date. | DEPOSITED, APPROVED, REVERSED, REFUNDED |
depositedDate |
Date of order deposit operation. | DEPOSITED, APPROVED, REVERSED, REFUNDED |
refundedDate |
Date of order refund operation. | REFUNDED |
reversedDate |
Date of order reversal operation. | DEPOSITED, REVERSED, REFUNDED |
declineDate |
Date of order cancellation. | DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
xid |
Electronic commerce indicator of the transaction defined by the merchant. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
cavv |
Cardholder authentication value. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
authValue |
Cardholder authentication value. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
sessionExpiredDate |
Date and time of the order expiration. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
creditBankName |
Name of the bank that issued the card to be credited (in P2P). | DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
creditPanCountryCode |
Country code of recipient card (in P2P). | DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
isInternationalP2P |
Whether P2P transfer is international. | DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
recipientData |
Information about P2P recipient. | DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
transactionTypeIndicator
|
Information about P2P recipient. Possible values:
|
DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
operationType |
Type of P2P operation: AFT/OCT. | DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
debitBankName |
Name of the bank that issued the card to be debited (in P2P). | DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
debitPanCountryCode |
Country code of the card tp be debited (in P2P). | DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
p2pDebitRrn |
RRN (Reference Retrieval Number) of P2P debit operation. | DEPOSITED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT |
taxSystem |
Tax system, the following values are allowed:
|
DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
inn |
Tax reference number of the payer. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
orgName |
Full name of the payer's organisation. | DEPOSITED, APPROVED, REVERSED, REFUNDED, DECLINED_BY_TIMEOUT, DECLINED_CARDPRESENT |
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";
?>- Assign the string value to
datavariable. - Assign the private key value to the
keyvariable. -
hash_hmacfunction ( 'sha256', $data, $key) calculates the checksum of the passed string using the private key and SHA-256 algorithm. - Save the function output in
hmacvariable. - Use
echofunction to create an output. - Compare this value with the one passed in the callback notification.
Asymmetric cryptography
PHP
- The Partner's server receives a callback from the bank.
- The Partner's server performs the necessary checks. Remember that the parameters
sign_aliasandchecksummust be excluded from the check. All other parameters must be arranged alphabetically.
For example, you receive the following parameters in the callback:
{orderNumber=25062025_2,
sign_alias=all2pay_callback_router_a2p_gosim.shop,
checksum=68652F245EC7558D11369B79BF802CC01B9CAD310D8ADC4A7C74530F94086FA542205212BD4768EE3E23196D7D15B9F4E61A64D
75D058E927129E58B763499619456BE5A14B1037A3861D1B94F1F4ADC3DE0D77E2B87FE9990F99CC393451ECD816C6995B82A1FE22A0663A4
D03886E47AD09729FFEE43697825F52AC4E0D5D6BB3A8F089636A3CEDC56E378980237F950DF1499CF18597CB3A3F4A44C1A528D15AA19DA
BE9ACAD15C16F9E23F065AC4E45920F8D07FF361B58A6F000DC4F6DEEAD63B00685AA65C49F982F94A0BB729AEAE2A67ED891747E35F9BDE
507F576D4C3B89A4EFA5BE170380D65379E02F4C1C71678B2676AAE6894FD97BA9E054BB,
mdOrder=19854d67-5f7a-7494-8764-625d2a3fea54,
operation=deposited,
status=1}You need to work with the following parameters: mdOrder, operation, orderNumber, status.
See code example in PHP for the above values:
<?php
// data from response
$data = 'mdOrder;19854d67-5f7a-7494-8764-
625d2a3fea54;operation;deposited;orderNumber;25062025_2;status;1;';
$checksum =
'68652F245EC7558D11369B79BF802CC01B9CAD310D8ADC4A7C74530F94086FA542205212BD4768EE3E23196D7D15B9F4
E61A64D75D058E927129E58B763499619456BE5A14B1037A3861D1B94F1F4ADC3DE0D77E2B87FE9990F99CC393451ECD8
16C6995B82A1FE22A0663A4D03886E47AD09729FFEE43697825F52AC4E0D5D6BB3A8F089636A3CEDC56E378980237F950
DF1499CF18597CB3A3F4A44C1A528D15AA19DABE9ACAD15C16F9E23F065AC4E45920F8D07FF361B58A6F000DC4F6DEEAD
63B00685AA65C49F982F94A0BB729AEAE2A67ED891747E35F9BDE507F576D4C3B89A4EFA5BE170380D65379E02F4C1C71
678B2676AAE6894FD97BA9E054BB';
// your public key (e.g. SHA-512 with RSA)
// if you have a CERT, please see openssl_get_publickey()
$publicKey = <<<EOD
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3XAwa4AYO61BSkbcK9GW84yR0ghscAldsMWGDYzzjiw4GRIdMSlO7
pCBKB0nfQbyzYEfmAWf3NJDb7W98L4VoqDq0bDwPt5l1XSa2Xt0E7uYKnw0DfvNFDL3B52IiPaPjznhN4Vr4hv2aE0QHizDH7
iSL1ZgajgULoNodTh2kXKzJ+CGh46IsTJ4NErZoT/4QLNJrkP6ho8RNYIxYGEYkT17C+YsFYpYYDCPeoeIlA/O/rHcOO8Sd4P
/MkYKMb8fCsBGdQLbCHUq5ceMmxdMXiaaBW3xRjfTB+EXuXD+cW8gLNDnblB1XSlk16EGY6/wDAooJKimorUJ0A+n1qZfVwID
AQAB
-----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";
}If correct data is entered, the output is signature ok.
In case of entering incorrect data, the result is bad (there's something wrong).