Chaindoc Webhooks

Chaindoc hesabınızda olaylar meydana geldiğinde gerçek zamanlı bildirimler alın. Webhooks, olay verilerini anında sunucunuza aktarır ve böylece yoklama ihtiyacını ortadan kaldırır.

Genel Bakış

Chaindoc Webhooks, hesabınızda bir olay meydana geldiğinde uygulamanızın gerçek zamanlı bildirimler almasını sağlar. API'yi sorgulamak yerine, webhooks bir eylem gerçekleştiğinde olay verilerini sunucunuza aktarır.

Temel Özellikler

  • Gerçek Zamanlı Bildirimler - Sunucunuza anında olay teslimi
  • Otomatik Yeniden Denemeler - Üstel geri çekilme ile en fazla 3 yeniden deneme
  • İmza Doğrulama - Yükün gerçekliği için HMAC SHA256
  • Etkinlik Filtreleme - Yalnızca ilgilendiğiniz etkinlikleri alın
  • Hata Takibi - Webhook teslimat durumunu ve hatalarını izleyin

Kullanım Örnekleri

  • Belgeler imzalandığında e-posta bildirimleri gönderin
  • Belgeler blok zincirinde doğrulandığında iş akışlarını tetikleyin
  • İmza talepleri oluşturulduğunda veritabanınızı güncelleyin
  • Belge durumunu harici sistemlerle senkronize edin
  • Denetim izi ve uyumluluk günlüğü

Kurulum

Adım 1: API Anahtarı Oluşturun

Chaindoc kontrol panelinizde Ayarlar → API Erişimi'ne gidin ve webhook yapılandırması etkinleştirilmiş bir API anahtarı oluşturun.

Adım 2: Webhook URL'sini yapılandırın

API'yi kullanarak webhook uç noktanızı yapılandırın:

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"
  }'

Adım 3: Webhook Uç Noktasını Uygulayın

Webhook olaylarını almak için sunucunuzda bir uç nokta oluşturun. İşte farklı dillerde örnekler:

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);

Etkinlik Türleri

Chaindoc, aşağıdaki olaylar için webhook'lar gönderir:

document.created

API aracılığıyla yeni bir belge oluşturulduğunda tetiklenir.

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

document.verified

Bir belge blok zincirinde başarıyla doğrulandığında tetiklenir.

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"
}

belge.imzalı

Gerekli tüm imzalar toplandığında tetiklenir.

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

Yeni imza isteği oluşturulduğunda tetiklenir.

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

Tüm imzalayanlar imzalarını tamamladığında tetiklenir.

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

İmzalayan kişi imza talebini reddettiğinde tetiklenir.

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"
}

Güvenlik

İmza Doğrulama

Chaindoc, HMAC SHA256 kullanarak tüm webhook yüklerini imzalar. Orijinalliği sağlamak ve tekrar saldırılarını önlemek için imzaları her zaman doğrulayın.

İmza Doğrulama Nasıl Çalışır?

1Chaindoc İmza OluştururChaindoc, webhook gizli anahtarınızı kullanarak HMAC imzası oluşturur.

2Başlıkta Gönderilen İmzaİmza, X-Webhook-Signature başlığında gönderilir.

3Sunucunuz DoğrularSunucunuz imzayı yeniden hesaplar ve zamanlama güvenli işlev kullanarak karşılaştırır.

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');
}

Yeniden Deneme Mantığı

Chaindoc, başarısız webhook teslimatlarını üstel geri çekilme ile otomatik olarak yeniden dener.

  • 1. yeniden deneme: 1 dakika sonra
  • 2. deneme: 5 dakika sonra (toplam: 6 dakika)
  • 3. deneme: 15 dakika sonra (toplam: 21 dakika)

Webhook'ları Test Etme

Yerel Geliştirme

Webhook testi için yerel sunucunuzu açığa çıkarmak için ngrok gibi araçlar kullanın:

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

Manuel Test

Webhook uç noktanızı örnek bir yük ile test edin:

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"
  }'

En İyi Uygulamalar

  • İşleme başlamadan önce her zaman webhook imzalarını doğrulayın.
  • Zaman aşımını önlemek için hızlı yanıt verin (30 saniye içinde).
  • Webhook'ları bir kuyrukta eşzamansız olarak işleyin
  • Yinelenen olayları işlemek için idempotensi uygulayın
  • Hata ayıklama ve denetim için tüm webhook olaylarını kaydedin
  • Kontrol panelinizde webhook teslimat hatalarını izleyin
  • Güvenlik için HTTPS uç noktaları kullanın
  • Tüm olay türlerini nazikçe işleyin (bilinmeyen olayları yok sayın)

Tam Örnek

İşte veritabanı entegrasyonuna sahip, üretime hazır bir webhook işleyicisi:

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: {
      status: 'verified',
      blockchainTxHash: payload.txHash,
      verifiedAt: new Date(payload.timestamp),
    },
  });
}

async function handleSignatureCompleted(payload: any) {
  await prisma.signatureRequest.update({
    where: { id: payload.signatureRequestId },
    data: {
      status: 'completed',
      completedAt: new Date(payload.completedAt),
    },
  });
}

function verifySignature(payload: any, signature: string, secret: string): boolean {
  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);