Skip to content

Webhooks API

Real-time event notifications for document processing and workflow events.


Overview

Webhooks allow you to receive HTTP callbacks when events occur in Archivus.

Common Use Cases:

  • Document processing completion notifications
  • Workflow status updates
  • Integration with external systems
  • Automated downstream processing

Create Webhook

Create a new webhook endpoint.

POST /api/v1/webhooks

Request Body

{
  "url": "https://yourapp.com/webhooks/archivus",
  "events": [
    "document.processed",
    "document.failed",
    "chat.message.created",
    "dag.execution.completed"
  ],
  "secret": "your-webhook-secret"
}

Example Request

curl -X POST https://api.archivus.app/api/v1/webhooks \
  -H "X-API-Key: ak_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/archivus",
    "events": ["document.processed", "document.failed"],
    "secret": "your-webhook-secret"
  }'
const response = await fetch('https://api.archivus.app/api/v1/webhooks', {
  method: 'POST',
  headers: {
    'X-API-Key': 'ak_live_YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://yourapp.com/webhooks/archivus',
    events: ['document.processed', 'document.failed'],
    secret: 'your-webhook-secret'
  })
});
response = requests.post(
    'https://api.archivus.app/api/v1/webhooks',
    json={
        'url': 'https://yourapp.com/webhooks/archivus',
        'events': ['document.processed', 'document.failed'],
        'secret': 'your-webhook-secret'
    },
    headers={'X-API-Key': 'ak_live_YOUR_API_KEY'}
)

Response

{
  "id": "webhook_abc123",
  "url": "https://yourapp.com/webhooks/archivus",
  "events": ["document.processed", "document.failed"],
  "status": "active",
  "created_at": "2026-01-18T10:30:00Z"
}

Webhook Events

Available Events

Event Description
document.processed Document processing completed successfully
document.failed Document processing failed
document.uploaded New document uploaded
chat.message.created New chat message created
chat.session.created New chat session created
dag.execution.started Workflow execution started
dag.execution.completed Workflow execution completed
dag.execution.failed Workflow execution failed
dag.task.created Human task created
dag.task.completed Human task completed

Event Payload

All webhook events follow this structure:

{
  "id": "event_abc123",
  "type": "document.processed",
  "timestamp": "2026-01-18T10:30:00Z",
  "data": {
    "document_id": "doc_abc123",
    "status": "completed",
    "ai_summary": "Contract analysis completed",
    "ai_tags": ["contract", "legal"]
  }
}

Webhook Verification

Signature Header

Archivus includes a signature in the X-Archivus-Signature header:

X-Archivus-Signature: sha256=abc123def456...

Verification Example

import hmac
import hashlib

def verify_webhook(payload, signature, secret):
    expected_signature = hmac.new(
        secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(
        f"sha256={expected_signature}",
        signature
    )

# Usage
payload = request.data
signature = request.headers.get('X-Archivus-Signature')
secret = 'your-webhook-secret'

if verify_webhook(payload, signature, secret):
    # Process webhook
    event = json.loads(payload)
    handle_event(event)
else:
    return 'Invalid signature', 401
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(`sha256=${expectedSignature}`),
    Buffer.from(signature)
  );
}

// Usage
const payload = JSON.stringify(req.body);
const signature = req.headers['x-archivus-signature'];
const secret = 'your-webhook-secret';

if (verifyWebhook(payload, signature, secret)) {
  // Process webhook
  handleEvent(req.body);
} else {
  res.status(401).send('Invalid signature');
}

Webhook Handler Example

Node.js Express

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

const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

app.post('/webhooks/archivus',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const signature = req.headers['x-archivus-signature'];
    const payload = req.body.toString();

    // Verify signature
    const expectedSignature = crypto
      .createHmac('sha256', WEBHOOK_SECRET)
      .update(payload)
      .digest('hex');

    if (signature !== `sha256=${expectedSignature}`) {
      return res.status(401).json({ error: 'Invalid signature' });
    }

    // Process event
    const event = JSON.parse(payload);

    switch (event.type) {
      case 'document.processed':
        handleDocumentProcessed(event.data);
        break;
      case 'document.failed':
        handleDocumentFailed(event.data);
        break;
      case 'dag.execution.completed':
        handleWorkflowCompleted(event.data);
        break;
    }

    res.json({ status: 'ok' });
  }
);

Python Flask

from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)
WEBHOOK_SECRET = os.environ['WEBHOOK_SECRET']

@app.route('/webhooks/archivus', methods=['POST'])
def archivus_webhook():
    signature = request.headers.get('X-Archivus-Signature')
    payload = request.get_data(as_text=True)

    # Verify signature
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(f"sha256={expected}", signature):
        return jsonify({"error": "Invalid signature"}), 401

    # Process event
    event = request.json

    if event['type'] == 'document.processed':
        handle_document_processed(event['data'])
    elif event['type'] == 'document.failed':
        handle_document_failed(event['data'])
    elif event['type'] == 'dag.execution.completed':
        handle_workflow_completed(event['data'])

    return jsonify({"status": "ok"}), 200

Best Practices

Security

Always Verify Signatures

Never process webhooks without verifying the signature. This prevents unauthorized requests.

  1. Use HTTPS - Webhook URLs must use HTTPS
  2. Verify signatures - Always verify the X-Archivus-Signature header
  3. Rotate secrets - Regularly rotate webhook secrets
  4. Validate events - Verify event types before processing

Reliability

  1. Return 200 quickly - Respond within 5 seconds
  2. Process asynchronously - Queue webhook events for background processing
  3. Handle duplicates - Implement idempotency using event IDs
  4. Log all events - Log webhooks for debugging and monitoring

Error Handling

  1. Retry logic - Archivus will retry failed webhooks (exponential backoff)
  2. Monitor failures - Track webhook delivery failures
  3. Fallback mechanisms - Have backup methods to poll for status

Manage Webhooks

List Webhooks

GET /api/v1/webhooks

Update Webhook

PUT /api/v1/webhooks/{webhook_id}

Delete Webhook

DELETE /api/v1/webhooks/{webhook_id}

Testing

Test Webhook Locally

Use tools like ngrok or localtunnel to expose your local server:

# Using ngrok
ngrok http 3000

# Update webhook URL to ngrok URL
curl -X PUT https://api.archivus.app/api/v1/webhooks/webhook_abc123 \
  -H "X-API-Key: ak_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://abc123.ngrok.io/webhooks/archivus"
  }'

Next Steps

  • Upload Documents


    Trigger webhook events with document uploads

    Documents API

  • Workflow Events


    Monitor workflow execution via webhooks

    Workflows API