Webhooks Guide
Webhooks allow you to receive real-time HTTP notifications when verification requests complete. Instead of polling for results, your server receives automatic updates as soon as processing finishes.
How Webhooks Work
Submit Request
You submit a verification request (e.g., UPI by Mobile)
Request Queued
API returns 202 Accepted with a request ID
Processing
TxnCheck processes the verification request
Webhook Delivered
Results are sent to your configured webhook URL
Confirmation
Your server returns 2xx to acknowledge receipt
Setting Up Webhooks
Webhook URLs are configured at the merchant account level. Contact your account manager or configure webhooks in the Merchant Dashboard under Settings → Webhooks .
Requirements
HTTPS URL - Webhook endpoints must use HTTPS
Public accessibility - Your endpoint must be reachable from the internet
Quick response - Return 2xx within 30 seconds
Webhook Events
Event Description request.completedVerification completed successfully request.failedVerification failed request.partialVerification partially completed (some steps failed)
Webhook Payload
All webhook payloads follow this structure:
{
"event" : "request.completed" ,
"timestamp" : "2025-01-11T10:30:00.000Z" ,
"data" : {
"requestId" : "550e8400-e29b-41d4-a716-446655440000" ,
"method" : "upi-by-mobile" ,
"status" : "COMPLETED" ,
"result" : {
"name" : "JOHN DOE" ,
"upi" : [
"johndoe@upi" ,
"9876543210@paytm"
],
"status" : "1"
},
"completedAt" : "2025-01-11T10:30:00.000Z"
}
}
Payload Fields
Field Type Description eventstring Event type (request.completed, request.failed, request.partial) timestampstring ISO 8601 timestamp when webhook was generated data.requestIdstring Unique request identifier data.methodstring Verification method used data.statusstring Final request status data.resultobject Verification result data (if successful) data.errorobject Error details (if failed) data.stepStatusesobject Individual step statuses (for full-check) data.completedAtstring When the request completed
Full Check Step Statuses
For full-check requests, the stepStatuses field shows the outcome of each verification step:
{
"event" : "request.completed" ,
"timestamp" : "2025-01-11T10:30:00.000Z" ,
"data" : {
"requestId" : "550e8400-e29b-41d4-a716-446655440000" ,
"method" : "full-check" ,
"status" : "COMPLETED" ,
"stepStatuses" : {
"upiByMobile" : "ok" ,
"kycByMobile" : "ok" ,
"vpaChargebackCheck" : "ok"
},
"result" : {
"upiByMobile" : {
"name" : "JOHN DOE" ,
"vpas" : [ "johndoe@upi" , "9876543210@paytm" ],
"status" : "1"
},
"kycByMobile" : {
"fullName" : "JOHN DOE" ,
"pan" : "ABCDE1234F" ,
"maskedAadhaar" : "XXXXXXXX1234" ,
"dob" : "1990-01-15" ,
"status" : "1" ,
"cached" : false
},
"vpaChargebackCheck" : {
"vpas" : [
{ "vpa" : "johndoe@upi" , "isBlocklisted" : false },
{ "vpa" : "9876543210@paytm" , "isBlocklisted" : false }
]
}
},
"completedAt" : "2025-01-11T10:30:00.000Z"
}
}
Use result.vpaChargebackCheck.vpas[].isBlocklisted to determine blocklist status.
Each webhook request includes these headers:
Header Description Content-TypeAlways application/json X-Webhook-TimestampUnix timestamp (milliseconds) when signature was created X-Webhook-SignatureHMAC-SHA256 signature for verification
Signature Verification
Always verify webhook signatures to ensure requests are from TxnCheck and haven’t been tampered with.
Verification Algorithm
payload_to_sign = `${timestamp}.${JSON.stringify(body)}`
expected_signature = HMAC_SHA256(webhook_secret, payload_to_sign)
Implementation Examples
const crypto = require ( 'crypto' );
function verifyWebhookSignature ( payload , signature , timestamp , secret ) {
// Reject old timestamps (> 5 minutes)
const currentTime = Date . now ();
if ( Math . abs ( currentTime - parseInt ( timestamp )) > 300000 ) {
throw new Error ( 'Timestamp too old' );
}
// Calculate expected signature
const payloadToSign = ` ${ timestamp } . ${ JSON . stringify ( payload ) } ` ;
const expectedSignature = crypto
. createHmac ( 'sha256' , secret )
. update ( payloadToSign )
. digest ( 'hex' );
// Compare signatures using timing-safe comparison
if ( ! crypto . timingSafeEqual (
Buffer . from ( signature ),
Buffer . from ( expectedSignature )
)) {
throw new Error ( 'Invalid signature' );
}
return true ;
}
// Express.js example
app . post ( '/webhooks/txncheck' , express . json (), ( req , res ) => {
const signature = req . headers [ 'x-webhook-signature' ];
const timestamp = req . headers [ 'x-webhook-timestamp' ];
try {
verifyWebhookSignature ( req . body , signature , timestamp , WEBHOOK_SECRET );
const { event , data } = req . body ;
console . log ( `Received ${ event } for request ${ data . requestId } ` );
switch ( event ) {
case 'request.completed' :
// Process successful verification
handleVerificationComplete ( data );
break ;
case 'request.failed' :
// Handle failed verification
handleVerificationFailed ( data );
break ;
case 'request.partial' :
// Handle partial completion
handlePartialVerification ( data );
break ;
}
res . status ( 200 ). json ({ received: true });
} catch ( error ) {
console . error ( 'Webhook error:' , error . message );
res . status ( 400 ). json ({ error: error . message });
}
});
Retry Policy
If webhook delivery fails (non-2xx response or timeout), TxnCheck retries with exponential backoff:
Attempt Delay 1 Immediate 2 1 second 3 2 seconds 4 4 seconds 5 8 seconds
After 5 failed attempts, the webhook is marked as failed. You can still retrieve results using the Request Status endpoint.
Testing Webhooks
Local Development
For local development, use a tunneling service like ngrok to expose your local server:
# Start ngrok
ngrok http 3000
# Use the ngrok URL for your webhook endpoint
# https://abc123.ngrok.io/webhooks/txncheck
Webhook Logs
View webhook delivery logs in the Merchant Dashboard under Webhooks → Logs . You can see:
Delivery status (success/failed)
Response codes
Retry attempts
Payload details
Best Practices
Always Verify Signatures Never process webhooks without verifying the signature first
Respond Quickly Return 200 immediately, process events asynchronously
Handle Duplicates Use request ID for idempotency - you may receive the same event twice
Log Everything Log webhook payloads for debugging and audit trails
Webhook endpoints must be publicly accessible HTTPS URLs. Self-signed certificates are not supported.