Skip to content

Webhooks

UniCraft provides webhook functionality for real-time notifications and event handling, allowing you to stay informed about important events and integrate with external systems.

Webhooks allow you to receive real-time notifications when specific events occur in UniCraft:

  • Request Events: Notifications when requests are completed or fail
  • Cost Events: Alerts when spending limits are reached
  • Provider Events: Notifications about provider status changes
  • Error Events: Alerts when errors occur
  • Custom Events: Notifications for custom-defined events
// Create a webhook via API
const webhook = await fetch("https://api.unicraft.com/v1/webhooks", {
method: "POST",
headers: {
Authorization: "Bearer your-unicraft-api-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Production Alerts",
url: "https://your-app.com/webhooks/unicraft",
events: [
"request.completed",
"request.failed",
"cost.exceeded",
"provider.unavailable",
],
secret: "your-webhook-secret",
enabled: true,
}),
});
const webhookData = await webhook.json();
console.log("Webhook created:", webhookData);
  1. Log into your UniCraft dashboard
  2. Navigate to SettingsWebhooks
  3. Click Add Webhook
  4. Configure the webhook:
    • Name: Descriptive name for the webhook
    • URL: Your endpoint URL
    • Events: Select events to monitor
    • Secret: Optional secret for verification
    • Enabled: Toggle webhook on/off
{
"event": "request.completed",
"timestamp": "2024-01-20T10:30:00Z",
"data": {
"request_id": "req_123456789",
"model": "gpt-3.5-turbo",
"provider": "openai",
"cost": 0.000042,
"response_time": 1250,
"tokens": {
"prompt": 50,
"completion": 25,
"total": 75
},
"user_id": "user_123",
"project_id": "proj_456"
}
}
{
"event": "request.failed",
"timestamp": "2024-01-20T10:30:00Z",
"data": {
"request_id": "req_123456789",
"model": "gpt-4",
"provider": "openai",
"error": {
"type": "rate_limit_exceeded",
"message": "Rate limit exceeded",
"code": "rate_limit_exceeded"
},
"retry_count": 3,
"user_id": "user_123",
"project_id": "proj_456"
}
}
{
"event": "cost.exceeded",
"timestamp": "2024-01-20T10:30:00Z",
"data": {
"budget_id": "budget_123",
"budget_name": "Monthly AI Budget",
"current_cost": 1050.0,
"limit": 1000.0,
"excess": 50.0,
"period": "monthly",
"user_id": "user_123",
"project_id": "proj_456"
}
}
{
"event": "cost.daily_alert",
"timestamp": "2024-01-20T10:30:00Z",
"data": {
"date": "2024-01-20",
"daily_cost": 85.0,
"daily_limit": 100.0,
"percentage": 85.0,
"user_id": "user_123",
"project_id": "proj_456"
}
}
{
"event": "provider.unavailable",
"timestamp": "2024-01-20T10:30:00Z",
"data": {
"provider": "openai",
"status": "unavailable",
"reason": "service_outage",
"estimated_recovery": "2024-01-20T11:00:00Z",
"affected_models": ["gpt-4", "gpt-3.5-turbo"]
}
}
{
"event": "provider.recovered",
"timestamp": "2024-01-20T11:00:00Z",
"data": {
"provider": "openai",
"status": "available",
"downtime_duration": 1800,
"affected_models": ["gpt-4", "gpt-3.5-turbo"]
}
}
{
"event": "error.high_rate",
"timestamp": "2024-01-20T10:30:00Z",
"data": {
"error_rate": 0.15,
"threshold": 0.1,
"time_window": "5m",
"provider": "openai",
"model": "gpt-4",
"error_types": [
{
"type": "rate_limit_exceeded",
"count": 25
},
{
"type": "invalid_request",
"count": 10
}
]
}
}

UniCraft signs webhook payloads with your secret:

const crypto = require("crypto");
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Express.js example
app.post("/webhooks/unicraft", (req, res) => {
const signature = req.headers["x-unicraft-signature"];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
// Process webhook
console.log("Webhook received:", req.body);
res.status(200).send("OK");
});

Restrict webhook access to specific IP addresses:

