Webhooks
FORG can send HTTP POST notifications to your endpoints when important events occur. Webhooks are signed with HMAC-SHA256 so you can verify authenticity.
Register a webhook
POST /api/v1/webhooks
Content-Type: application/json
Authorization: Bearer forg_live_...
{
"url": "https://your-server.com/forg-webhook",
"events": ["budget.exceeded", "rule.triggered", "anomaly.detected"],
"secret": "your-webhook-secret-min-32-chars"
}{
"id": "wh_9f3a2b1c",
"url": "https://your-server.com/forg-webhook",
"events": ["budget.exceeded", "rule.triggered", "anomaly.detected"],
"enabled": true,
"created_at": "2025-05-28T10:00:00Z"
}Webhook events
| Event | Fired when |
|---|---|
session.started | A new session begins |
session.ended | A session ends (timeout or explicit close) |
budget.exceeded | A budget rule threshold is crossed |
budget.warning | A budget reaches 80% of its threshold |
rule.triggered | Any rule fires (block, warn, notify, or log) |
anomaly.detected | The intelligence layer detects unusual activity |
Payload schema
// All webhook payloads have this envelope:
{
"id": "wev_4a2b9c1d",
"type": "budget.exceeded",
"org_id": "org_abc123",
"ts": "2025-05-28T14:30:00Z",
"data": { ... } // event-specific payload
}
// budget.exceeded data:
{
"rule_id": "rule_7b3c1d9e",
"rule_name": "Monthly $500 org budget",
"scope": "org",
"scope_id": "org_abc123",
"threshold": 500,
"current": 502.34,
"window": "monthly",
"metric": "cost_usd"
}
// rule.triggered data:
{
"rule_id": "rule_9a2b3c",
"rule_name": "Block GPT-4o",
"action": "block",
"user_id": "user_abc",
"model": "gpt-4o",
"session_id": "sess_xyz",
"event_id": "evt_123"
}
// anomaly.detected data:
{
"anomaly_type": "token_spike",
"user_id": "user_abc",
"baseline_avg": 1200,
"observed": 9840,
"deviation_pct": 720,
"session_id": "sess_xyz"
}Verifying signatures
Each webhook request includes an X-Forg-Signature header containing an HMAC-SHA256 of the raw request body, signed with your webhook secret:
X-Forg-Signature: sha256=a3f9e2c1b84d7f6e0a2c1d8e9f0b3c4d...// Node.js verification
import crypto from "crypto";
function verifyWebhook(body: string, signature: string, secret: string): boolean {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(body, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
// In your Express handler:
app.post("/forg-webhook", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.headers["x-forg-signature"] as string;
if (!verifyWebhook(req.body.toString(), sig, process.env.FORG_WEBHOOK_SECRET!)) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(req.body.toString());
console.log("Received:", event.type, event.data);
res.sendStatus(200);
});Retry policy
FORG retries failed webhook deliveries (non-2xx response or timeout) with exponential backoff:
- Attempt 1: immediate
- Attempt 2: 30 seconds
- Attempt 3: 5 minutes
- Attempt 4: 30 minutes
- Attempt 5: 2 hours
After 5 failed attempts, the webhook is marked as failing and an alert is sent to the org admin. The webhook remains enabled but delivery is paused until you re-enable it in the dashboard.
Delivery timeout
Your endpoint must respond within 10 seconds. Return 200 immediately and process asynchronously if needed. Long-running handlers will cause retries.
List webhooks
GET /api/v1/webhooksDelete a webhook
DELETE /api/v1/webhooks/:idTest delivery
POST /api/v1/webhooks/:id/testSends a test session.started event to the endpoint.