HIVE

Integrations

Webhooks

Webhooks

Webhooks enable real-time communication between HIVE Protocol and your external systems. When events occur in HIVE, webhook endpoints receive instant notifications, allowing you to build reactive integrations and automated workflows.

Overview

┌─────────────────────────────────────────────────────────────────┐
│                    Webhook Architecture                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   HIVE Protocol                        Your System               │
│  ┌─────────────┐                      ┌─────────────┐           │
│  │   Event     │   POST request       │  Webhook    │           │
│  │   Occurs    │ ─────────────────▶   │  Endpoint   │           │
│  │             │   with payload       │             │           │
│  │ - message   │                      │  - Verify   │           │
│  │ - swarm     │   ◀─────────────────  │  - Process  │           │
│  │ - agent     │   200 OK             │  - Act      │           │
│  └─────────────┘                      └─────────────┘           │
│                                                                  │
│  Features:                                                       │
│  - HMAC signature verification                                  │
│  - Automatic retry on failure                                   │
│  - Event filtering                                              │
│  - Delivery logging                                             │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Setting Up Webhooks

Creating a Webhook

  1. Navigate to Settings > Webhooks
  2. Click Create Webhook
  3. Fill in the configuration:
FieldDescriptionRequired
NameDescriptive identifierYes
URLHTTPS endpoint URLYes
EventsEvents to subscribe toYes
SecretHMAC signing secret (auto-generated)Yes
ActiveEnable/disable webhookYes
HeadersCustom headers to includeNo

Configuration Interface

┌─────────────────────────────────────────────────────────────────┐
│  Create Webhook                                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Name                                                            │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ Production Slack Notifier                                │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  Endpoint URL                                                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ https://api.yourcompany.com/webhooks/hive               │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  Events to Subscribe                                             │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ [x] message.created      [ ] message.updated            │    │
│  │ [x] message.flagged      [x] swarm.created              │    │
│  │ [x] swarm.completed      [ ] swarm.deleted              │    │
│  │ [x] agent.error          [ ] agent.created              │    │
│  │ [x] tool.executed        [ ] tool.error                 │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  Signing Secret                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ whsec_a1b2c3d4e5f6...                    [Regenerate]   │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  Custom Headers (Optional)                                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ X-Custom-Header: your-value                             │    │
│  │ Authorization: Bearer token123                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│                                    [Cancel]  [Create Webhook]    │
└─────────────────────────────────────────────────────────────────┘

Available Events

Message Events

EventTriggerPayload Includes
message.createdNew message sentmessage_id, swarm_id, content, sender
message.updatedMessage editedmessage_id, old_content, new_content
message.deletedMessage removedmessage_id, swarm_id
message.flaggedMessage flagged for reviewmessage_id, flag_reason, flagged_by

Example: message.created payload

{
  "id": "evt_msg_created_abc123",
  "type": "message.created",
  "created_at": "2024-01-15T10:30:00.000Z",
  "data": {
    "message_id": "msg_xyz789",
    "swarm_id": "swm_123456",
    "swarm_name": "Research Project",
    "content": "I've completed the analysis of the quarterly data.",
    "sender_type": "agent",
    "sender_id": "agt_456",
    "sender_name": "Data Analyst",
    "metadata": {
      "tokens_used": 245,
      "model": "gpt-4o",
      "latency_ms": 1234
    }
  }
}

Swarm Events

EventTriggerPayload Includes
swarm.createdNew swarm createdswarm_id, name, created_by
swarm.updatedSwarm settings changedswarm_id, changes
swarm.deletedSwarm removedswarm_id, deleted_by
swarm.completedSwarm task finishedswarm_id, result, duration
swarm.agent_addedAgent joined swarmswarm_id, agent_id
swarm.agent_removedAgent left swarmswarm_id, agent_id, reason

Example: swarm.completed payload

