When an alert fires
The pipeline runs continuously. An alert is emitted when all four of the following hold:- A keyword’s per-window volume crosses 5σ above its 14-day rolling baseline on a topic or watchlist.
- The spike is spread across multiple domains and languages — single-domain bursts are filtered as noise.
- An LLM gate classifies the spike as a real, describable event (not a recurring meme, scheduled show, or platform artifact).
- The signal hasn’t already been emitted in the current deduplication window.
cyber or disinfo may produce zero alerts in a 24-hour window. That is by design: alerts are intentionally rare. Use /v1/topics/{t}/volume for raw activity instead.
The default
hours=168 (7 days) on /v1/topics/{t}/alerts exists for exactly this reason — it gives quiet topics a useful window without forcing every caller to remember the parameter. Tune down to hours=24 for high-volume topics like global.The alert envelope
Same JSON shape on every endpoint that returns alerts:/v1/topics/{t}/alerts, /v1/watchlists/{id}/alerts, and webhook deliveries.
Field guide
Identity
Signal type
signal_type is the discriminator. Today’s stable values:
Match on
signal_type to route alerts to the right consumer (SOC vs. brand vs. newsroom).
Severity
The math, in plain terms:
deviation_sigma = (current_value − baseline_value) / σ_14d, and the alert is only emitted when deviation_sigma ≥ 5.
Spread
The virality footprint. Single-domain spikes — even loud ones — are filtered out. An alert withdomain_count: 14, language_count: 8 is a story crossing platforms and language communities, not one viral tweet.
A common disinfo filter is
domain_count >= 5 AND language_count >= 3 (see Use cases recipe 4).
Confidence and LLM validation
Evidence
/v1/topics/{t}/posts (See tier and above).
IOCs
The IOC extractor runs on every alert with text content, includingvolume_spike types. Always present, often empty.
if "cves" in iocs checks.
Matched cluster
If the spike falls inside an existing conversation cluster, the alert links to it:GET /v1/topics/{t}/clusters/{cluster_id} (See tier) for the full cluster: top entities, top domains, time-series, full evidence post list. matched_cluster is null when the spike doesn’t fit any active cluster — usually meaning it’s a brand-new story.
Endpoints that return alerts
Query parameters on the polling endpoints:
Request a
hours value above your tier cap and the response is silently clamped — the JSON includes the effective window in query_window.
Polling pattern (Watch and See)
Below 5-second freshness, switch to webhooks. See Rate limits.
Webhook delivery (See and Know)
Verify the signature server-side before trusting the payload:
webhook_dead. Re-enable from PATCH /v1/subscriptions/{id} once your endpoint is healthy. See Errors → Subscription / webhook errors.
Filtering patterns
Newsroom — only loud, validated, multi-platform stories:Idempotency and dedup
- Across polls:
alert_idis stable. Keep asetof seen IDs (or a RedisSADDwith TTL) and skip duplicates. - Across webhook retries: Use
X-Exorde-Delivery-Idas the dedup key — samealert_idmay be redelivered if your endpoint 5xx’d. - Across rotations: Alerts persist through key rotation. The
alert_iddoesn’t reset.
Operational guidance
- Don’t trust
descriptionfor routing — it’s prose. Route onsignal_type,topic,severity.deviation_sigma,iocspresence. - Always pass
llm_validated: truein production filters unless you’re explicitly hunting noise. - Persist
alert_idfor at least 7 days — the maximum dedup window. Shorter and you’ll re-page the on-call. - Show the
trace_id(response headerX-Exorde-Trace-Id) on any UI that surfaces an alert. It’s the support handshake. matched_cluster: nullis a feature, not missing data — it tells you “this is brand new, not part of an ongoing story.”- Alerts count against RPM but not monthly quota when delivered via webhook. Push is the right architecture above 5-second cadence.
What’s not an alert
For clarity:
Alerts are the push-shaped, machine-routable view of the data. Everything else is pull-shaped and human-shaped.
Last reviewed: 2026-05-19. API version 1.2.8.