List view
Getting Started
Getting Started
Authentication Guide
Authentication Guide
India
India
Secure Integration Steps for Merchant Authentication
TezPay Callback Signature Validation
Overview
TezPay sends callbacks to merchants with HMAC-SHA256 signatures to ensure data integrity and authenticity. This document explains how to validate these signatures in your merchant application.
Callback Format
TezPay sends callbacks with the following structure:
{ "tx_id": "c8e092a1-658a-4216-8747-abedca22ff6a", "status": "COMPLETED", "updated_at": "2025-09-19T19:25:34.015277+00:00", "merchant_reference": "PAY4653613844", "payment_method": "IMPS_IN", "signature": "a1b2c3d4e5f6789..." }
Signature Generation Process
The signature is generated using HMAC-SHA256 with the following process:
- Extract fields in this exact order:
tx_idstatusmerchant_referenceupdated_atpayment_method
- Concatenate fields without any separators:
message = tx_id + status + merchant_reference + updated_at + payment_method
- Generate HMAC-SHA256 using your
client_secret:
signature = HMAC-SHA256(message, client_secret)
Implementation Examples
JavaScript/Node.js
const crypto = require('crypto'); function generateSignature(callbackData, clientSecret) { const message = callbackData.tx_id + callbackData.status + callbackData.merchant_reference + callbackData.updated_at + callbackData.payment_method; return crypto.createHmac('sha256', clientSecret) .update(message) .digest('hex'); } function validateSignature(callbackData, receivedSignature, clientSecret) { const expectedSignature = generateSignature(callbackData, clientSecret); return crypto.timingSafeEqual( Buffer.from(expectedSignature, 'hex'), Buffer.from(receivedSignature, 'hex') ); } // Usage const callbackData = { tx_id: "c8e092a1-658a-4216-8747-abedca22ff6a", status: "COMPLETED", merchant_reference: "PAY4653613844", updated_at: "2025-09-19T19:25:34.015277+00:00", payment_method: "IMPS_IN" }; const clientSecret = "AtHhxl0NIBImMMb4l4ToPf2lfurWDyM9SMe26sWPJWM"; const receivedSignature = "a1b2c3d4e5f6789..."; const isValid = validateSignature(callbackData, receivedSignature, clientSecret); console.log("Signature valid:", isValid);
PHP
<?php function generateSignature($callbackData, $clientSecret) { $message = $callbackData['tx_id'] . $callbackData['status'] . $callbackData['merchant_reference'] . $callbackData['updated_at'] . $callbackData['payment_method']; return hash_hmac('sha256', $message, $clientSecret); } function validateSignature($callbackData, $receivedSignature, $clientSecret) { $expectedSignature = generateSignature($callbackData, $clientSecret); return hash_equals($expectedSignature, $receivedSignature); } // Usage $callbackData = [ 'tx_id' => 'c8e092a1-658a-4216-8747-abedca22ff6a', 'status' => 'COMPLETED', 'merchant_reference' => 'PAY4653613844', 'updated_at' => '2025-09-19T19:25:34.015277+00:00', 'payment_method' => 'IMPS_IN' ]; $clientSecret = 'AtHhxl0NIBImMMb4l4ToPf2lfurWDyM9SMe26sWPJWM'; $receivedSignature = 'a1b2c3d4e5f6789...'; $isValid = validateSignature($callbackData, $receivedSignature, $clientSecret); echo "Signature valid: " . ($isValid ? 'true' : 'false'); ?>
Python
import hmac import hashlib def generate_signature(callback_data, client_secret): message = (callback_data['tx_id'] + callback_data['status'] + callback_data['merchant_reference'] + callback_data['updated_at'] + callback_data['payment_method']) return hmac.new( client_secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256 ).hexdigest() def validate_signature(callback_data, received_signature, client_secret): expected_signature = generate_signature(callback_data, client_secret) return hmac.compare_digest(expected_signature, received_signature) # Usage callback_data = { 'tx_id': 'c8e092a1-658a-4216-8747-abedca22ff6a', 'status': 'COMPLETED', 'merchant_reference': 'PAY4653613844', 'updated_at': '2025-09-19T19:25:34.015277+00:00', 'payment_method': 'IMPS_IN' } client_secret = 'AtHhxl0NIBImMMb4l4ToPf2lfurWDyM9SMe26sWPJWM' received_signature = 'a1b2c3d4e5f6789...' is_valid = validate_signature(callback_data, received_signature, client_secret) print(f"Signature valid: {is_valid}")
Java
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; public class SignatureValidator { public static String generateSignature(String txId, String status, String merchantReference, String updatedAt, String paymentMethod, String clientSecret) throws NoSuchAlgorithmException, InvalidKeyException { String message = txId + status + merchantReference + updatedAt + paymentMethod; Mac mac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKey = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); mac.init(secretKey); byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8)); return bytesToHex(hash); } public static boolean validateSignature(String txId, String status, String merchantReference, String updatedAt, String paymentMethod, String receivedSignature, String clientSecret) throws NoSuchAlgorithmException, InvalidKeyException { String expectedSignature = generateSignature(txId, status, merchantReference, updatedAt, paymentMethod, clientSecret); return expectedSignature.equals(receivedSignature); } private static String bytesToHex(byte[] bytes) { StringBuilder result = new StringBuilder(); for (byte b : bytes) { result.append(String.format("%02x", b)); } return result.toString(); } }
C
using System; using System.Security.Cryptography; using System.Text; public class SignatureValidator { public static string GenerateSignature(string txId, string status, string merchantReference, string updatedAt, string paymentMethod, string clientSecret) { string message = txId + status + merchantReference + updatedAt + paymentMethod; byte[] keyBytes = Encoding.UTF8.GetBytes(clientSecret); byte[] messageBytes = Encoding.UTF8.GetBytes(message); using (var hmac = new HMACSHA256(keyBytes)) { byte[] hash = hmac.ComputeHash(messageBytes); return BitConverter.ToString(hash).Replace("-", "").ToLower(); } } public static bool ValidateSignature(string txId, string status, string merchantReference, string updatedAt, string paymentMethod, string receivedSignature, string clientSecret) { string expectedSignature = GenerateSignature(txId, status, merchantReference, updatedAt, paymentMethod, clientSecret); return expectedSignature.Equals(receivedSignature, StringComparison.OrdinalIgnoreCase); } }
Security Best Practices
- Always validate signatures before processing callbacks
- Use secure comparison (timing-safe) to prevent timing attacks
- Store client_secret securely (environment variables, secure vaults)
- Log validation results for debugging and monitoring
- Reject invalid signatures in production environments
Testing
You can test your implementation using the provided mock credentials:
{ "client_id": "502034de-48e4-44eb-a437-2bc7773964f7", "client_secret": "AtHhxl0NIBImMMb4l4ToPf2lfurWDyM9SMe26sWPJWM" }
Support
For technical support or questions about signature validation, please contact the TezPay support team.