Skip to main content
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:
  1. 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.
  2. We sign + POST it to just this subscription’s URL (the only_subscription_id filter — your other subs won’t see it).
  3. 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

FieldRequiredDefaultNotes
event_typenoFirst 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

StatusCodeMeaning
400bad_requestevent_type is not in this subscription’s events
400bad_requestSubscription has no events configured
401(auth)Missing or invalid API key
404not_foundSubscription 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)