{
  "id": "evt_swarm_completed_def456",
  "type": "swarm.completed",
  "created_at": "2024-01-15T11:45:00.000Z",
  "data": {
    "swarm_id": "swm_123456",
    "swarm_name": "Research Project",
    "status": "completed",
    "result": {
      "summary": "Analysis complete with 15 insights generated",
      "outputs": ["report.pdf", "data.csv"]
    },
    "duration_seconds": 3600,
    "messages_count": 45,
    "tokens_used": {
      "input": 25000,
      "output": 12000,
      "total": 37000
    },
    "cost_usd": 0.45
  }
}

Agent Events

EventTriggerPayload Includes
agent.createdNew agent createdagent_id, name, model
agent.updatedAgent config changedagent_id, changes
agent.deletedAgent removedagent_id, deleted_by
agent.errorAgent encountered erroragent_id, error, context
agent.status_changedAgent status updateagent_id, old_status, new_status

Example: agent.error payload

{
  "id": "evt_agent_error_ghi789",
  "type": "agent.error",
  "created_at": "2024-01-15T12:00:00.000Z",
  "data": {
    "agent_id": "agt_456",
    "agent_name": "Data Analyst",
    "swarm_id": "swm_123456",
    "error": {
      "code": "RATE_LIMIT_EXCEEDED",
      "message": "OpenAI rate limit exceeded",
      "provider": "openai",
      "model": "gpt-4o"
    },
    "context": {
      "request_id": "req_abc123",
      "retry_count": 3,
      "last_message_id": "msg_xyz788"
    }
  }
}

Tool Events

EventTriggerPayload Includes
tool.executedTool successfully rantool_id, agent_id, result
tool.errorTool execution failedtool_id, agent_id, error

Example: tool.executed payload

{
  "id": "evt_tool_executed_jkl012",
  "type": "tool.executed",
  "created_at": "2024-01-15T12:15:00.000Z",
  "data": {
    "tool_id": "tool_weather_api",
    "tool_name": "Weather API",
    "agent_id": "agt_456",
    "agent_name": "Data Analyst",
    "swarm_id": "swm_123456",
    "execution": {
      "input": { "location": "San Francisco, CA" },
      "output": { "temperature": 65, "conditions": "sunny" },
      "duration_ms": 234
    }
  }
}

User Events

EventTriggerPayload Includes
user.joinedUser added to accountuser_id, email, role
user.removedUser removeduser_id, removed_by
user.role_changedUser role updateduser_id, old_role, new_role

Webhook Payload Structure

Common Fields

All webhook payloads include these fields:

{
  "id": "evt_unique_event_id",
  "type": "event.type",
  "created_at": "2024-01-15T10:30:00.000Z",
  "api_version": "2024-01-01",
  "data": {
    // Event-specific data
  }
}

HTTP Headers

Every webhook request includes these headers:

HeaderDescriptionExample
Content-TypeAlways JSONapplication/json
X-Hive-SignatureHMAC-SHA256 signaturesha256=abc123...
X-Hive-EventEvent typemessage.created
X-Hive-DeliveryUnique delivery IDdel_xyz789
X-Hive-TimestampUnix timestamp1705313400
User-AgentHIVE webhook agentHIVE-Webhook/1.0

Verifying Webhooks

Why Verify?

Always verify webhook signatures to ensure:

  • Request actually came from HIVE
  • Payload wasn't tampered with
  • Protection against replay attacks

Signature Verification

HIVE signs webhooks using HMAC-SHA256:

import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string,
  timestamp: string
): boolean {
  // Verify timestamp is recent (within 5 minutes)
  const now = Math.floor(Date.now() / 1000);
  const webhookTime = parseInt(timestamp, 10);
  if (Math.abs(now - webhookTime) > 300) {
    return false; // Reject old webhooks
  }

  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  // Compare signatures using timing-safe comparison
  const expectedBuffer = Buffer.from(`sha256=${expected}`, 'utf8');
  const signatureBuffer = Buffer.from(signature, 'utf8');

  if (expectedBuffer.length !== signatureBuffer.length) {
    return false;
  }

  return crypto.timingSafeEqual(expectedBuffer, signatureBuffer);
}

Complete Handler Examples

Node.js / Express:

import express from 'express';
import crypto from 'crypto';

const app = express();
app.use(express.raw({ type: 'application/json' }));

