Skip to main content

Payment result webhook

When a payment succeeds via a static or dynamic QR code, the TINGEE system automatically sends a webhook notification to the URL you registered in your configuration.

Webhook trigger conditions by account type (original account number vs virtual account VA)
  • Accounts linked by original account number (isNotifyAccountNumber = true): A transfer to the original account number triggers a balance notification from the bank to Tingee → Tingee sends a webhook to the partner.
  • Accounts that do NOT support original account number linking (VA only, isNotifyAccountNumber = false):
    • The payer must transfer to the issued virtual account (VA) number.
    • If the money is transferred directly to the original account number, the bank does not send the transaction notification to Tingee → Tingee does not receive the transaction from the bank → No webhook.
  • See the list of supported accounts in the Original account number linking support table.
POST
URLhttps://your-server.com/api/webhook/payment

Push notification of transaction data from Tingee to your system as soon as money arrives in the account.

Headers sent​

These headers help you identify the request and verify the integrity of the received data.

HeaderDescription
Content-TypeAlways application/json.
x-request-idUnique identifier of each webhook request (UUID).
x-request-timestampTime the notification is sent (format: yyyyMMddHHmmssSSS, UTC+7).
x-signatureHMAC SHA512 signature used to verify the data.

Body Parameter​

The transaction details are sent in the body.

FieldTypeDescription
clientIdstringYour Client ID.
transactionCodestringSystem transaction code.
amountnumberActual amount paid.
contentstringTransfer description or note.
bankstringReceiving bank name.
accountNumberstringReceiving bank account number.
vaAccountNumberstringVirtual account number (if any).
transactionDatestringTransaction time (format: yyyyMMddHHmmss).
typestringTransaction type
- credit: Credit transaction
- debit: Debit transaction
If not sent, defaults to Credit.
additionalDataarrayAdditional information (e.g. billId for dynamic QR).
Note for VietinBank

VietinBank does not return the payment description when a transaction occurs, so the webhook from Tingee to the partner will not include the content field either.

Webhook authentication​

You must verify the x-signature signature to make sure the webhook really comes from Tingee. The signature is generated with: HMAC_SHA512(timestamp + ":" + json_body, secretKey).

Verification code samples​

import { createHmac } from 'crypto';

function verifyWebhook(headers: any, body: any, secretKey: string): boolean {
const signature = headers['x-signature'];
const timestamp = headers['x-request-timestamp'];

const message = `${timestamp}:${JSON.stringify(body)}`;
const computedSig = createHmac('sha512', secretKey).update(message).digest('hex');

return computedSig === signature;
}

Responding to the request​

After processing successfully, your server must respond with HTTP 200 OK and the following JSON:

{
"code": "00",
"message": "Success"
}

Retry & Logging​

Tingee always makes every effort to ensure you receive notifications:

  • Retry: If your server responds with an error or does not respond (timeout), Tingee automatically resends the webhook up to 5 times, 1 minute apart.
  • Idempotency: Use transactionCode to check whether a transaction has already been processed, to avoid duplicate processing when you receive a webhook retry.
  • Audit Log: We recommend logging the full webhook payload and headers to make investigation easier when issues arise.

⚠️ Note — Dynamic QR transactions​

For payments via dynamic QR, the payer may change the amount when scanning the code, so the amount actually received differs from the amount embedded in the QR code.

📌 Most banks now do not allow the amount to be edited when paying via dynamic QR. However, some banks have not yet applied this restriction, so the risk still exists.

In this case, TINGEE still records the transaction and sends the webhook to you as usual.

You must actively reconcile and verify the transaction using additional sources such as:

  • The customer's transaction screenshot
  • The statement of the bank account that actually received the money

Only confirm the transaction as complete after checking that the actual amount matches the invoice amount.


Security note

Never expose your secretKey in source code, and only process transactions when the x-signature signature is fully valid.