Chaindoc webhooks

Webhooks आपके सर्वर को तुरंत इवेंट डेटा भेजते हैं जब कुछ भी Chaindoc में होता है। कोई पोलिंग नहीं, कोई देरी नहीं। यहाँ बात यह है — इस पेज में सेटअप, इवेंट टाइप्स, HMAC वेरिफिकेशन, रीट्राई लॉजिक और टेस्टिंग सब कुछ कवर किया गया है।

Overview

API को पोल करने के बजाय, webhooks आपके सर्वर को बताते हैं कि क्या हुआ जैसे ही वह होता है। आप इन्हें document status sync करने, signatures के बाद workflows trigger करने, notifications भेजने और अपने database को sync रखने के लिए use करेंगे।

  • 3 automatic retries के साथ instant delivery (exponential backoff)
  • HMAC SHA256 signature verification हर payload पर
  • सिर्फ उन्हीं event types को filter करें जिनकी आपको जरूरत है
  • आपके dashboard में delivery status tracking

Setup

Step 1: API key बनाएं

अपने Chaindoc dashboard में Settings → API Access पर जाएं और एक API key बनाएं जिसमें webhook configuration enabled हो।

Step 2: Webhook URL configure करें

API use करके अपना webhook endpoint configure करें:

terminal
curl -X PATCH https://api.chaindoc.io/user/api-access/1/config \
  -H "Authorization: Bearer your_auth_token" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookUrl": "https://yourapp.com/webhooks/chaindoc",
    "webhookEnabled": true,
    "webhookSecret": "your_secure_random_string"
  }'

Step 3: अपना endpoint implement करें

अपने सर्वर पर webhook events receive करने के लिए एक endpoint बनाएं। यहाँ अलग-अलग languages में examples हैं:

const express = require('express');
const crypto = require('crypto');

const app = express();
app.use(express.json());

app.post('/webhooks/chaindoc', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const eventType = req.headers['x-webhook-event'];
  
  // Verify signature
  if (!verifySignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process event
  console.log('Received event:', eventType, req.body);
  
  // Handle different event types
  switch (eventType) {
    case 'document.created':
      handleDocumentCreated(req.body);
      break;
    case 'document.verified':
      handleDocumentVerified(req.body);
      break;
    case 'signature.request.completed':
      handleSignatureCompleted(req.body);
      break;
  }
  
  // Always respond with 200 OK
  res.status(200).send('Webhook received');
});

function verifySignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const digest = hmac.update(JSON.stringify(payload)).digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(digest)
  );
}

app.listen(3000);

Event types

Chaindoc इन events के लिए webhooks भेजता है:

document.created

Trigger होता है जब API के जरिए कोई नया document बनता है।

terminal
{
  "event": "document.created",
  "documentId": "86840ee4-8bf2-4a91-a289-e99d8307ec25",
  "name": "Service Agreement",
  "timestamp": "2024-12-04T10:30:00.000Z"
}

document.verified

Trigger होता है जब कोई document blockchain पर सफलतापूर्वक verified हो जाता है।

terminal
{
  "event": "document.verified",
  "documentId": "86840ee4-8bf2-4a91-a289-e99d8307ec25",
  "versionId": "f0b7721f-0399-4035-9b69-7b95d3a367f0",
  "txHash": "0x789ghi...",
  "chainId": 137,
  "timestamp": "2024-12-04T10:35:00.000Z"
}

document.signed

Trigger होता है जब सभी जरूरी signatures एकत्र हो जाते हैं।

terminal
{
  "event": "document.signed",
  "documentId": "86840ee4-8bf2-4a91-a289-e99d8307ec25",
  "signatureRequestId": "req_21096b94498f4a2d9795e810edc2c9a9",
  "signers": [
    {
      "email": "signer1@example.com",
      "signedAt": "2024-12-04T10:30:00.000Z"
    },
    {
      "email": "signer2@example.com",
      "signedAt": "2024-12-04T10:32:00.000Z"
    }
  ],
  "timestamp": "2024-12-04T10:32:00.000Z"
}

signature.request.created

Trigger होता है जब कोई नया signature request बनाया जाता है।

terminal
{
  "event": "signature.request.created",
  "signatureRequestId": "req_21096b94498f4a2d9795e810edc2c9a9",
  "documentId": "86840ee4-8bf2-4a91-a289-e99d8307ec25",
  "recipients": [
    {"email": "signer1@example.com"},
    {"email": "signer2@example.com"}
  ],
  "deadline": "2024-12-31T23:59:59.000Z",
  "timestamp": "2024-12-04T10:30:00.000Z"
}

signature.request.completed

Trigger होता है जब सभी signers अपने signatures complete कर लेते हैं।

terminal
{
  "event": "signature.request.completed",
  "signatureRequestId": "req_21096b94498f4a2d9795e810edc2c9a9",
  "documentId": "86840ee4-8bf2-4a91-a289-e99d8307ec25",
  "completedAt": "2024-12-04T10:32:00.000Z",
  "timestamp": "2024-12-04T10:32:00.000Z"
}

signature.request.rejected

