Webhooks
Receive real-time notifications when events happen in your Hebbrix account. Webhooks let you build reactive integrations that respond instantly to memory changes, document processing, and more.
How Webhooks Work
When an event occurs (like a new memory being created), Hebbrix sends an HTTP POST request to your configured endpoint with details about the event. Your server processes the payload and responds with a 2xx status to acknowledge receipt.
Event Occurs
Memory created, document processed, etc.
Webhook Fired
POST request sent to your endpoint
You Process
Handle the event and respond 2xx
Supported Events
| Event | Description |
|---|---|
memory.created | A new memory was created |
memory.updated | A memory was updated |
memory.deleted | A memory was deleted |
memory.tier_changed | A memory was promoted/demoted between tiers |
document.created | A new document was uploaded |
document.processed | Document processing finished (searchable) |
document.failed | Document processing failed |
document.deleted | A document was deleted |
collection.created | A new collection was created |
collection.updated | A collection's metadata or members changed |
search.completed | A hybrid/graph search returned results |
user.feedback_received | User provided explicit feedback on a memory / answer |
rl.training_started | A reinforcement-learning job kicked off |
rl.training_completed | Reinforcement-learning job finished successfully |
rl.training_failed | Reinforcement-learning job failed |
Endpoints
Webhook Payload
Every webhook delivery includes these standard fields:
{
"id": "evt_abc123xyz",
"event_type": "memory.created",
"timestamp": 1705315800,
"data": {
"id": "mem_xyz789",
"content": "User prefers dark mode",
"collection_id": "col_default",
"importance": 0.75,
"created_at": "2024-01-15T10:30:00Z"
},
"idempotency_key": "memory.created:mem_xyz789:550e8400-e29b-41d4-a716-446655440000:wh_abc123"
}timestamp is a Unix epoch integer (seconds). Use idempotency_key to deduplicate — the same key is used for all retry attempts of a single delivery.
Verifying Signatures
Always verify signatures
Every webhook includes a signature in the X-Webhook-Signature-256 header (format sha256=<hex>) and the signing timestamp inX-Webhook-Timestamp. Verify both using your signing_secret to confirm the request came from Hebbrix.
import hmac
import hashlib
from flask import Flask, request
app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_secret_here"
@app.route("/webhooks/hebbrix", methods=["POST"])
def handle_webhook():
# Get the signature + timestamp from headers
signature = request.headers.get("X-Webhook-Signature-256", "")
timestamp = request.headers.get("X-Webhook-Timestamp")
# Strip the "sha256=" prefix
if signature.startswith("sha256="):
signature = signature[7:]
# Create the signed payload (timestamp.body)
payload = f"{timestamp}.{request.data.decode()}"
# Calculate expected signature
expected = hmac.new(
WEBHOOK_SECRET.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
# Verify signature matches (timing-safe)
if not hmac.compare_digest(signature, expected):
return "Invalid signature", 401
# Process the event
event = request.json
print(f"Received event: {event['event_type']}")
if event["event_type"] == "memory.created":
handle_memory_created(event["data"])
elif event["event_type"] == "document.processed":
handle_document_processed(event["data"])
return "OK", 200import crypto from 'crypto';
import express from 'express';
const app = express();
const WEBHOOK_SECRET = 'whsec_your_secret_here';
app.post('/webhooks/hebbrix', express.raw({type: 'application/json'}), (req, res) => {
const signatureHeader = (req.headers['x-webhook-signature-256'] || '') as string;
const timestamp = req.headers['x-webhook-timestamp'] as string;
// Strip the "sha256=" prefix
const signature = signatureHeader.startsWith('sha256=')
? signatureHeader.slice(7)
: signatureHeader;
// Create the signed payload (timestamp.body)
const payload = `${timestamp}.${req.body.toString()}`;
// Calculate expected signature
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
// Verify signature matches (timing-safe)
const sigBuf = Buffer.from(signature, 'hex');
const expBuf = Buffer.from(expected, 'hex');
if (sigBuf.length !== expBuf.length || !crypto.timingSafeEqual(sigBuf, expBuf)) {
return res.status(401).send('Invalid signature');
}
// Process the event
const event = JSON.parse(req.body.toString());
console.log(`Received event: ${event.event_type}`);
switch (event.event_type) {
case 'memory.created':
handleMemoryCreated(event.data);
break;
case 'document.processed':
handleDocumentProcessed(event.data);
break;
}
res.status(200).send('OK');
});Retry Policy
If your endpoint doesn't respond with a 2xx status (or the request times out / errors at the transport layer), delivery is retried with exponential backoff up to 5 total attempts. Backoff waits 2^attempt seconds, clamped to a minimum of 4 seconds and a maximum of 3600 seconds (1 hour) between attempts.
After 5 failed attempts the delivery is moved to the Dead Letter Queue (DLQ) and marked as failed. Each attempt uses the same idempotency_keyso your receiver can safely deduplicate.
Best Practices
Respond Quickly
Return a 2xx response within 30 seconds. Process events asynchronously if needed.
Handle Duplicates
Use the event ID to deduplicate. The same event may be delivered multiple times.
Verify Signatures
Always verify the X-Webhook-Signature-256 header to ensure authenticity.
Use HTTPS
HTTPS recommended; HTTP is accepted for public hosts. Localhost endpoints are rejected for security.
cURL Example
/v1/webhookscurl -X POST "https://api.hebbrix.com/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/hebbrix",
"events": [
"memory.created",
"document.processed"
]
}'