Skip to main content

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

1

Submit Request

You submit a verification request (e.g., UPI by Mobile)
2

Request Queued

API returns 202 Accepted with a request ID
3

Processing

TxnCheck processes the verification request
4

Webhook Delivered

Results are sent to your configured webhook URL
5

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

EventDescription
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

FieldTypeDescription
eventstringEvent type (request.completed, request.failed, request.partial)
timestampstringISO 8601 timestamp when webhook was generated
data.requestIdstringUnique request identifier
data.methodstringVerification method used
data.statusstringFinal request status
data.resultobjectVerification result data (if successful)
data.errorobjectError details (if failed)
data.stepStatusesobjectIndividual step statuses (for full-check)
data.completedAtstringWhen 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": { ... },
      "kycByMobile": { ... },
      "vpaChargebackCheck": { ... }
    },
    "completedAt": "2025-01-11T10:30:00.000Z"
  }
}

Webhook Headers

Each webhook request includes these headers:
HeaderDescription
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:
AttemptDelay
1Immediate
21 second
32 seconds
44 seconds
58 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.