Trigger होता है जब कोई signer signature request reject कर देता है।

terminal
{
  "event": "signature.request.rejected",
  "signatureRequestId": "req_21096b94498f4a2d9795e810edc2c9a9",
  "documentId": "86840ee4-8bf2-4a91-a289-e99d8307ec25",
  "rejectedBy": "signer1@example.com",
  "reason": "Terms not acceptable",
  "timestamp": "2024-12-04T10:30:00.000Z"
}

Security

Signature verification

Chaindoc सभी webhook payloads को HMAC SHA256 use करके sign करता है। Authenticity सुनिश्चित करने और replay attacks रोकने के लिए हमेशा signatures verify करें।

Verification कैसे काम करता है

1Chaindoc signature बनाता हैChaindoc आपके webhook secret का use करके HMAC signature बनाता है

2Header में signature भेजा जाता हैSignature X-Webhook-Signature header में भेजा जाता है

3आपका सर्वर verify करता हैआपका सर्वर signature recalculate करता है और timing-safe function से compare करता है

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const digest = hmac.update(JSON.stringify(payload)).digest('hex');
  
  // Use timing-safe comparison to prevent timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(digest)
  );
}

// Usage
const isValid = verifyWebhookSignature(
  req.body,
  req.headers['x-webhook-signature'],
  process.env.WEBHOOK_SECRET
);

if (!isValid) {
  return res.status(401).send('Invalid signature');
}

Retry logic

Chaindoc failed webhook deliveries को exponential backoff के साथ automatic retry करता है।

  • 1st retry: 1 minute बाद
  • 2nd retry: 5 minutes बाद (total: 6 minutes)
  • 3rd retry: 15 minutes बाद (total: 21 minutes)

Webhooks test करना

Local development

Webhook testing के लिए ngrok जैसे tools का इस्तेमाल करके अपने local server को expose करें:

terminal
# Install ngrok
npm install -g ngrok

# Start your local server
node server.js

# Expose port 3000
ngrok http 3000

# Use the ngrok URL as your webhook endpoint
# Example: https://abc123.ngrok.io/webhooks/chaindoc

Manual testing

Sample payload के साथ अपने webhook endpoint को test करें:

terminal
curl -X POST https://yourapp.com/webhooks/chaindoc \
  -H "Content-Type: application/json" \
  -H "X-Webhook-Event: document.created" \
  -H "X-Webhook-Signature: test_signature" \
  -d '{
    "event": "document.created",
    "documentId": "test-123",
    "name": "Test Document",
    "timestamp": "2024-12-04T10:30:00.000Z"
  }'

Best practices

  • Process करने से पहले हमेशा webhook signatures verify करें
  • Timeouts से बचने के लिए जल्दी respond करें (30 seconds से कम)
  • Webhooks को queue में asynchronously process करें
  • Duplicate events handle करने के लिए idempotency implement करें
  • Debugging और audit के लिए सभी webhook events log करें
  • अपने dashboard में webhook delivery failures monitor करें
  • Security के लिए HTTPS endpoints use करें
  • सभी event types को gracefully handle करें (unknown events ignore करें)

Production example

यहाँ database integration के साथ एक production-ready webhook handler है:

webhooks/chaindoc.ts
import express from 'express';
import crypto from 'crypto';
import { PrismaClient } from '@prisma/client';

const app = express();
const prisma = new PrismaClient();

app.use(express.json());

app.post('/webhooks/chaindoc', async (req, res) => {
  const signature = req.headers['x-webhook-signature'] as string;
  const eventType = req.headers['x-webhook-event'] as string;
  const payload = req.body;
  
  // 1. Verify signature
  if (!verifySignature(payload, signature, process.env.WEBHOOK_SECRET!)) {
    console.error('Invalid webhook signature');
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // 2. Check for duplicate events (idempotency)
  const eventId = `${eventType}-${payload.timestamp}`;
  const existing = await prisma.webhookEvent.findUnique({
    where: { eventId },
  });
  
  if (existing) {
    console.log('Duplicate event, skipping:', eventId);
    return res.status(200).json({ status: 'duplicate' });
  }
  
  // 3. Store event
  await prisma.webhookEvent.create({
    data: {
      eventId,
      eventType,
      payload,
      processedAt: new Date(),
    },
  });
  
  // 4. Process event asynchronously
  processWebhookAsync(eventType, payload).catch((error) => {
    console.error('Error processing webhook:', error);
  });
  
  // 5. Respond immediately
  res.status(200).json({ status: 'received' });
});

async function processWebhookAsync(eventType: string, payload: any) {
  switch (eventType) {
    case 'document.verified':
      await handleDocumentVerified(payload);
      break;
    case 'signature.request.completed':
      await handleSignatureCompleted(payload);
      await sendNotificationEmail(payload);
      break;
    case 'signature.request.rejected':
      await handleSignatureRejected(payload);
      break;
  }
}

async function handleDocumentVerified(payload: any) {
  await prisma.document.update({
    where: { id: payload.documentId },
    data: {
      verifiedAt: new Date(),
      txHash: payload.txHash,
    },
  });
}

What to do next