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.
Five event types 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.
Subset of anomaly.detected — fires only when severity = critical (≥3σ). Useful for paging escalation.
New sovereign briefing volume published. Payload includes slug, title, abstract, body URL.
New AVN-ID minted by /api/v1/avn-id/issue. Payload includes the canonical identifier + signature.
New row in eu_validation_snapshots — Avena cohort vs official series delta. Fires daily 05:30 UTC.
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"]
}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.
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.
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