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​
Attempt | Delay |
---|---|
1 | Immediate |
2 | 1 minute |
3 | 5 minutes |
4 | 30 minutes |
5 | 2 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:
- API Overview - Learn about other API endpoints
- Crew APIs - Deploy and manage AI crews
- Authentication - Secure your API access