Base path: https://api.aegis-kyt.com/v1/webhooks · Auth: X-API-Key: aeg_<48 chars>
Register a subscription
curl -X POST https://api.aegis-kyt.com/v1/webhooks \
-H "X-API-Key: aeg_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/aegis-events",
"events": ["tx.policy.alert.triggered"],
"failure_threshold": 5
}'
Response (HTTP 200):
{
"schema_version": 1,
"id": "9f0a3a07-37bb-4f99-91b5-…",
"url": "https://your-app.example.com/aegis-events",
"events": ["tx.policy.alert.triggered"],
"secret": "aegws_secret_xxx…",
"is_active": true,
"created_at": "2026-05-20T09:14:01.234Z"
}
secret is returned ONLY on creation. Store it server-side
immediately — you’ll need it to verify the X-Aegis-Signature
header on every delivery, and we never return it again. Lost the
secret? Delete the subscription and create a new one.
Validation:
url must start with https:// (or http://localhost for dev).
events must be a non-empty subset of the allowlist (see
Event schemas for the current set).
failure_threshold is optional, defaults to 5, range 1..50.
Auto-disable kicks in after this many consecutive gave_up
deliveries.
List subscriptions
curl https://api.aegis-kyt.com/v1/webhooks \
-H "X-API-Key: aeg_YOUR_KEY_HERE"
{
"schema_version": 1,
"subscriptions": [
{
"id": "9f0a3a07-…",
"url": "https://your-app.example.com/aegis-events",
"events": ["tx.policy.alert.triggered"],
"is_active": true,
"created_at": "2026-05-20T09:14:01.234Z",
"updated_at": "2026-05-20T09:14:01.234Z",
"last_delivery_at": null,
"last_failure_at": null,
"consecutive_failures": 0,
"failure_threshold": 5
}
]
}
secret is never returned by this endpoint or by GET /v1/webhooks/{id}.
Get one subscription
curl https://api.aegis-kyt.com/v1/webhooks/9f0a3a07-… \
-H "X-API-Key: aeg_YOUR_KEY_HERE"
Returns 404 if the subscription doesn’t exist or isn’t owned by
your API key (IDOR guard).
Update — toggle / change events
curl -X PUT https://api.aegis-kyt.com/v1/webhooks/9f0a3a07-… \
-H "X-API-Key: aeg_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"is_active": true,
"events": ["tx.policy.alert.triggered", "aegis.check.high_risk"]
}'
Setting is_active: true also resets consecutive_failures to
zero, so this is the canonical way to re-enable a subscription
after auto-disable.
Both fields are optional — send only what you want to change.
Delete
curl -X DELETE https://api.aegis-kyt.com/v1/webhooks/9f0a3a07-… \
-H "X-API-Key: aeg_YOUR_KEY_HERE"
Cascades to the aegis_webhook_deliveries history; you can’t get
this data back. Pending deliveries already queued in
BackgroundTasks may still fire once after delete (best-effort).
Send a synthetic test event
curl -X POST https://api.aegis-kyt.com/v1/webhooks/9f0a3a07-…/test \
-H "X-API-Key: aeg_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"event_type": "tx.policy.alert.triggered"}'
Response:
{
"schema_version": 1,
"subscription_id": "9f0a3a07-…",
"event_type": "tx.policy.alert.triggered",
"deliveries_enqueued": 1,
"synthetic": true
}
What happens next:
- We build a synthetic payload for the requested
event_type —
sentinel ids (00000000-…), a top-level synthetic: true
field, and minimum-viable fields per event_type.
- We sign + POST it to just this subscription’s URL (the
only_subscription_id filter — your other subs won’t see it).
- Retry policy is the same as production events: 5 attempts
over ~1 h. This intentionally lets you verify your retry /
idempotency handling, not just first-call signature checks.
Request body
| Field | Required | Default | Notes |
|---|
event_type | no | First event in the subscription’s events[] | Must be one of the events you’re subscribed to — sending a test for an unsubscribed event returns 400 |
Errors
| Status | Code | Meaning |
|---|
| 400 | bad_request | event_type is not in this subscription’s events |
| 400 | bad_request | Subscription has no events configured |
| 401 | (auth) | Missing or invalid API key |
| 404 | not_found | Subscription not owned by this caller |
Recipes
Verify your handler before going live
# 1) Create the subscription pointed at your prod endpoint
SUB=$(curl -s -X POST https://api.aegis-kyt.com/v1/webhooks \
-H "X-API-Key: $AEG" -H "Content-Type: application/json" \
-d '{"url": "https://prod.example.com/aegis", "events": ["tx.policy.alert.triggered"]}')
SUB_ID=$(echo "$SUB" | jq -r .id)
# 2) Save the secret — last chance!
echo "$SUB" | jq -r .secret > /run/secrets/aegis_webhook_secret
# 3) Fire a synthetic event — your endpoint should accept + return 2xx
curl -X POST https://api.aegis-kyt.com/v1/webhooks/$SUB_ID/test \
-H "X-API-Key: $AEG"
# 4) If the test fails, check logs. Common causes:
# - signature mismatch (re-serialised JSON before HMAC, wrong secret)
# - your endpoint rejects {synthetic: true} payloads
# - your firewall blocks the source IP (our outbound is from the
# Hetzner range; whitelist if you have egress filtering)
Re-enable after auto-disable
curl -X PUT https://api.aegis-kyt.com/v1/webhooks/$SUB_ID \
-H "X-API-Key: $AEG" -H "Content-Type: application/json" \
-d '{"is_active": true}'
(also resets consecutive_failures to 0)