Skip to main content

Webhooks

Webhooks allow you to receive real-time notifications when events occur in HornetHive, such as when outcomes are completed, crews finish processing, or integrations are executed. This eliminates the need to continuously poll the API for updates.

Overview​

HornetHive webhooks are HTTP POST requests sent to your specified endpoint when events occur. Each webhook includes:

  • Event type: What happened (e.g., outcome.completed)
  • Timestamp: When the event occurred
  • Data payload: Relevant information about the event
  • Signature: For verifying the webhook authenticity

Setting Up Webhooks​

Create a Webhook​

Register a webhook endpoint to receive notifications:

POST /v1/webhooks

Request Body​

{
"url": "https://your-app.com/webhooks/hornethive",
"events": [
"outcome.completed",
"outcome.failed",
"outcome.revision_requested",
"crew.deployed",
"integration.executed"
],
"secret": "your_webhook_secret_key",
"description": "Production webhook for outcome notifications",
"active": true
}

Response​

{
"id": "wh_1234567890abcdef",
"url": "https://your-app.com/webhooks/hornethive",
"events": [
"outcome.completed",
"outcome.failed",
"outcome.revision_requested",
"crew.deployed",
"integration.executed"
],
"secret": "your_webhook_secret_key",
"description": "Production webhook for outcome notifications",
"active": true,
"created_at": "2024-01-15T10:30:00Z",
"last_delivery": null,
"delivery_count": 0
}

Available Events​

Outcome Events​

outcome.created

  • Triggered when a new outcome is created
  • Sent immediately after crew deployment

outcome.processing

  • Triggered when outcome processing begins
  • Includes initial progress information

outcome.completed

  • Triggered when an outcome is successfully completed
  • Includes the final result and metadata

outcome.failed

  • Triggered when outcome processing fails
  • Includes error information and failure reason

outcome.revision_requested

  • Triggered when a revision is requested
  • Includes revision details and requirements

Crew Events​

crew.deployed

  • Triggered when a crew is successfully deployed
  • Includes crew information and initial status

crew.agent_started

  • Triggered when individual agents begin processing
  • Includes agent information and current stage

crew.agent_completed

  • Triggered when individual agents complete their tasks
  • Includes agent results and next steps

Integration Events​

integration.executed

  • Triggered when integrations are executed
  • Includes integration results and status

integration.failed

  • Triggered when integrations fail
  • Includes error information and retry details

Webhook Payloads​

Outcome Completed​

{
"event": "outcome.completed",
"timestamp": "2024-01-15T10:33:24Z",
"data": {
"outcome_id": "out_1234567890abcdef",
"crew": "hivewriter",
"status": "completed",
"created_at": "2024-01-15T10:30:00Z",
"completed_at": "2024-01-15T10:33:24Z",
"processing_time_seconds": 204,
"result": {
"content": "# AI Automation for Small Businesses\n\nIn today's competitive landscape...",
"metadata": {
"word_count": 1847,
"reading_time": "7 minutes",
"seo_score": 85
}
},
"quality_metrics": {
"overall_score": 92,
"criteria": {
"relevance": 95,
"clarity": 88,
"completeness": 94
}
},
"integrations_executed": [
{
"type": "linkedin",
"status": "completed",
"post_url": "https://linkedin.com/posts/..."
}
]
}
}

Outcome Failed​

{
"event": "outcome.failed",
"timestamp": "2024-01-15T10:35:12Z",
"data": {
"outcome_id": "out_1234567890abcdef",
"crew": "hivewriter",
"status": "failed",
"created_at": "2024-01-15T10:30:00Z",
"failed_at": "2024-01-15T10:35:12Z",
"error": {
"code": "content_generation_failed",
"message": "Unable to generate content meeting quality standards",
"details": {
"stage": "content_creation",
"agent": "ContentAgent",
"retry_count": 3,
"last_error": "Content quality score below threshold (45/100)"
}
},
"retry_available": true,
"estimated_retry_time": "2024-01-15T10:40:00Z"
}
}

Crew Deployed​

