Skip to main content
An alert is a structured signal that conversation on a topic just spiked outside its normal pattern, validated by an LLM gate, with enough metadata to act on it without a human having to read the underlying posts. Alerts are one of the three pillars of the Intel API — alongside trending and narrative — and the only one designed for push-style consumption: poll on Watch, subscribe to a webhook on See and Know.

When an alert fires

The pipeline runs continuously. An alert is emitted when all four of the following hold:
  1. A keyword’s per-window volume crosses 5σ above its 14-day rolling baseline on a topic or watchlist.
  2. The spike is spread across multiple domains and languages — single-domain bursts are filtered as noise.
  3. An LLM gate classifies the spike as a real, describable event (not a recurring meme, scheduled show, or platform artifact).
  4. The signal hasn’t already been emitted in the current deduplication window.
Low-volume topics like 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 with domain_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

3–5 representative posts. Truncated to ~160 chars; for full content fetch /v1/topics/{t}/posts (See tier and above).

IOCs

The IOC extractor runs on every alert with text content, including volume_spike types. Always present, often empty.
The shape is always the full schema, even when empty. Code can iterate keys safely without if "cves" in iocs checks.

Matched cluster

If the spike falls inside an existing conversation cluster, the alert links to it:
Drill down with 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)

Cadence guidance: Below 5-second freshness, switch to webhooks. See Rate limits.

Webhook delivery (See and Know)

Each delivery POSTs the alert envelope (above) to your URL, with these headers: Verify the signature server-side before trusting the payload:
Webhooks that return non-2xx N times in a row auto-pause and emit 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:
Threat-intel — only alerts carrying actionable IOCs:
Disinfo — coordinated multi-language pushes only:

Idempotency and dedup

  • Across polls: alert_id is stable. Keep a set of seen IDs (or a Redis SADD with TTL) and skip duplicates.
  • Across webhook retries: Use X-Exorde-Delivery-Id as the dedup key — same alert_id may be redelivered if your endpoint 5xx’d.
  • Across rotations: Alerts persist through key rotation. The alert_id doesn’t reset.

Operational guidance

  • Don’t trust description for routing — it’s prose. Route on signal_type, topic, severity.deviation_sigma, iocs presence.
  • Always pass llm_validated: true in production filters unless you’re explicitly hunting noise.
  • Persist alert_id for at least 7 days — the maximum dedup window. Shorter and you’ll re-page the on-call.
  • Show the trace_id (response header X-Exorde-Trace-Id) on any UI that surfaces an alert. It’s the support handshake.
  • matched_cluster: null is 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.