Chaindoc veebihookid

Saate reaalajas teateid, kui teie Chaindoc-kontol toimuvad sündmused. Webhookid edastavad sündmuste andmed teie serverisse koheselt, mistõttu pole vaja teavet küsida.

Ülevaade

Chaindoc Webhooks võimaldab teie rakendusel saada reaalajas teateid, kui teie kontol toimuvad sündmused. API päringute asemel edastavad webhooks sündmuste andmed teie serverisse niipea, kui toimub mingi tegevus.

Peamised omadused

  • Reaalajas teated – sündmuste kohene edastamine teie serverisse
  • Automaatsed korduskatseid – kuni 3 korduskatseid eksponentsiaalse tagasilükkamisega
  • Allkirja kontrollimine – HMAC SHA256 andmete autentsuse kontrollimiseks
  • Sündmuste filtreerimine – saate ainult need sündmused, mis teile huvi pakuvad
  • Veakontroll – jälgige webhooki edastamise staatust ja vigu

Kasutusjuhud

  • Saada e-posti teated, kui dokumendid on allkirjastatud
  • Käivitage töövood, kui dokumendid on blockchainis kinnitatud
  • Uuendage oma andmebaasi, kui luuakse allkirja taotlused
  • Sünkroniseerige dokumendi staatus väliste süsteemidega
  • Auditi jälg ja vastavuse logimine

Seadistamine

1. samm: looge API-võti

Mine oma Chaindoc-i juhtpaneelis valikule „Seaded” → „API-juurdepääs” ja loo API-võti, mille veebihooki konfiguratsioon on aktiveeritud.

2. samm: konfigureerige veebihooki URL

Kasutage API-d oma webhooki lõpppunkti konfigureerimiseks:

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

3. samm: rakendage veebihooki lõpppunkt

Looge oma serverisse lõpppunkt veebihooki sündmuste vastuvõtmiseks. Siin on näited erinevates keeltes:

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

Ürituste tüübid

Chaindoc saadab veebihooke järgmiste sündmuste puhul:

document.created

Käivitatakse, kui API kaudu luuakse uus dokument.

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

document.verified

Käivitatakse, kui dokument on edukalt kinnitatud plokiahelas.

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

Käivitatakse, kui kõik vajalikud allkirjad on kogutud.

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

Käivitatakse, kui luuakse uus allkirja taotlus.

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

Käivitatakse, kui kõik allkirjastajad on oma allkirjad andnud.

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

Käivitatakse, kui allakirjutaja lükkab allkirja taotluse tagasi.

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

Turvalisus

Allkirja kontrollimine

Chaindoc allkirjastab kõik veebihooki andmed HMAC SHA256 abil. Kontrollige alati allkirju, et tagada autentsus ja vältida kordusrünnakuid.

Kuidas allkirja kontrollimine toimib

1Chaindoc loob allkirjaChaindoc loob HMAC-allkirja, kasutades teie veebihooki salajast võtit

2Allkiri saadetud päisesAllkiri saadetakse X-Webhook-Signature päises

3Teie server kontrollibTeie server arvutab allkirja uuesti ja võrdleb seda ajaliselt turvalise funktsiooni abil.

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

Korrata loogikat

Chaindoc proovib ebaõnnestunud webhooki edastusi automaatselt uuesti eksponentsiaalse tagasilükkamisega.

  • 1. korduskatse: 1 minuti pärast
  • 2. korduskatse: 5 minuti pärast (kokku: 6 minutit)
  • 3. korduskatse: 15 minuti pärast (kokku: 21 minutit)

Veebihookide testimine

Kohalik arendus

Kasutage ngrok-i taolisi tööriistu, et avada oma kohalik server veebihookide testimiseks:

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

Käsitsi testimine

Testige oma webhooki lõpppunkti näidisandmetega:

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

Parimad tavad

  • Kontrollige alati veebihooki allkirju enne töötlemist
  • Vastake kiiresti (alla 30 sekundi), et vältida ajalõpu ületamist
  • Töötle veebihookeid asünkroonselt järjekorras
  • Rakendage idempotentsust, et käsitleda dubleeritud sündmusi
  • Logige kõik veebihooki sündmused veaotsinguks ja auditeerimiseks
  • Jälgige veebihookide edastamise ebaõnnestumisi oma juhtpaneelis
  • Kasutage turvalisuse tagamiseks HTTPS-lõpppunkte
  • Käsitlege kõiki sündmustüüpe viisakalt (ignoreerige tundmatud sündmused)

Täielik näide

Siin on tootmisvalmis veebihooki käitleja koos andmebaasi integratsiooniga:

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