{
"event": "crew.deployed",
"timestamp": "2024-01-15T10:30:05Z",
"data": {
"outcome_id": "out_1234567890abcdef",
"crew": "hivepilot",
"status": "processing",
"agents_deployed": [
"ProductAgent",
"TechnicalAgent",
"PlanningAgent"
],
"estimated_completion": "2024-01-15T10:45:00Z",
"brief": "Create PRD for user notification system",
"requirements": {
"format": "standard_prd",
"include_user_stories": true
}
}
}

Integration Executed​

{
"event": "integration.executed",
"timestamp": "2024-01-15T10:34:15Z",
"data": {
"outcome_id": "out_1234567890abcdef",
"integration": {
"type": "slack",
"action": "post_message",
"status": "completed",
"details": {
"channel": "#content-team",
"message_ts": "1705315455.123456",
"permalink": "https://workspace.slack.com/archives/C1234567890/p1705315455123456"
}
},
"execution_time_ms": 1250
}
}

Webhook Security​

Signature Verification​

HornetHive signs all webhook payloads using HMAC-SHA256. Verify the signature to ensure the webhook is authentic:

Header: X-HornetHive-Signature Format: sha256=<signature>

Verification Examples​

Node.js:

const crypto = require('crypto');

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

const receivedSignature = signature.replace('sha256=', '');

return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(receivedSignature, 'hex')
);
}

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

if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Unauthorized');
}

const event = JSON.parse(payload);
console.log('Received event:', event.event);

res.status(200).send('OK');
});

Python:

import hmac
import hashlib

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

received_signature = signature.replace('sha256=', '')

return hmac.compare_digest(expected_signature, received_signature)

# Flask example
from flask import Flask, request, abort
import json

app = Flask(__name__)

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

if not verify_webhook(payload, signature, os.getenv('WEBHOOK_SECRET')):
abort(401)

event = json.loads(payload)
print(f"Received event: {event['event']}")

return 'OK', 200

PHP:

function verifyWebhook($payload, $signature, $secret) {
$expectedSignature = hash_hmac('sha256', $payload, $secret);
$receivedSignature = str_replace('sha256=', '', $signature);

return hash_equals($expectedSignature, $receivedSignature);
}

// Usage
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_HORNETHIVE_SIGNATURE'];
$secret = getenv('WEBHOOK_SECRET');

if (!verifyWebhook($payload, $signature, $secret)) {
http_response_code(401);
exit('Unauthorized');
}

$event = json_decode($payload, true);
echo "Received event: " . $event['event'];

Webhook Management​

List Webhooks​

Get all webhooks for your account:

GET /v1/webhooks

Response​

{
"webhooks": [
{
"id": "wh_1234567890abcdef",
"url": "https://your-app.com/webhooks/hornethive",
"events": ["outcome.completed", "outcome.failed"],
"active": true,
"created_at": "2024-01-15T10:30:00Z",
"last_delivery": "2024-01-15T10:33:24Z",
"delivery_count": 42,
"success_rate": 0.98
}
]
}

Update Webhook​

Modify an existing webhook:

PATCH /v1/webhooks/{webhook_id}

Request Body​

{
"events": [
"outcome.completed",
"outcome.failed",
"crew.deployed"
],
"active": true,
"description": "Updated webhook for production"
}

Delete Webhook​

Remove a webhook:

DELETE /v1/webhooks/{webhook_id}

Delivery and Retries​

Delivery Expectations​

  • Timeout: 30 seconds
  • Expected Response: HTTP 2xx status code
  • Retry Policy: Exponential backoff for failed deliveries
  • Max Retries: 5 attempts over 24 hours

Retry Schedule​

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

Delivery Logs​

View webhook delivery history:

GET /v1/webhooks/{webhook_id}/deliveries

Response​

{
"deliveries": [
{
"id": "del_1234567890abcdef",
"event": "outcome.completed",
"status": "success",
"response_code": 200,
"delivered_at": "2024-01-15T10:33:25Z",
"response_time_ms": 245,
"attempt": 1
},
{
"id": "del_0987654321fedcba",
"event": "outcome.failed",
"status": "failed",
"response_code": 500,
"delivered_at": "2024-01-15T10:35:15Z",
"response_time_ms": 30000,
"attempt": 3,
"next_retry": "2024-01-15T11:05:15Z"
}
]
}

Testing Webhooks​

Test Webhook​

Send a test event to verify your webhook endpoint:

