Avena · Webhooks

Push notifications,
institutionally signed.

Register an HTTPS endpoint. Avena POSTs to it every time a new event fires — macro anomaly, sovereign briefing, signed AVN-ID, cross-validation snapshot. Every delivery is HMAC-SHA256 signed with your subscription secret. Same security contract as Stripe and GitHub webhooks.

Active subscribers
0
Events supported
5
Deliveries 24h
0
Success rate 24h
100.0%
Event catalogue

Five event types live.

anomaly.detected● live

Any new row in eu_anomalies — z-score ≥ 2σ deviation from trailing 8-period mean. Fires on every cron tick at 06:00 UTC.

anomaly.critical● live

Subset of anomaly.detected — fires only when severity = critical (≥3σ). Useful for paging escalation.

briefing.published● live

New sovereign briefing volume published. Payload includes slug, title, abstract, body URL.

avn_id.issued● live

New AVN-ID minted by /api/v1/avn-id/issue. Payload includes the canonical identifier + signature.

validation.snapshot● live

New row in eu_validation_snapshots — Avena cohort vs official series delta. Fires daily 05:30 UTC.

Register a subscription

One POST, you're live.

Send your callback URL plus the events you want. Avena returns a subscription_id and a one-time-visible secret. Store the secret — you'll use it to verify every signature.

curl -X POST https://avenaterminal.com/api/v1/subscriptions/webhooks \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://your-system.example.com/webhooks/avena",
    "events": ["anomaly.critical", "briefing.published"],
    "contact_email": "ops@your-bank.eu",
    "organisation": "Example Bank EU"
  }'

Response:

{
  "ok": true,
  "subscription_id": "8b3c0a91-...-...",
  "secret": "9f2e7b...32-byte hex...c4d1",
  "events": ["anomaly.critical", "briefing.published"]
}
Delivery contract

What every Avena POST looks like.

POST /your/callback/url HTTP/1.1
Host: your-system.example.com
Content-Type: application/json
X-Avena-Event: anomaly.critical
X-Avena-Signature: sha256=4f9c8b...64-hex...e123
X-Avena-Delivery-Id: 8e2a14c5...
User-Agent: Avena-Webhook/1.0

{
  "event": "anomaly.critical",
  "timestamp": "2026-05-25T06:00:14.221Z",
  "data": {
    "country_code": "ES",
    "source": "ecb_sdw",
    "indicator_code": "MIR::M.ES.B.A2C.AM.R.A.2250.EUR.N",
    "indicator_name": "Mortgage rate — Spain, new business",
    "period": "2026-04",
    "value": 3.85,
    "z_score": 3.42,
    "severity": "critical",
    "trend": "up",
    "note": "Latest 3.85 vs trailing 8-period mean 2.41 (σ=0.42) → z-score 3.42.",
    "source_url": "https://data-api.ecb.europa.eu/service/data/MIR/..."
  }
}

Return any 2xx response within 8 seconds to acknowledge. Avena increments your failure_count on any non-2xx or timeout; after 10 consecutive failures the subscription auto-pauses.

Signature verification

Three lines in any language.

# Node.js
import { createHmac, timingSafeEqual } from 'crypto';

function verifyAvenaWebhook(rawBody: string, signature: string, secret: string): boolean {
  const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
  return signature.length === expected.length &&
    timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

# Python
import hmac, hashlib
def verify(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = 'sha256=' + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

If verification fails, return 401 — Avena's retry logic will respect that response and pause your subscription if it persists.

Health endpoint

GET /api/v1/subscriptions/webhooks returns anonymised aggregate stats (active subscriber count, supported events, 24-hour delivery success rate). No URLs, no secrets, no contact info.

Full API documentation · Live anomaly feed · Institutional contact