const WEBHOOK_SECRET = process.env.HIVE_WEBHOOK_SECRET;

app.post('/webhooks/hive', (req, res) => {
  const signature = req.headers['x-hive-signature'] as string;
  const timestamp = req.headers['x-hive-timestamp'] as string;
  const payload = req.body.toString();

  if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET, timestamp)) {
    console.error('Invalid webhook signature');
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Respond immediately
  res.status(200).json({ received: true });

  // Process asynchronously
  const event = JSON.parse(payload);
  processEvent(event).catch(console.error);
});

async function processEvent(event: any) {
  console.log(`Processing event: ${event.type}`);

  switch (event.type) {
    case 'message.created':
      await handleMessageCreated(event.data);
      break;
    case 'swarm.completed':
      await handleSwarmCompleted(event.data);
      break;
    case 'agent.error':
      await handleAgentError(event.data);
      break;
    default:
      console.log(`Unhandled event type: ${event.type}`);
  }
}

async function handleMessageCreated(data: any) {
  // Send to Slack
  await fetch(SLACK_WEBHOOK_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      text: `New message in ${data.swarm_name}: ${data.content.substring(0, 100)}...`
    })
  });
}

async function handleSwarmCompleted(data: any) {
  // Log completion metrics
  console.log(`Swarm ${data.swarm_name} completed in ${data.duration_seconds}s`);
}

async function handleAgentError(data: any) {
  // Alert on errors
  await sendPagerDutyAlert({
    summary: `Agent error: ${data.error.message}`,
    severity: 'warning',
    source: 'HIVE Protocol'
  });
}

Python / Flask:

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

app = Flask(__name__)
WEBHOOK_SECRET = os.environ.get('HIVE_WEBHOOK_SECRET')

def verify_signature(payload, signature, timestamp):
    # Check timestamp freshness
    if abs(time.time() - int(timestamp)) > 300:
        return False

    # Compute signature
    signed_payload = f"{timestamp}.{payload}"
    expected = 'sha256=' + hmac.new(
        WEBHOOK_SECRET.encode(),
        signed_payload.encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected, signature)

@app.route('/webhooks/hive', methods=['POST'])
def handle_webhook():
    payload = request.get_data(as_text=True)
    signature = request.headers.get('X-Hive-Signature')
    timestamp = request.headers.get('X-Hive-Timestamp')

    if not verify_signature(payload, signature, timestamp):
        return jsonify({'error': 'Invalid signature'}), 401

    event = request.get_json()

    # Process based on event type
    if event['type'] == 'message.created':
        handle_message(event['data'])
    elif event['type'] == 'agent.error':
        handle_error(event['data'])

    return jsonify({'received': True}), 200

Testing Webhooks

Built-in Test Feature

  1. Go to Settings > Webhooks
  2. Click on your webhook
  3. Click Send Test Event
  4. Select event type
  5. View delivery result
┌─────────────────────────────────────────────────────────────────┐
│  Test Webhook: Production Slack Notifier                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Select Event Type:                                              │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ message.created                                    [v]   │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  Test Payload Preview:                                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │ {                                                        │    │
│  │   "id": "evt_test_123",                                 │    │
│  │   "type": "message.created",                            │    │
│  │   "data": { ... }                                       │    │
│  │ }                                                        │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│                                         [Cancel] [Send Test]     │
└─────────────────────────────────────────────────────────────────┘

Local Development with ngrok

# Install ngrok
npm install -g ngrok

# Start your local server
npm run dev  # Running on localhost:3000

# In another terminal, expose your local server
ngrok http 3000

# You'll see output like:
# Forwarding: https://abc123.ngrok.io -> http://localhost:3000

# Use https://abc123.ngrok.io/webhooks/hive as your webhook URL

Webhook Delivery Logs

View recent deliveries in the dashboard:

┌─────────────────────────────────────────────────────────────────┐
│  Recent Deliveries                                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  del_abc123  message.created   200 OK    234ms    2 min ago     │
│  del_def456  swarm.completed   200 OK    156ms    5 min ago     │
│  del_ghi789  agent.error       500 Error 2034ms   8 min ago [R] │
│  del_jkl012  message.created   200 OK    189ms    12 min ago    │
│                                                                  │
│  [R] = Scheduled for retry                                      │
│                                                                  │
│  Click on a delivery to see full request/response details       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Retry Behavior

