Security
All POST
notifications are signed with a JWS signature.
We use RFC 7515: JSON Web Signature (JWS).
The signature is available in the X-JWS-Signature, header, which is one of the HTTP headers included with the notifications.
The notification content should be verified using publicly available certificates:
- Signature certificate: https://secure.tpay.com/x509/notifications-jws.pem
- Tpay CA root certificate: https://secure.tpay.com/x509/tpay-jws-root.pem
This ensures that the notification comes from a trusted source and that its content has not been altered during transmission.
For security reasons, JWS signature verification is mandatory.
We do not provide a list of IP addresses from which notifications are sent to whitelist them, as these addresses are dynamic. Therefore, implement the JWS signature verification algorithm to ensure your system is fully secure.
Example of JWS validation implementation:
<?php
// Get Request X-JWS-Signature header
$jws = isset($_SERVER["HTTP_X_JWS_SIGNATURE"])
? $_SERVER["HTTP_X_JWS_SIGNATURE"]
: null;
if (null === $jws) {
exit("FALSE - Missing JSW header");
}
// Extract JWS header properties
$jwsData = explode(".", $jws);
$headers = isset($jwsData[0]) ? $jwsData[0] : null;
$signature = isset($jwsData[2]) ? $jwsData[2] : null;
if (null === $headers || null === $signature) {
exit("FALSE - Invalid JWS header");
}
// Decode received headers json string from base64_url_safe
$headersJson = base64_decode(strtr($headers, "-_", "+/"));
// Get x5u header from headers json
$headersData = json_decode($headersJson, true);
$x5u = isset($headersData["x5u"]) ? $headersData["x5u"] : null;
if (null === $x5u) {
exit("FALSE - Missing x5u header");
}
// Check certificate url
$prefix = "https://secure.tpay.com";
if (substr($x5u, 0, strlen($prefix)) !== $prefix) {
exit("FALSE - Wrong x5u url");
}
// Get JWS sign certificate from x5u uri
$certificate = file_get_contents($x5u);
// Verify JWS sign certificate with Tpay CA certificate
// Get Tpay CA certificate to verify JWS sign certificate. CA certificate be cached locally.
$trusted = file_get_contents("https://secure.tpay.com/x509/tpay-jws-root.pem");
// in php7.4+ with ext-openssl you can use openssl_x509_verify
if (1 !== openssl_x509_verify($certificate, $trusted)) {
exit("FALSE - Signing certificate is not signed by Tpay CA certificate");
}
// or using phpseclib
$x509 = new \phpseclib3\File\X509();
$x509->loadX509($certificate);
$x509->loadCA($trusted);
if (!$x509->validateSignature()) {
exit("FALSE - Signing certificate is not signed by Tpay CA certificate");
}
// Get request body
$body = file_get_contents("php://input");
// Encode body to base46_url_safe
$payload = str_replace("=", "", strtr(base64_encode($body), "+/", "-_"));
// Decode received signature from base64_url_safe
$decodedSignature = base64_decode(strtr($signature, "-_", "+/"));
// Verify RFC 7515: JSON Web Signature (JWS) with ext-openssl
// Get public key from certificate
$publicKey = openssl_pkey_get_public($certificate);
if (
1 !==
openssl_verify(
$headers . "." . $payload,
$decodedSignature,
$publicKey,
OPENSSL_ALGO_SHA256
)
) {
exit("FALSE - Invalid JWS signature");
}
// or using phpseclib
$publicKey = $x509
->getPublicKey()
->withHash("sha256")
->withPadding(\phpseclib3\Crypt\RSA::SIGNATURE_PKCS1);
if (!$publicKey->verify($headers . "." . $payload, $decodedSignature)) {
exit("FALSE - Invalid JWS signature");
}
// JWS signature verified successfully.
// Process request data and send valid response to notification service.
$transactionData = $_POST;
echo "TRUE";
Remember, this is just a basic example to help you understand the JWS signature verification process and should be tailored to your specific requirements. There are many external libraries for JWS token verification. A list of these libraries in various languages can be found at https://jwt.io/libraries.
Idempotent handling of notifications
Your system must be prepared for a situation where the same notification is sent more than once. Re-sending a notification must not result in re-processing of a service, issuing goods, or any other irreversible operations. Each notification for a given transaction will always contain the same identifier, allowing for safe verification and prevention of duplicate operations.
Notification system requirements and limitations
The notification system does not support 302 and 301 redirects.
This means that redirecting notifications sent from the resulting URL to another address is not possible. If the merchant's system is configured to, for example, redirect from http to https, you must enter the final address that will receive notifications after all redirects.
You can verify the correctness of receiving notifications using the notification testing tool.
Tpay.com servers are equipped with a firewall, that blocks traffic on ports other than standard web ports (i.e., 80, 8080, 443).
he currently supported protocol by Tpay is TLS 1.2, which ensures the confidentiality and integrity of data transmission and server authentication. Servers using older protocols, such as SSLv3, may cause errors in receiving notifications.
Automatic resending of notifications
If the notification mechanism does not receive a correct response, it will attempt to resend the notifications according to the notification schedule.
Notification Range | Time Interval |
---|---|
1st - 10th notification | Every 1 minute |
11th - 20th notification | Every 3 minutes |
21st - 30th notification | Every 10 minutes |
31st - 35th notification | Every 1 hour |
36th notification | 12 hours after the last notification |
37th notification | 24 hours after the last notification |
The system will stop resending notifications after receiving an HTTP response with the code 404 Not Found
.
After the third incorrect response from your system, an informational email will be sent to the merchant's email address. In such a case, you should fix the receiving script to correctly process the provided parameters.
We also recommend ensuring that the JWS signature is correctly validated, and the merchant ID and security code (formerly the Confirmation Code) are properly configured.
Manual resending of notifications
The system allows merchants to resend notifications regarding their transactions. Currently, the following options are available in the transaction details tab:
- Sending notifications using the resend button. The notification will be sent to the notification endpoint URL. If the result URL was not defined during transaction creation or was not set in the Merchant Panel, this option will not be available.
- Sending a reminder about an incomplete transaction to the payer's email address. A transaction that has not been paid by the payer receives a "pending" status. For such transactions, it is possible to send a reminder about the incomplete transaction to the payer's email address provided at the beginning of the transaction. The payer will receive a message enabling them to complete the payment. The "Send Reminder" option can be used once every 3 hours.
Notification after transaction settlement
When the transaction is successfully settled, we send a POST
notification with content type application/x-www-form-urlencoded
to your system's endpoint.
Notification address configuration
The endpoint to which the transaction settlement notification will be sent can be configured in the Merchant Panel (Settings > Notifications).
If you have the Allow override option enabled, you can specify the endpoint URL in the callbacks.notification.url
parameter when creating the transaction, to which the notification will be sent instead of the default endpoint saved in the account settings.
Example:
{ "amount": 0.1, "description": "Visa Mobile test transaction", "payer": { "email": "[email protected]", "name": "John Doe" }, "pay": { "groupId": 171 }, "callbacks": { "notification": { "url": "https://www.your-endpoint.com" } } }
Notification parameters
The following parameters will be sent to your endpoint after each successful transaction.
id | The numeric identifier assigned to the merchant during registration. |
tr_id | The transaction title is assigned by the Tpay system. |
tr_date | The date the transaction was created. |
tr_crc | This parameter contains the exact value passed in the transaction creation request from your system, the hiddenDescription parameter. You should use it to identify the order ID on your side. |
tr_amount | The target transaction amount. |
tr_paid | The actual amount paid by the payer. Note: Depending on your account settings, this amount may differ from the transaction amount! |
tr_desc | The transaction description. |
tr_status | A successful payment notification will contain the word true . A notification of a full manual refund made from the Merchant Panel will contain the word chargeback . |
tr_error | Error information parameter. This parameter always takes the value none , as the Error status functionality has been deprecated. |
tr_email | The payer's email address. |
md5sum | A checksum is used to verify the parameters sent to the merchant. This checksum should always be verified on the merchant's side, and the data should be rejected in case of a conflict. If the merchant's verification code is not set, its value is assumed to be an empty string. |
test_mode | A parameter indicating whether the transaction was created in test mode or normal mode: test transaction - 1, normal transaction - 0. |
card_token | A payment token was sent if the payment was made by card and the pay.cardPaymentData.save:1 parameter was sent, Check here. |
token_expiry_date | The token's expiry date is in the MMYY format. Present only if the token has an expiry date. |
card_tail | The last 4 digits of the card number. |
card_brand | The card brand. Possible values are Visa or Mastercard. |
Additional Parameters, EISOP.
tokenPaymentData_tokenValue | EISOP token. |
tokenPaymentData_initialTransactionId | The ID of the initiating transaction for which tokenization was performed. |
tokenPaymentData_cardExpiryDate | Card/token expiry date. |
tokenPaymentData_cardBrand | The brand of the tokenized card. |
tokenPaymentData_cardTail | The last four digits of the tokenized card number. |
Expected response
In response to the transaction notification from your server, we expect:
HTTP Code: 200
Body:
If the response is anything other than
true
, the system will schedule a retry of the notification. After several attempts with responses other than TRUE, we will send you an email with additional details.To verify the md5sum parameter, use a similar algorithm:
$md5sum = md5($id . $tr_id . $tr_amount . $tr_crc . $code);
The
$code
parameter is the merchant's security code. Find in the Merchant Panel (Notifications -> Security tab).
Notification after tokenization without charge
When tokenization without charge, performed via the /tokens
endpoint, is successfully completed, we will send a POST
notification with the content type application/json
to your system's endpoint.
Notification address configuration
You can configure the endpoint to which the tokenization notification will be sent using the callbackUrl parameter during tokenization creation.
Example:
{ "payer": { "name": "John Doe", "email": "[email protected]" }, "callbackUrl": "https://your-page.com/webhook/tokens" }
Notification parameters
After each successful tokenization, the following parameters will be sent to your endpoint.
data.token | 64-character alphanumeric token. |
data.cardBrand | One of two values: Mastercard or Visa. |
data.cardTail | The last 4 digits of the tokenized card number. |
data.tokenExpiryDate | The token's expiry date in MMYY format. |
data.type | Type of tokenization (tokenization, tokenization_eisop). |
Example:
Expected response
In response to the tokenization notification from your server, we expect:
HTTP Code: 200
Body:
If the message is not received or the response content is different, we will retry according to the scheme.
Token or card update notification
We will notify you of any changes in the status of the payment token or the card image, as a part ot Tokenization Plus program. See more
Notification address configuration
You must configure the endpoint to which the token update notification will be sent using the callbackUrl
parameter during tokenization creation.
Example:
{ "payer": { "name": "John Doe", "email": "[email protected]" }, "callbackUrl": "https://your-page.com/webhook/tokens" }
Notification parameters
After each token status update, the following parameters will be sent to your endpoint.
type | token_update. |
data.token | 64-character alphanumeric token. |
Example:
Expected response
In response to the token status update notification from your server, we expect:
HTTP Code: 200
Body:
If the message is not received by your server or the response content from your system is different, we will retry according to the scheme.
After receiving the token status update notification, we recommend re-fetching the token status along with the card image to update information in your system, more information.
Marketplace notification
When a payment made via the /marketplace/v1/transaction
endpoint is successfully completed, we will send a POST
notification with the content type application/json
to your system's endpoint.
Notification address configuration
You must configure the endpoint to which the marketplace transaction notification will be sent using the callbackUrl, parameter during marketplace transaction creation.
{ "payer": { "name": "John Doe", "email": "[email protected]" }, "callbackUrl": "https://your-page.com/webhook/tokens" }
Notification parameters
After each successful marketplace transaction, the following parameters will be sent to your endpoint.
type | marketplace_transaction. |
data.transactionId | A string ID of the main transaction (ULID encoded in base32 format). |
data.transactionTitle | User-friendly transaction title assigned by the Tpay system. |
data.transactionAmount | The requested transaction amount. |
data.transactionPaidAmount | The actual amount paid by the payer. Currently, the marketplace system only allows payments that match the exact amount and currency of the main transaction. Payments that do not match the amount or currency of the main transaction will be automatically canceled and refunded to the payer. |
data.transactionStatus | A successful payment notification will contain the word correct . No other statuses are available at this time. |
data.transactionHiddenDescription | This parameter will contain the exact value passed when creating the transaction from your system. You can use it to identify the order ID on your side. |
data.payerEmail | The payer's email address. Please note that the payer's address may change during the payment process |
data.transactionDate | The date the transaction was created. |
data.transactionDescription | The transaction description was provided during transaction creation. |
data.cardToken | The token used by the transaction method. It will be sent only once after a successful card payment if card saving was requested. It will not be present in transactions with another channel. |
Expected response
In response to the marketplace transaction notification from your server, we expect:
HTTP Code: 200
Body:
If the message is not received or the response content is different, we will retry according to the scheme.