POST /v1/webhooks/{webhook_id}/test

Request Body​

{
"event": "outcome.completed"
}

Test Payload​

{
"event": "webhook.test",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"webhook_id": "wh_1234567890abcdef",
"test": true,
"message": "This is a test webhook from HornetHive"
}
}

Local Testing​

Use tools like ngrok for local development:

# Install ngrok
npm install -g ngrok

# Expose local server
ngrok http 3000

# Use the ngrok URL for your webhook
# https://abc123.ngrok.io/webhooks/hornethive

Best Practices​

1. Implement Idempotency​

Handle duplicate webhook deliveries gracefully:

const processedEvents = new Set();

app.post('/webhooks/hornethive', (req, res) => {
const event = req.body;
const eventId = event.data.outcome_id + '_' + event.event + '_' + event.timestamp;

if (processedEvents.has(eventId)) {
return res.status(200).send('Already processed');
}

processedEvents.add(eventId);

// Process the event
handleEvent(event);

res.status(200).send('OK');
});

2. Respond Quickly​

Acknowledge webhooks quickly and process asynchronously:

app.post('/webhooks/hornethive', (req, res) => {
// Acknowledge immediately
res.status(200).send('OK');

// Process asynchronously
setImmediate(() => {
processWebhook(req.body);
});
});

3. Handle Failures Gracefully​

Implement proper error handling:

app.post('/webhooks/hornethive', (req, res) => {
try {
const event = req.body;

// Validate event structure
if (!event.event || !event.data) {
return res.status(400).send('Invalid event structure');
}

// Process event
processEvent(event);

res.status(200).send('OK');
} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).send('Internal server error');
}
});

4. Monitor Webhook Health​

Track webhook delivery success rates:

const webhookMetrics = {
delivered: 0,
failed: 0,

recordSuccess() {
this.delivered++;
},

recordFailure() {
this.failed++;
},

getSuccessRate() {
const total = this.delivered + this.failed;
return total > 0 ? this.delivered / total : 0;
}
};

Common Use Cases​

1. Outcome Completion Notifications​

Notify your team when content is ready:

function handleOutcomeCompleted(event) {
const { outcome_id, crew, result } = event.data;

// Send Slack notification
sendSlackMessage({
channel: '#content-team',
text: `🎉 ${crew} completed outcome ${outcome_id}`,
attachments: [{
title: 'Content Ready for Review',
text: result.metadata.word_count + ' words generated',
color: 'good'
}]
});

// Update database
updateOutcomeStatus(outcome_id, 'completed', result);
}

2. Integration Workflow Triggers​

Trigger additional workflows when integrations complete:

function handleIntegrationExecuted(event) {
const { outcome_id, integration } = event.data;

if (integration.type === 'linkedin' && integration.status === 'completed') {
// Schedule follow-up social media posts
scheduleFollowUpPosts(outcome_id, integration.details.post_url);

// Track engagement metrics
trackSocialEngagement(integration.details.post_url);
}
}

3. Error Handling and Alerts​

Alert on failures and trigger recovery:

function handleOutcomeFailed(event) {
const { outcome_id, error, retry_available } = event.data;

// Send alert to operations team
sendAlert({
severity: 'high',
message: `Outcome ${outcome_id} failed: ${error.message}`,
details: error.details
});

// Auto-retry if available
if (retry_available) {
setTimeout(() => {
retryOutcome(outcome_id);
}, 60000); // Retry after 1 minute
}
}

Troubleshooting​

Common Issues​

Webhook Not Receiving Events:

  • Verify the webhook URL is accessible from the internet
  • Check that your server is responding with 2xx status codes
  • Ensure the webhook is active and configured for the right events

Signature Verification Failing:

  • Verify you're using the correct webhook secret
  • Ensure you're using the raw request body for signature calculation
  • Check that the signature header is being read correctly

High Failure Rate:

  • Monitor your server response times (should be < 30 seconds)
  • Check server logs for errors during webhook processing
  • Verify your server can handle the webhook volume

Debug Mode​

Enable debug mode to see detailed webhook information:

PATCH /v1/webhooks/{webhook_id}
{
"debug": true
}

When debug mode is enabled, webhook payloads include additional debugging information.


Next Steps: