Webhooks
Setting Up Webhooks
You can configure webhook endpoints through the dashboard or via the management API. Each webhook endpoint subscribes to one or more event types and receives HTTP POST requests with JSON payloads whenever those events occur.
Via the Dashboard
- Navigate to Settings > Webhooks in your dashboard
- Click Add Endpoint
- Enter your HTTPS endpoint URL
- Select the event types you want to receive
- Click Create and copy the signing secret
Via the API
curl -X POST https://api.bolor.ai/v1/webhooks \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/bolor",
"events": [
"agentguard.action.blocked",
"agentguard.action.approved",
"compliance.check.failed",
"mindvault.memory.stored"
],
"description": "Production event handler"
}'
# Response:
# {
# "id": "wh_abc123",
# "url": "https://your-app.com/webhooks/bolor",
# "events": ["agentguard.action.blocked", ...],
# "signing_secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxx",
# "status": "active",
# "created_at": "2026-02-14T12:00:00Z"
# }Important: Your webhook endpoint must use HTTPS and respond with a 2xx status code within 30 seconds. Endpoints that consistently fail will be automatically disabled after 5 consecutive failures.
Event Types
Subscribe to specific event types to receive only the notifications you need. Events are organized by product.
AgentGuard Events
| Event | Description |
|---|---|
agentguard.action.approved | An agent action was approved and executed |
agentguard.action.blocked | An agent action was blocked by safety rules |
agentguard.action.review | An agent action requires human review |
ComplianceGraph Events
| Event | Description |
|---|---|
compliance.check.passed | A compliance check passed all rules |
compliance.check.failed | A compliance check failed one or more rules |
compliance.rule.updated | A compliance rule was created or modified |
MindVault Events
| Event | Description |
|---|---|
mindvault.memory.stored | A new memory entity was stored |
mindvault.graph.updated | Knowledge graph relationships were modified |
System Events
| Event | Description |
|---|---|
system.rate_limit.warning | Usage reached 80% of rate limit |
system.rate_limit.exceeded | Rate limit was exceeded |
Webhook Payload
Every webhook delivery sends a JSON payload with a consistent structure. The data field contains event-specific information.
{
"id": "evt_abc123def456",
"type": "agentguard.action.blocked",
"created_at": "2026-02-14T15:30:00Z",
"workspace_id": "ws_xyz789",
"data": {
"action_id": "act_001",
"agent_id": "agent_support_v2",
"action_type": "api_call",
"blocked_reason": "Exceeded spending limit",
"rules_violated": ["max_transaction_amount"],
"safety_score": 23,
"proposed_action": {
"tool": "payment_api",
"method": "POST",
"params": {"amount": 50000, "currency": "USD"}
}
}
}Signature Verification
Every webhook request includes a signature in the X-Bolor-Signature header. You should verify this signature to ensure the request came from Bolor Intelligence and was not tampered with.
The signature is computed as an HMAC-SHA256 of the raw request body using your webhook signing secret.
Python Verification
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
"""Verify a Bolor Intelligence webhook signature."""
expected = hmac.new(
secret.encode("utf-8"),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
# In your webhook handler (Flask example):
from flask import Flask, request, abort
app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_signing_secret"
@app.route("/webhooks/bolor", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-Bolor-Signature", "")
if not verify_webhook(request.data, signature, WEBHOOK_SECRET):
abort(401, "Invalid signature")
event = request.json
event_type = event["type"]
if event_type == "agentguard.action.blocked":
# Handle blocked agent action
print(f"Action blocked: {event['data']['blocked_reason']}")
return "", 200Node.js Verification
import crypto from "crypto";
import express from "express";
const app = express();
const WEBHOOK_SECRET = "whsec_your_signing_secret";
function verifyWebhook(payload: string, signature: string): boolean {
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(payload, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(`sha256=${expected}`),
Buffer.from(signature)
);
}
app.post("/webhooks/bolor", express.raw({ type: "*/*" }), (req, res) => {
const signature = req.headers["x-bolor-signature"] as string;
const payload = req.body.toString();
if (!verifyWebhook(payload, signature)) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(payload);
switch (event.type) {
case "agentguard.action.blocked":
console.log(`Action blocked: ${event.data.blocked_reason}`);
break;
case "compliance.check.failed":
console.log(`Compliance failed: ${event.data.rules_violated}`);
break;
}
res.status(200).send("OK");
});Retry Policy
If your endpoint returns a non-2xx status code or times out (30 second limit), Bolor Intelligence will retry the delivery with exponential backoff.
| Attempt | Delay | Cumulative Time |
|---|---|---|
| 1st retry | 1 minute | 1 minute |
| 2nd retry | 5 minutes | 6 minutes |
| 3rd retry | 30 minutes | 36 minutes |
| 4th retry | 2 hours | ~2.5 hours |
| 5th retry (final) | 8 hours | ~10.5 hours |
After 5 failed retries, the event is marked as failed and will not be retried automatically. You can view failed deliveries in the dashboard and manually retry them.
Automatic disabling: If your endpoint fails to respond successfully 5 consecutive times across different events, the webhook will be automatically disabled. You will receive an email notification and can re-enable it from the dashboard.
Next Steps
- SDKs & Libraries →
Our SDKs include built-in webhook verification helpers.
- Getting Started →
Go back to the beginning and set up your first integration.