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.
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:
// 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}';
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"
}
}
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 |
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