HIVE

API Reference

Webhooks API

Webhooks API

The Webhooks API allows you to create, manage, and monitor webhooks for receiving real-time event notifications from HIVE Protocol.

Database Schema

-- webhooks table
CREATE TABLE webhooks (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id) NOT NULL,
  name TEXT NOT NULL,
  url TEXT NOT NULL,
  secret TEXT NOT NULL,
  events TEXT[] NOT NULL,
  is_active BOOLEAN DEFAULT true,
  headers JSONB DEFAULT '{}',
  retry_count INTEGER DEFAULT 3,
  timeout_ms INTEGER DEFAULT 30000,
  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now()
);

-- webhook_deliveries table
CREATE TABLE webhook_deliveries (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  webhook_id UUID REFERENCES webhooks(id) ON DELETE CASCADE,
  event_type TEXT NOT NULL,
  payload JSONB NOT NULL,
  status TEXT DEFAULT 'pending',
  status_code INTEGER,
  response_body TEXT,
  attempts INTEGER DEFAULT 0,
  next_retry_at TIMESTAMPTZ,
  delivered_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- RLS Policies
ALTER TABLE webhooks ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users can manage own webhooks"
  ON webhooks FOR ALL TO authenticated
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

Endpoints Overview

OperationMethodEndpointDescription
ListGET/rest/v1/webhooksGet all webhooks
GetGET/rest/v1/webhooks?id=eq.{id}Get single webhook
CreatePOST/rest/v1/webhooksCreate webhook
UpdatePATCH/rest/v1/webhooks?id=eq.{id}Update webhook
DeleteDELETE/rest/v1/webhooks?id=eq.{id}Delete webhook
TestPOST/functions/v1/test-webhookSend test event
DeliveriesGET/rest/v1/webhook_deliveriesGet delivery history

List Webhooks

Retrieve all webhooks for the authenticated user.

Request

const { data: webhooks, error } = await supabase
  .from('webhooks')
  .select(`
    *,
    webhook_deliveries (
      id,
      status,
      created_at
    )
  `)
  .order('created_at', { ascending: false });

Response

{
  "data": [
    {
      "id": "bb0e8400-e29b-41d4-a716-446655440001",
      "user_id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Slack Notifier",
      "url": "https://api.mycompany.com/webhooks/hive",
      "secret": "whsec_abc123...",
      "events": [
        "message.created",
        "swarm.completed",
        "agent.error"
      ],
      "is_active": true,
      "headers": {
        "X-Custom-Header": "custom-value"
      },
      "retry_count": 3,
      "timeout_ms": 30000,
      "created_at": "2024-01-15T10:00:00.000Z",
      "updated_at": "2024-01-15T10:00:00.000Z",
      "webhook_deliveries": [
        {
          "id": "cc0e8400-e29b-41d4-a716-446655440001",
          "status": "delivered",
          "created_at": "2024-01-15T14:30:00.000Z"
        }
      ]
    }
  ],
  "error": null
}

Create Webhook

Create a new webhook endpoint.

Request

const { data: webhook, error } = await supabase
  .from('webhooks')
  .insert({
    name: 'Production Notifier',
    url: 'https://api.mycompany.com/webhooks/hive',
    events: [
      'message.created',
      'message.flagged',
      'swarm.created',
      'swarm.completed',
      'agent.error',
      'tool.executed'
    ],
    headers: {
      'X-Source': 'hive-protocol',
      'X-Environment': 'production'
    },
    retry_count: 5,
    timeout_ms: 15000
  })
  .select()
  .single();

// Secret is auto-generated
console.log('Webhook secret:', webhook.secret);

Request Body

FieldTypeRequiredDescription
namestringYesWebhook display name
urlstringYesHTTPS endpoint URL
eventsstring[]YesEvents to subscribe to
headersobjectNoCustom headers to include
is_activebooleanNoEnable/disable (default: true)
retry_countintegerNoMax retries (default: 3)
timeout_msintegerNoTimeout (default: 30000)

Available Events

Message Events:

  • message.created - New message in swarm
  • message.updated - Message edited
  • message.deleted - Message removed
  • message.flagged - Message flagged for review

Swarm Events:

  • swarm.created - New swarm created
  • swarm.updated - Swarm settings changed
  • swarm.deleted - Swarm removed
  • swarm.completed - Swarm task finished
  • swarm.agent_added - Agent joined swarm
  • swarm.agent_removed - Agent left swarm

Agent Events:

  • agent.created - New agent created
  • agent.updated - Agent config changed
  • agent.deleted - Agent removed
  • agent.error - Agent encountered error
  • agent.status_changed - Agent status update

Tool Events:

  • tool.executed - Tool successfully ran
  • tool.error - Tool execution failed

User Events:

  • user.joined - User added to account
  • user.removed - User removed
  • user.role_changed - User role updated

Response

{
  "data": {
    "id": "bb0e8400-e29b-41d4-a716-446655440002",
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Production Notifier",
    "url": "https://api.mycompany.com/webhooks/hive",
    "secret": "whsec_7a8b9c0d1e2f3g4h5i6j7k8l9m0n",
    "events": ["message.created", "swarm.completed", "agent.error"],
    "is_active": true,
    "headers": {},
    "retry_count": 5,
    "timeout_ms": 15000,
    "created_at": "2024-01-15T15:00:00.000Z",
    "updated_at": "2024-01-15T15:00:00.000Z"
  },
  "error": null
}

Update Webhook

Update webhook configuration.

Request

const { data: webhook, error } = await supabase
  .from('webhooks')
  .update({
    name: 'Updated Name',
    events: ['message.created', 'agent.error'],
    is_active: true
  })
  .eq('id', webhookId)
  .select()
  .single();

Regenerate Secret

const response = await fetch(
  `${SUPABASE_URL}/functions/v1/webhooks`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      action: 'regenerate_secret',
      webhook_id: webhookId
    })
  }
);