const allowedIPs = ["192.168.1.100", "10.0.0.50"];
function verifyIP(req, res, next) {
const clientIP = req.ip || req.connection.remoteAddress;
if (!allowedIPs.includes(clientIP)) {
return res.status(403).send("IP not allowed");
}
next();
}
app.post("/webhooks/unicraft", verifyIP, (req, res) => {
// Process webhook
});
const express = require("express");
const crypto = require("crypto");
const app = express();
app.use(express.json());
// Webhook endpoint
app.post("/webhooks/unicraft", (req, res) => {
const signature = req.headers["x-unicraft-signature"];
const payload = JSON.stringify(req.body);
// Verify signature
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
const event = req.body;
// Handle different events
switch (event.event) {
case "request.completed":
handleRequestCompleted(event.data);
break;
case "request.failed":
handleRequestFailed(event.data);
break;
case "cost.exceeded":
handleCostExceeded(event.data);
break;
case "provider.unavailable":
handleProviderUnavailable(event.data);
break;
default:
console.log("Unknown event:", event.event);
}
res.status(200).send("OK");
});
function handleRequestCompleted(data) {
console.log("Request completed:", data.request_id);
// Update database, send notifications, etc.
}
function handleRequestFailed(data) {
console.log("Request failed:", data.request_id, data.error);
// Log error, alert team, etc.
}
function handleCostExceeded(data) {
console.log("Cost exceeded:", data.budget_name, data.excess);
// Send alert, pause requests, etc.
}
function handleProviderUnavailable(data) {
console.log("Provider unavailable:", data.provider);
// Switch to backup provider, alert team, etc.
}
app.listen(3000, () => {
console.log("Webhook server running on port 3000");
});
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
app = Flask(__name__)
def verify_webhook_signature(payload, signature, secret):
expected_signature = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
@app.route('/webhooks/unicraft', methods=['POST'])
def webhook():
signature = request.headers.get('X-UniCraft-Signature')
payload = json.dumps(request.json)
# Verify signature
if not verify_webhook_signature(payload, signature, os.environ['WEBHOOK_SECRET']):
return jsonify({'error': 'Invalid signature'}), 401
event = request.json
# Handle different events
if event['event'] == 'request.completed':
handle_request_completed(event['data'])
elif event['event'] == 'request.failed':
handle_request_failed(event['data'])
elif event['event'] == 'cost.exceeded':
handle_cost_exceeded(event['data'])
elif event['event'] == 'provider.unavailable':
handle_provider_unavailable(event['data'])
return jsonify({'status': 'OK'})
def handle_request_completed(data):
print(f"Request completed: {data['request_id']}")
# Update database, send notifications, etc.
def handle_request_failed(data):
print(f"Request failed: {data['request_id']} - {data['error']}")
# Log error, alert team, etc.
def handle_cost_exceeded(data):
print(f"Cost exceeded: {data['budget_name']} - ${data['excess']}")
# Send alert, pause requests, etc.
def handle_provider_unavailable(data):
print(f"Provider unavailable: {data['provider']}")
# Switch to backup provider, alert team, etc.
if __name__ == '__main__':
app.run(port=3000)
// Get all webhooks
const webhooks = await fetch("https://api.unicraft.com/v1/webhooks", {
headers: {
Authorization: "Bearer your-unicraft-api-key",
},
});
const webhookList = await webhooks.json();
console.log("Webhooks:", webhookList);
// Update webhook
const updatedWebhook = await fetch(
"https://api.unicraft.com/v1/webhooks/webhook_123",
{
method: "PUT",
headers: {
Authorization: "Bearer your-unicraft-api-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Updated Webhook",
events: ["request.completed", "cost.exceeded"],
enabled: true,
}),
}
);
// Delete webhook
const deleted = await fetch(
"https://api.unicraft.com/v1/webhooks/webhook_123",
{
method: "DELETE",
headers: {
Authorization: "Bearer your-unicraft-api-key",
},
}
);
// Test webhook
const test = await fetch(
"https://api.unicraft.com/v1/webhooks/webhook_123/test",
{
method: "POST",
headers: {
Authorization: "Bearer your-unicraft-api-key",
},
}
);
const testResult = await test.json();
console.log("Test result:", testResult);
  • Idempotency: Make webhook handlers idempotent
  • Retry Logic: Implement retry logic for failed webhooks
  • Error Handling: Handle errors gracefully
  • Logging: Log all webhook events for debugging
  • Signature Verification: Always verify webhook signatures
  • HTTPS: Use HTTPS for webhook endpoints
  • IP Whitelisting: Restrict access to known IPs
  • Rate Limiting: Implement rate limiting on webhook endpoints
  • Async Processing: Process webhooks asynchronously
  • Queue System: Use message queues for high-volume webhooks
  • Monitoring: Monitor webhook performance and failures
  • Scaling: Scale webhook endpoints based on load
  • Timeout Handling: Set appropriate timeouts
  • Dead Letter Queue: Handle failed webhooks
  • Monitoring: Monitor webhook delivery success rates
  • Alerting: Set up alerts for webhook failures
  1. Webhook Not Receiving Events

    • Check webhook URL accessibility
    • Verify webhook is enabled
    • Check event configuration
  2. Signature Verification Fails

    • Verify webhook secret
    • Check payload format
    • Ensure proper signature generation
  3. Webhook Timeouts

    • Optimize webhook processing
    • Increase timeout settings
    • Use async processing
  4. Duplicate Events

    • Implement idempotency
    • Use event IDs for deduplication
    • Handle retries properly
  1. Enable Logging: Log all webhook events
  2. Test Endpoints: Use webhook testing tools
  3. Monitor Delivery: Track webhook delivery success
  4. Check Logs: Review UniCraft webhook logs

For support with webhooks:

After setting up webhooks:

  1. Test Webhooks: Test all webhook events
  2. Monitor Delivery: Set up monitoring for webhook delivery
  3. Handle Events: Implement proper event handling
  4. Scale Infrastructure: Scale webhook endpoints as needed
  5. Document Processes: Document webhook handling procedures