Automatic Retries

HIVE automatically retries failed webhook deliveries:

AttemptDelayTotal Time
1Immediate0
21 minute1 min
35 minutes6 min
430 minutes36 min
52 hours2h 36m
68 hours10h 36m

Retry Conditions

Webhooks are retried when:

  • HTTP status code is 5xx (server error)
  • Connection timeout (30 seconds)
  • Connection refused/reset

Webhooks are NOT retried when:

  • HTTP status code is 2xx (success)
  • HTTP status code is 4xx (client error, except 429)
  • HTTP status code is 429 (retried with backoff)

Handling Retries

Make your handlers idempotent:

import { createClient } from '@supabase/supabase-js';

const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);

async function handleEvent(event: any) {
  // Check if already processed using event ID
  const { data: existing } = await supabase
    .from('processed_webhooks')
    .select('id')
    .eq('event_id', event.id)
    .maybeSingle();

  if (existing) {
    console.log(`Event ${event.id} already processed, skipping`);
    return;
  }

  // Process the event
  await processEvent(event);

  // Mark as processed
  await supabase
    .from('processed_webhooks')
    .insert({ event_id: event.id, processed_at: new Date().toISOString() });
}

Best Practices

1. Respond Quickly

Return 200 immediately, process asynchronously:

app.post('/webhook', (req, res) => {
  // Verify signature first
  if (!verifySignature(req)) {
    return res.status(401).send('Unauthorized');
  }

  // Respond immediately
  res.status(200).json({ received: true });

  // Queue for background processing
  queue.add('process-webhook', req.body);
});

2. Use a Queue System

For high-volume webhooks:

import { Queue, Worker } from 'bullmq';

const webhookQueue = new Queue('webhooks');

// In your webhook handler
app.post('/webhook', async (req, res) => {
  await webhookQueue.add('process', req.body);
  res.status(200).send('OK');
});

// Worker processes events
new Worker('webhooks', async (job) => {
  const event = job.data;
  await processEvent(event);
});

3. Implement Circuit Breakers

Protect downstream services:

import CircuitBreaker from 'opossum';

const slackBreaker = new CircuitBreaker(sendToSlack, {
  timeout: 5000,
  errorThresholdPercentage: 50,
  resetTimeout: 30000
});

async function handleMessage(data: any) {
  try {
    await slackBreaker.fire(data);
  } catch (error) {
    console.error('Slack notification failed:', error);
    // Queue for retry or fallback
  }
}

4. Log Everything

Maintain detailed logs for debugging:

function logWebhook(event: any, status: string, error?: Error) {
  console.log(JSON.stringify({
    timestamp: new Date().toISOString(),
    event_id: event.id,
    event_type: event.type,
    status,
    error: error?.message,
    processing_time_ms: Date.now() - startTime
  }));
}

Troubleshooting

Common Issues

IssueCauseSolution
401 UnauthorizedInvalid signatureCheck webhook secret matches
TimeoutSlow processingRespond immediately, process async
Duplicate eventsRetry deliveryImplement idempotency
Missing eventsWrong event selectionCheck webhook event subscriptions
SSL ErrorInvalid certificateEnsure valid HTTPS certificate

Debugging Checklist

[ ] Webhook endpoint is HTTPS
[ ] Endpoint returns 200 within 30 seconds
[ ] Signature verification uses correct secret
[ ] Event types are correctly subscribed
[ ] Handler processes events idempotently
[ ] Logs capture all webhook activity
[ ] Error handling doesn't crash the server
  • [Available Integrations](/docs/integrations/available-integrations): Overview of all integrations
  • [Custom Tools](/docs/integrations/custom-tools): Build your own tools
  • [API Reference](/docs/api/authentication): API documentation

Cookie Preferences

We use cookies to enhance your experience, analyze site traffic, and for marketing purposes. By clicking "Accept All", you consent to our use of cookies. Read our Privacy Policy for more information.