Chaindoc webhooks
Webhooks, Chaindoc'ta bir şey olduğu anda olay verilerini sunucunuza iletir. Polling yok, gecikme yok. Bu sayfada kurulum, olay türleri, HMAC doğrulama, yeniden deneme mantığı ve test adımlarını bulacaksınız.
Genel bakış
API'yi polling yapmak yerine, webhooks sunucunuza bir şey olduğunda hemen haber verir. Belge durumunu senkronize etmek, imza sonrası iş akışlarını tetiklemek, bildirim göndermek ve veritabanınızı güncel tutmak için kullanacaksınız.
- Üstel geri çekilme ile 3 otomatik yeniden denemeye kadar anlık teslimat
- Her payload'da HMAC SHA256 imza doğrulaması
- Yalnızca ilgilendiğiniz olay türlerini filtreleme
- Dashboard'da teslimat durumu takibi
Kurulum
Adım 1: API anahtarı oluşturun
Chaindoc dashboard'ınızda 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
Webhook endpoint'inizi yapılandırmak için API'yi kullanın:
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: Endpoint'inizi uygulayın
Webhook olaylarını almak için sunucunuzda bir endpoint 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);Olay türleri
Chaindoc aşağıdaki olaylar için webhook gönderir:
document.created
API aracılığıyla yeni bir belge oluşturulduğunda tetiklenir.
{
"event": "document.created",
"documentId": "86840ee4-8bf2-4a91-a289-e99d8307ec25",
"name": "Service Agreement",
"timestamp": "2024-12-04T10:30:00.000Z"
}document.verified
Bir belge blockchain'de başarıyla doğrulandığında tetiklenir.
{
"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
Tüm gerekli imzalar toplandığında tetiklenir.
{
"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 bir imza isteği oluşturulduğunda tetiklenir.
{
"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 imzacılar imzalarını tamamladığında tetiklenir.
{
"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
Bir imzacı imza isteğini reddettiğinde tetiklenir.
{
"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 tüm webhook payload'larını HMAC SHA256 kullanarak imzalar. Orijinalliği sağlamak ve tekrar saldırılarını önlemek için her zaman imzaları doğrulayın.
Doğrulama nasıl çalışır
1Chaindoc imzayı oluştururChaindoc webhook secret'ınızı kullanarak HMAC imzası oluşturur
2İmza header'da gönderilirİmza X-Webhook-Signature header'ında gönderilir
3Sunucunuz doğrularSunucunuz imzayı yeniden hesaplar ve timing-safe fonksiyonla 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. yeniden deneme: 5 dakika sonra (toplam: 6 dakika)
- 3. yeniden deneme: 15 dakika sonra (toplam: 21 dakika)
Webhook'ları test etme
Yerel geliştirme
Webhook testi için yerel sunucunuzu dışarıya açmak üzere ngrok gibi araçları kullanın:
# 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/chaindocManuel test
Örnek bir payload ile webhook endpoint'inizi test edin:
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 iyi uygulamalar
- İşlemeden önce her zaman webhook imzalarını doğrulayın
- Zaman aşımlarını önlemek için hızlı yanıt verin (30 saniye altında)
- Webhook'ları kuyrukta asenkron olarak işleyin
- Yinelenen olayları ele almak için idempotency uygulayın
- Hata ayıklama ve denetim için tüm webhook olaylarını loglayın
- Dashboard'da webhook teslimat hatalarını izleyin
- Güvenlik için HTTPS endpoint'leri kullanın
- Tüm olay türlerini düzgün şekilde ele alın (bilinmeyen olayları yoksayın)
Üretim örneği
İşte veritabanı entegrasyonlu üretime hazır bir webhook handler:
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',
txHash: payload.txHash,
verifiedAt: new Date(),
},
});
}
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);Sonraki adımlar
- API entegrasyonu — yaygın kalıplar ve iş akışı örnekleri
- API dokümantasyonu — tam endpoint referansı
- SDK'lar — Server SDK ve Embed SDK kılavuzları
- Güvenlik — HMAC doğrulama ve anahtar yönetimi
- Kurulum — tüm framework'ler için SDK kurulumu