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

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.