const { new_secret } = await response.json();

Delete Webhook

Delete a webhook.

Request

const { error } = await supabase
  .from('webhooks')
  .delete()
  .eq('id', webhookId);

Test Webhook

Send a test event to verify webhook configuration.

Edge Function: test-webhook

const response = await fetch(
  `${process.env.NEXT_PUBLIC_SUPABASE_URL}/functions/v1/test-webhook`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
      'apikey': process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
    },
    body: JSON.stringify({
      webhook_id: webhookId,
      event_type: 'message.created'
    })
  }
);

const result = await response.json();

Response

{
  "success": true,
  "delivery_id": "cc0e8400-e29b-41d4-a716-446655440002",
  "status_code": 200,
  "response_time_ms": 234,
  "response_body": "{\"received\": true}"
}

Webhook Deliveries

Get delivery history and status.

List Deliveries

const { data: deliveries, error } = await supabase
  .from('webhook_deliveries')
  .select('*')
  .eq('webhook_id', webhookId)
  .order('created_at', { ascending: false })
  .limit(50);

Response

{
  "data": [
    {
      "id": "cc0e8400-e29b-41d4-a716-446655440001",
      "webhook_id": "bb0e8400-e29b-41d4-a716-446655440001",
      "event_type": "message.created",
      "payload": {
        "id": "evt_abc123",
        "type": "message.created",
        "data": {
          "message_id": "880e8400-e29b-41d4-a716-446655440001",
          "swarm_id": "660e8400-e29b-41d4-a716-446655440001",
          "content": "Hello, world!"
        }
      },
      "status": "delivered",
      "status_code": 200,
      "response_body": "{\"received\": true}",
      "attempts": 1,
      "delivered_at": "2024-01-15T14:30:01.000Z",
      "created_at": "2024-01-15T14:30:00.000Z"
    },
    {
      "id": "cc0e8400-e29b-41d4-a716-446655440002",
      "webhook_id": "bb0e8400-e29b-41d4-a716-446655440001",
      "event_type": "agent.error",
      "payload": {...},
      "status": "failed",
      "status_code": 500,
      "response_body": "Internal Server Error",
      "attempts": 3,
      "next_retry_at": null,
      "delivered_at": null,
      "created_at": "2024-01-15T14:00:00.000Z"
    }
  ],
  "error": null
}

Delivery Status Values

StatusDescription
pendingAwaiting delivery
deliveredSuccessfully delivered
failedAll retries exhausted
retryingScheduled for retry

Retry a Failed Delivery

const response = await fetch(
  `${SUPABASE_URL}/functions/v1/webhook-dispatcher`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      action: 'retry',
      delivery_id: deliveryId
    })
  }
);

Webhook Payload Format

All webhook payloads follow this structure:

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

Headers Sent

HeaderDescription
Content-Typeapplication/json
X-Hive-SignatureHMAC-SHA256 signature
X-Hive-EventEvent type
X-Hive-DeliveryDelivery UUID
X-Hive-TimestampUnix timestamp

Signature Verification

Always verify webhook signatures:

import crypto from 'crypto';

function verifySignature(
  payload: string,
  signature: string,
  timestamp: string,
  secret: string
): boolean {
  // Check timestamp freshness (5 minutes)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp)) > 300) {
    return false;
  }

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

  return crypto.timingSafeEqual(
    Buffer.from(signature.replace('sha256=', '')),
    Buffer.from(expected)
  );
}

// Express handler
app.post('/webhooks/hive', express.raw({ type: 'application/json' }), (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 (!verifySignature(payload, signature, timestamp, WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

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

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

Retry Behavior

Failed deliveries are automatically retried:

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

Retry Conditions

Retried:

  • 5xx status codes
  • Connection timeout
  • Connection refused

Not Retried:

  • 2xx status codes (success)
  • 4xx status codes (client error)
  • Except 429 (rate limited, with backoff)

Error Codes

CodeStatusDescription
WEBHOOK_NOT_FOUND404Webhook does not exist
WEBHOOK_DISABLED403Webhook is disabled
INVALID_URL400URL is not valid HTTPS
INVALID_EVENTS400Unknown event types
DELIVERY_FAILED502Endpoint returned error
  • [Webhooks Guide](/docs/integrations/webhooks): Full webhook guide
  • [Swarms API](/docs/api/swarms-api): Swarm events
  • [Messages API](/docs/api/messages-api): Message events