Skip to main content

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:

FieldTypeDescription
urlStringHTTPS endpoint (must be accessible from public internet)
eventsArrayEvent types to subscribe to (see Event Types below)

Optional Fields:

FieldTypeDefaultDescription
descriptionString""Human-readable description
activeBooleantrueWebhook is enabled
headersObjectCustom headers to include in requests
auth_tokenString""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:

ParameterTypeDescription
activeBooleanFilter by status (true/false)
limitIntegerItems 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):

FieldTypeDescription
urlStringNew endpoint URL
eventsArrayUpdated event subscriptions
activeBooleanEnable/disable webhook
descriptionStringUpdated 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

EventPayloadDescription
interaction.createdInteraction objectNew AI interaction logged
interaction.policy_violatedInteraction + policy decisionPolicy triggered (block/coach/log)
interaction.high_riskInteraction objectRisk score >= 0.8
interaction.classifiedInteraction + classificationsTier 2/3 classification completed

Alert Events

EventPayloadDescription
alert.createdAlert objectNew security alert
alert.severity_criticalAlert objectCritical severity alert
alert.severity_highAlert objectHigh severity alert
alert.resolvedAlert objectAlert marked as resolved

Policy Events

EventPayloadDescription
policy.createdPolicy objectNew policy created
policy.updatedPolicy objectPolicy modified
policy.deletedPolicy IDPolicy deleted
policy.enabledPolicy objectPolicy activated
policy.disabledPolicy objectPolicy deactivated

User Events

EventPayloadDescription
user.invitedUser objectUser invited to organization
user.activatedUser objectUser accepted invitation
user.role_changedUser objectUser role modified
user.deletedUser IDUser 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:

AttemptDelayTimeout
1Immediate5 seconds
25 seconds5 seconds
330 seconds5 seconds
45 minutes5 seconds
530 minutes5 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

  1. Verify signatures — Always verify X-Noxys-Signature header
  2. Use HTTPS — All webhook URLs must be HTTPS
  3. Idempotent processing — Handle duplicate deliveries gracefully (same event may arrive twice)
  4. Fast responses — Respond quickly (< 5 seconds); use async processing if needed
  5. Handle retries — Log and monitor webhook deliveries
  6. Secure secrets — Store signing_secret securely; never commit to code
  7. Error logging — Log failures; check /webhooks/:id/deliveries regularly

Troubleshooting

Webhook Not Receiving Events

  1. Check webhook is active: true
  2. Verify URL is publicly accessible
  3. Verify events match your subscriptions
  4. Check delivery history: GET /webhooks/:id/deliveries
  5. Test manually: POST /webhooks/:id/test

Signature Verification Fails

  1. Ensure you're using the raw request body (not parsed JSON)
  2. Use correct signing_secret from webhook object
  3. Use HMAC-SHA256 algorithm
  4. 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?