OAuth 2.0 Authentication

Client should authorize before making any requests by obtaining a temporary access token. To get the access token call the /oauth/auth endpoint with your credentials.
The token is valid until "expires_in" time + current timestamp.
Attach the token to every method header call i.e.

Authorization: Bearer 648f8f2127984a1ef33f4b55fadf0625fc465da9

The test Partner credentials (only works on sandbox environment):
client_id: 1238-532ba67e3575aaaa
client_secret: 2c7d638f89e409185b6e44ca509b3226b318c3ea1de56fecb0d9e0c18b586da5

The test Merchant credentials (only works on sandbox environment):
client_id: 1235-fdbc7e9020117a8c
client_secret: 737bf2a3c5a7ca96eb8d8339349a2e011331fd994ec031a3cc3534d992f025f5

Alternatively, BasicAuth is available for authentication.

Marketplace notifications

After successful payment, the marketplace service will send asynchronous POST notification to the URL specified in transaction callbacks object. To receive the notification, provide the transactionCallbacks object with one transactionCallback type 3 and valid URL. See the marketplace/v1/transaction/create endpoint description.

POST Notifications are signed with JWS signature. We use the RFC 7515: JSON Web Signature (JWS). The signature is available in the header X-JWS-Signature. The content of the notification must be validated on the basis of a publicly available certificates:

For security reasons it is mandatory to verify the JWS signature to ensure that notification comes from the tpay.com notification service. Example implementation in PHP language look as follows:



// 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
// For sandbox please verify 'https://secure.sandbox.tpay.com'
$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 = json_decode($body, true);
echo '{"result": true}';
                            
Keep in mind that this is only a basic example to help you understand the JWS signature verification process and should be adjusted to meet your requirements. There are a lot of external libraries to verify JWS token. You can find list of them in many languages on https://jwt.io/libraries

After each successful transaction, Tpay.com system always sends an email notification to the customer, but the merchant email notification is optional and will be sent if the valid email callback was provided.
An example webhook content:

{
    "type": "marketplace_transaction",
    "data": {
        "transactionId": "01HGDE8BXSHGH7170CJAT2WVWF",
        "transactionTitle": "M-WWC6X",
        "transactionAmount": 5,
        "transactionPaidAmount": 5,
        "transactionStatus": "correct",
        "transactionHiddenDescription": "QWERTY321",
        "payerEmail": "[email protected]",
        "transactionDate": "2023-11-29 12:47:05",
        "transactionDescription": "Test marketplace transaction"
    }
}

The table of POST notification contents:

Parameter Details
type Const "marketplace_transaction"
transactionId The string ID of parent transaction (ULID encoded to base32 format)
transactionTitle Transaction user-friendly title assigned by the Tpay system.
transactionDate Transaction creation date.
transactionHiddenDescription This parameter will contain the exact value passed with create transaction request from your system. You may use it to identify the order ID on your side.
transactionAmount Transaction requested amount.
transactionPaidAmount Real amount paid by a customer.
Currently the marketplace system allows only payments matching the exact amount and currency of parent transaction.
Payments not matching the parent transaction amount or currency will be automatically cancelled and returned to payer.
transactionDescription Transaction description provided while creating transaction
transactionStatus The successful payment notification will contain word "correct". No other statuses are currently available.
payerEmail Payer email address. Please note, the payer address may change during the payment process.
cardToken This is token used by transaction method. It will be sent only once after successfull card payment if the card saving was requested. This won't be present in transactions with different channel.

Note 1: Merchant system should print {"result": true} response when all validations are correct. If the response is different, the notifications will be rescheduled.
The notifications are rescheduled according to the following schema:

Notification number Time interval
1-10 1 minute
11-20 3 minutes
21-30 10 minutes
31-35 1h
36 12h after last notification
37 24h after last notification

Note 2: The merchant system must be prepared for the situation when one notification is sent more than once. Submitting the notification again cannot result in a reissue service delivery / release of goods, etc. Notifications for a particular transaction will always contain the same transaction identifier (transaction_id).
Note 3: The notification system does not support 302 and 301 redirections. That means it is not supported to redirect notifications sent from the resulting URL to another. If the merchant system is configured to for example: redirect from http to https, enter the destination address to receive notifications after all redirections.
Note 4: Tpay servers are equipped with a firewall that blocks traffic on other ports than standard www (i.e. 80, 8080, 443).
Note 5: The currently supported protocol by Tpay is the TLS 1.2 protocol that provides confidentiality and integrity of data transmission as well as server authentication. The servers using older protocols like SSLv3 may cause an error in receiving notifications.
Note 6: The recommended method of handling notifications is putting them into internal queue of merchant system. Making all order correlated business logic synchronously before printing response may cause connection timeout.

Credit card payments

Tpay Marketplace system allows Merchant to host payment form on his website and perform a sale using credit card details provided by the payer.
This payment method supports 3D Secure validation which is an additional security layer for online credit and debit card transactions.
This approach requires special security considerations. We support secure communication by encrypting card data (card number, validity date and cvv/cvs number) on the client side (javascript) with Merchant public RSA key concatenated as one parameter (card).
A valid SSL certificate on the Merchant domain is required.

The application flow is presented below for clarification:
1. Generate webpage with your public RSA key in javascript
2. Before sending payment form, insert new input with encrypted card data using your public key and clear inputs with card data so only encrypted data will be sent and submit form.
3. On the backend prepare parameters and send them with marketplace/v1/transaction/{id}/pay method
4. Redirect the payer to the received 3DS verification URL
5. Receive an asynchronous notification about successful payment (see the notifications section).

Card data must be encrypted with public key and encoded in base64. The credit card data must be concatenated with vertical bar | ie.
1234567891234567|05/17|123|https://merchantwebsite.com
The concatenation pattern is: card_number|valid_date|CVV|Merchant_POS_url

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8nZcu8Y9cU2/AMP9P6qz
pLsaW8jR/dyp5RFOAL1vydg+mIDuVFgt5TDDD6LxWsHnvDUhubpQNTn1sC2Elzgd
NyhF9ZDTNNEZmwjdX6aMF4AKOt2usfBoEdlff+DYF3ZejoWlaPuqV0c/HuyjrCaO
jGgNYCLzMTb/kEsX1qu0NqH1o4DDc7lOr/P4XJnkaP44WkZYaAY0qAlJJyY0yGkG
7fSVm3YI1/YO0/jRRIHJMdisW1/fsBN6dabcDk2e5xie8nuqliXEqvkpoZlgTPJN
ei6na2ODRwtJUI5YJuCYrlNIqIyddwGyt9tS5fsaRcvS95WT/G1J+96ki6eV8ydU
wwIDAQAB
-----END PUBLIC KEY-----

We have published code samples, libraries and instructions to give some insights on the process - see https://github.com/tpay-com/tpay-php .
The library used in the example has a limit of 117 input characters for encryption. In production mode, this generated hash works only once and should always be generated even for the same card data.

• The best way to implement 3DS is to open a link to 3D-Secure authentication in a new window or make a simple redirection.
• Do not use an inline frame to implement the 3D-Secure authentication on Merchant’s Site. In this case, some banks can block 3DS authorisation.

The example card allowed for test cases is 1234 5678 9123 4567. Any other number will return business payment error like insufficient funds. Use this examples to test the encryption methods.