Webhook Configuration¶
ARX can deliver event notifications to external HTTP endpoints via webhooks. This guide covers registering webhook endpoints, the event payload format, HMAC-SHA256 signature verification, and retry behavior.
Overview¶
Webhooks provide a push-based mechanism for receiving ARX events in real time. When a subscribed event occurs, ARX sends an HTTP POST request to your registered endpoint with a JSON payload describing the event.
Webhooks are useful for: - Triggering downstream workflows in response to ARX events - Feeding events into custom analytics or monitoring systems - Integrating with platforms not directly supported by the built-in SIEM or notification integrations
Registering a Webhook Endpoint¶
Webhooks are configured as SIEM integrations with integration_type set to webhook:
POST /v1/settings/siem
{
"integration_type": "webhook",
"name": "Custom Event Webhook",
"config": {
"endpoint": "https://your-service.example.com/webhooks/arx",
"secret": "whsec_your-signing-secret-here",
"headers": {
"X-Custom-Header": "optional-custom-value"
}
},
"enabled": true
}
| Field | Required | Description |
|---|---|---|
endpoint |
Yes | The HTTPS URL where ARX will POST events |
secret |
Recommended | A shared secret used to compute the HMAC-SHA256 signature |
headers |
No | Additional HTTP headers included in every delivery |
Use HTTPS endpoints exclusively. HTTP endpoints transmit event data and signatures in the clear, which compromises security.
Event Types¶
ARX delivers the following event types via webhooks:
| Event Type | Description |
|---|---|
agent.deployed |
An agent was deployed |
agent.stopped |
An agent was stopped |
agent.error |
An agent encountered an error |
approval.requested |
A new approval request was created |
approval.reviewed |
An approval request was approved or denied |
approval.expired |
An approval request expired without review |
drift.detected |
Configuration drift was detected |
user.created |
A new user was provisioned |
user.deactivated |
A user was deactivated |
ip_allowlist.entry_added |
An IP allowlist entry was added |
ip_allowlist.entry_removed |
An IP allowlist entry was removed |
siem.integration.created |
A SIEM integration was configured |
encryption.config.updated |
Encryption settings were changed |
Payload Format¶
Each webhook delivery is an HTTP POST with a JSON body:
{
"id": "evt_a1b2c3d4e5f6",
"type": "agent.deployed",
"timestamp": "2026-04-11T14:30:00Z",
"org_id": "a1b2c3d4-...",
"data": {
"agent_id": "d0e8a7b2-...",
"agent_name": "production-scanner",
"deployed_by": "jane@example.com",
"environment": "production"
}
}
| Field | Type | Description |
|---|---|---|
id |
string | Unique event identifier (for deduplication) |
type |
string | The event type |
timestamp |
string | ISO 8601 timestamp of when the event occurred |
org_id |
string | Organization ID |
data |
object | Event-specific payload (varies by event type) |
HMAC-SHA256 Signature Verification¶
When a secret is configured on the webhook, every delivery includes an X-ARX-Signature header:
X-ARX-Signature: sha256=a4f8c29b1d3e5f7a09b2c4d6e8f0a1b3c5d7e9f1a3b5c7d9e1f3a5b7c9d1e3f5
The signature is computed as the HMAC-SHA256 of the raw request body using the secret as the key.
Verification Example (Python)¶
import hashlib
import hmac
def verify_arx_signature(
payload_body: bytes,
signature_header: str,
secret: str,
) -> bool:
"""Verify the X-ARX-Signature header from an ARX webhook delivery."""
if not signature_header.startswith("sha256="):
return False
expected_signature = "sha256=" + hmac.new(
secret.encode("utf-8"),
payload_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected_signature, signature_header)
Verification Example (Node.js)¶
const crypto = require('crypto');
function verifyArxSignature(payloadBody, signatureHeader, secret) {
const expectedSignature = 'sha256=' +
crypto.createHmac('sha256', secret)
.update(payloadBody, 'utf-8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(signatureHeader)
);
}
Verification Example (Go)¶
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
)
func verifyARXSignature(payloadBody []byte, signatureHeader, secret string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payloadBody)
expectedSignature := "sha256=" + hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expectedSignature), []byte(signatureHeader))
}
Important: Always use constant-time comparison (hmac.compare_digest, crypto.timingSafeEqual, hmac.Equal) to prevent timing attacks.
Signing Secret¶
The signing secret should be a cryptographically random string of at least 32 characters. Generate one with:
openssl rand -hex 32
Store the secret securely. If compromised, update the webhook configuration with a new secret immediately.
Retry Behavior¶
When a webhook delivery fails (non-2xx response or network error), ARX retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 10 seconds |
| 2nd retry | 30 seconds |
| 3rd retry | 60 seconds |
| 4th retry | 5 minutes |
| 5th retry | 15 minutes |
After all retries are exhausted, the delivery is marked as failed. The error_count on the integration record is incremented and the last_error field is updated with the failure details.
Your endpoint should return a 2xx status code within 10 seconds to indicate successful receipt. If your processing takes longer, accept the webhook and process it asynchronously.
Deduplication¶
Each event includes a unique id field. If your endpoint receives the same event ID more than once (due to retries or redelivery), treat the duplicate as a no-op. Implement idempotency on the consumer side.
Error Monitoring¶
Monitor webhook health through the SIEM integration response:
GET /v1/settings/siem
Each integration record includes:
| Field | Description |
|---|---|
error_count |
Consecutive delivery failures (resets to 0 on success) |
last_error |
Error message from the most recent failure |
last_event_at |
Timestamp of the last successful delivery |
Use the test endpoint to verify connectivity:
POST /v1/settings/siem/{integration_id}/test
Best Practices¶
- Always verify signatures. Reject any request where the
X-ARX-Signatureheader is missing or invalid. - Use HTTPS. Never register an HTTP endpoint for webhook delivery.
- Respond quickly. Return
200 OKimmediately and process the event asynchronously. - Implement idempotency. Use the event
idto detect and skip duplicate deliveries. - Monitor error counts. Set up alerting when
error_countexceeds a threshold. - Rotate secrets periodically. Update the webhook secret on a regular schedule.