Webhooks API
Webhooks deliver real-time events (policy violations, high-risk interactions, user actions) to your systems as they happen. Ideal for SIEM integration, alerting, and workflow automation.
Overview
Webhooks allow you to:
- Receive alerts in real-time as policies are violated
- Integrate with SIEM (Splunk, Sentinel, Datadog) without polling
- Trigger automation in response to events
- Build custom workflows on top of Noxys data
Create Webhook
Register an endpoint to receive events.
Endpoint: POST /api/v1/webhooks
Request:
curl -X POST https://api.noxys.cloud/api/v1/webhooks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/webhooks/noxys",
"events": [
"interaction.created",
"interaction.policy_violated",
"alert.severity_high"
],
"active": true,
"description": "Send all policy violations to our SIEM"
}'
Required Fields:
| Field | Type | Description |
|---|---|---|
url | String | HTTPS endpoint (must be accessible from public internet) |
events | Array | Event types to subscribe to (see Event Types below) |
Optional Fields:
| Field | Type | Default | Description |
|---|---|---|---|
description | String | "" | Human-readable description |
active | Boolean | true | Webhook is enabled |
headers | Object | Custom headers to include in requests | |
auth_token | String | "" | Bearer token for authenticating requests from webhook |
Response (201 Created):
{
"id": "whk_abc123def456",
"url": "https://your-app.example.com/webhooks/noxys",
"events": [
"interaction.created",
"interaction.policy_violated",
"alert.severity_high"
],
"active": true,
"description": "Send all policy violations to our SIEM",
"signing_secret": "whsec_1234567890abcdef",
"created_at": "2026-03-20T10:00:00Z"
}
Signing Secret: Use this to verify webhook requests (see Verification below).
List Webhooks
Get all registered webhooks.
Endpoint: GET /api/v1/webhooks
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
active | Boolean | Filter by status (true/false) |
limit | Integer | Items per page (default: 50) |
Example:
curl "https://api.noxys.cloud/api/v1/webhooks?active=true" \
-H "Authorization: Bearer $TOKEN"
Response (200 OK):
{
"webhooks": [
{
"id": "whk_abc123def456",
"url": "https://your-app.example.com/webhooks/noxys",
"events": ["interaction.created", "interaction.policy_violated"],
"active": true,
"created_at": "2026-03-20T10:00:00Z",
"last_delivery": "2026-03-20T14:32:00Z",
"delivery_count": 1234
}
],
"total": 2
}
Get Webhook
Retrieve a single webhook.
Endpoint: GET /api/v1/webhooks/:id
Example:
curl https://api.noxys.cloud/api/v1/webhooks/whk_abc123def456 \
-H "Authorization: Bearer $TOKEN"
Response (200 OK): Full webhook object.
Update Webhook
Modify webhook configuration.
Endpoint: PUT /api/v1/webhooks/:id
Request:
curl -X PUT https://api.noxys.cloud/api/v1/webhooks/whk_abc123def456 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/webhooks/noxys-v2",
"events": [
"interaction.policy_violated",
"alert.severity_critical"
],
"active": true
}'
Fields (all optional):
| Field | Type | Description |
|---|---|---|
url | String | New endpoint URL |
events | Array | Updated event subscriptions |
active | Boolean | Enable/disable webhook |
description | String | Updated description |
Response (200 OK): Updated webhook object.
Delete Webhook
Remove a webhook.
Endpoint: DELETE /api/v1/webhooks/:id
Example:
curl -X DELETE https://api.noxys.cloud/api/v1/webhooks/whk_abc123def456 \
-H "Authorization: Bearer $TOKEN"
Response (204 No Content).
Event Types
Interaction Events
| Event | Payload | Description |
|---|---|---|
interaction.created | Interaction object | New AI interaction logged |
interaction.policy_violated | Interaction + policy decision | Policy triggered (block/coach/log) |
interaction.high_risk | Interaction object | Risk score >= 0.8 |
interaction.classified | Interaction + classifications | Tier 2/3 classification completed |
Alert Events
| Event | Payload | Description |
|---|---|---|
alert.created | Alert object | New security alert |
alert.severity_critical | Alert object | Critical severity alert |
alert.severity_high | Alert object | High severity alert |
alert.resolved | Alert object | Alert marked as resolved |
Policy Events
| Event | Payload | Description |
|---|---|---|
policy.created | Policy object | New policy created |
policy.updated | Policy object | Policy modified |
policy.deleted | Policy ID | Policy deleted |
policy.enabled | Policy object | Policy activated |
policy.disabled | Policy object | Policy deactivated |
User Events
| Event | Payload | Description |
|---|---|---|
user.invited | User object | User invited to organization |
user.activated | User object | User accepted invitation |
user.role_changed | User object | User role modified |
user.deleted | User ID | User deleted |
Webhook Payload Format
All webhooks receive JSON with this structure:
{
"id": "evt_abc123def456",
"timestamp": "2026-03-20T14:32:00Z",
"event_type": "interaction.policy_violated",
"tenant_id": "00000000-0000-0000-0000-000000000001",
"data": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"platform_id": "chatgpt",
"risk_score": 0.95,
"classifications": [
{
"type": "EMAIL",
"value": "alice@acme.fr",
"score": 0.98
}
],
"policy_decisions": [
{
"policy_id": "c8d4e2f1-aaaa-bbbb-cccc-000000000001",
"policy_name": "Block PII on ChatGPT",
"action": "block"
}
]
}
}
Webhook Verification
Verify requests came from Noxys using HMAC-SHA256 signatures.
Header: X-Noxys-Signature
Format: sha256=<hex-encoded-signature>
Algorithm:
HMAC_SHA256(signing_secret, request_body)
Example: Verification in Node.js
const crypto = require('crypto');
const express = require('express');
const app = express();
app.use(express.raw({ type: 'application/json' }));
const SIGNING_SECRET = 'whsec_1234567890abcdef';
app.post('/webhooks/noxys', (req, res) => {
// Get signature from header
const signature = req.headers['x-noxys-signature'];
// Compute expected signature
const hash = crypto
.createHmac('sha256', SIGNING_SECRET)
.update(req.body)
.digest('hex');
const expected = `sha256=${hash}`;
// Compare signatures (constant-time comparison)
if (!crypto.timingSafeEqual(signature, expected)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
const event = JSON.parse(req.body);
console.log(`Received event: ${event.event_type}`);
res.json({ received: true });
});
app.listen(3000);
Example: Verification in Python
import hmac
import hashlib
import json
from flask import Flask, request
app = Flask(__name__)
SIGNING_SECRET = 'whsec_1234567890abcdef'
@app.route('/webhooks/noxys', methods=['POST'])
def webhook():
# Get signature from header
signature = request.headers.get('X-Noxys-Signature', '')
# Get raw body
body = request.get_data()
# Compute expected signature
expected_hash = hmac.new(
SIGNING_SECRET.encode(),
body,
hashlib.sha256
).hexdigest()
expected_signature = f"sha256={expected_hash}"
# Compare signatures (constant-time comparison)
if not hmac.compare_digest(signature, expected_signature):
return {'error': 'Invalid signature'}, 401
# Process webhook
event = json.loads(body)
print(f"Received event: {event['event_type']}")
return {'received': True}, 200
if __name__ == '__main__':
app.run(port=3000)
Retry Logic
Noxys retries failed deliveries with exponential backoff:
| Attempt | Delay | Timeout |
|---|---|---|
| 1 | Immediate | 5 seconds |
| 2 | 5 seconds | 5 seconds |
| 3 | 30 seconds | 5 seconds |
| 4 | 5 minutes | 5 seconds |
| 5 | 30 minutes | 5 seconds |
Success Criteria:
- HTTP 2xx status code
- Response within 5 seconds
If all retries fail, webhook is disabled and you'll receive an email alert.
Testing Webhooks
Manual Test Delivery
Endpoint: POST /api/v1/webhooks/:id/test
curl -X POST https://api.noxys.cloud/api/v1/webhooks/whk_abc123def456/test \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event_type": "interaction.policy_violated"
}'
Response (200 OK):
{
"delivered": true,
"status_code": 200,
"response_time_ms": 125,
"timestamp": "2026-03-20T14:32:00Z"
}
View Delivery History
Endpoint: GET /api/v1/webhooks/:id/deliveries
curl "https://api.noxys.cloud/api/v1/webhooks/whk_abc123def456/deliveries?limit=50" \
-H "Authorization: Bearer $TOKEN"
Response (200 OK):
{
"deliveries": [
{
"id": "dlv_abc123",
"timestamp": "2026-03-20T14:32:00Z",
"event_type": "interaction.policy_violated",
"status_code": 200,
"response_time_ms": 125,
"success": true
},
{
"id": "dlv_abc124",
"timestamp": "2026-03-20T14:31:00Z",
"event_type": "interaction.created",
"status_code": 500,
"response_time_ms": 5000,
"success": false,
"error": "Internal server error"
}
],
"total": 1234
}
Code Examples
Python: Set Up Webhook for Policy Violations
import requests
BASE_URL = "https://api.noxys.cloud/api/v1"
TOKEN = "eyJhbGc..."
headers = {"Authorization": f"Bearer {TOKEN}"}
# Create webhook
webhook_data = {
"url": "https://your-app.example.com/webhooks/noxys",
"events": [
"interaction.policy_violated",
"alert.severity_critical"
],
"description": "Send policy violations to SIEM",
"active": True
}
response = requests.post(f"{BASE_URL}/webhooks", headers=headers, json=webhook_data)
webhook = response.json()
print(f"Created webhook: {webhook['id']}")
print(f"Signing secret: {webhook['signing_secret']}")
# Test delivery
test_response = requests.post(
f"{BASE_URL}/webhooks/{webhook['id']}/test",
headers=headers,
json={"event_type": "interaction.policy_violated"}
)
print(f"Test delivered: {test_response.json()['delivered']}")
# List deliveries
deliveries_response = requests.get(
f"{BASE_URL}/webhooks/{webhook['id']}/deliveries?limit=10",
headers=headers
)
deliveries = deliveries_response.json()["deliveries"]
for delivery in deliveries:
status = "✓" if delivery['success'] else "✗"
print(f"{status} {delivery['timestamp']}: {delivery['event_type']} ({delivery['status_code']})")
Go: Create and Monitor Webhook
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
const BaseURL = "https://api.noxys.cloud/api/v1"
type WebhookRequest struct {
URL string `json:"url"`
Events []string `json:"events"`
Description string `json:"description"`
Active bool `json:"active"`
}
func createWebhook(token string) error {
webhook := WebhookRequest{
URL: "https://your-app.example.com/webhooks/noxys",
Events: []string{
"interaction.policy_violated",
"alert.severity_critical",
},
Description: "SIEM integration",
Active: true,
}
payload, _ := json.Marshal(webhook)
req, _ := http.NewRequest("POST", BaseURL+"/webhooks", bytes.NewReader(payload))
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 201 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("API error: %s", string(body))
}
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Printf("Created webhook: %v\n", result["id"])
fmt.Printf("Signing secret: %v\n", result["signing_secret"])
return nil
}
func main() {
token := "eyJhbGc..."
createWebhook(token)
}
Best Practices
- Verify signatures — Always verify
X-Noxys-Signatureheader - Use HTTPS — All webhook URLs must be HTTPS
- Idempotent processing — Handle duplicate deliveries gracefully (same event may arrive twice)
- Fast responses — Respond quickly (< 5 seconds); use async processing if needed
- Handle retries — Log and monitor webhook deliveries
- Secure secrets — Store
signing_secretsecurely; never commit to code - Error logging — Log failures; check
/webhooks/:id/deliveriesregularly
Troubleshooting
Webhook Not Receiving Events
- Check webhook is
active: true - Verify URL is publicly accessible
- Verify events match your subscriptions
- Check delivery history:
GET /webhooks/:id/deliveries - Test manually:
POST /webhooks/:id/test
Signature Verification Fails
- Ensure you're using the raw request body (not parsed JSON)
- Use correct
signing_secretfrom webhook object - Use HMAC-SHA256 algorithm
- Compare signatures with
crypto.timingSafeEqual(constant-time comparison)
Webhook Disabled After Errors
Check email for notification. To re-enable:
curl -X PUT https://api.noxys.cloud/api/v1/webhooks/whk_abc123def456 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"active": true}'
What's Next?
- Events API — Create and query interactions
- SIEM Integrations — Pre-built integration guides