Predict.aiDocs
Signals

Events

Discrete, timestamped occurrences — recorded under named streams, automatically scored, and wired straight into forecasts as first-class inputs.

Signals are continuous — a value every tick. Events are discrete: things that happen. A product launch, an outage, a news headline, a policy change. Each event is a timestamped piece of text recorded under a named stream (its key), and streams work like signals do: one name, many occurrences, listed and charted together.

What makes events useful for forecasting is scoring. Every recorded event is scored automatically in the context of your workspace — its sentiment, how significant it is, how relevant to your domain, and its expected directional impact — so a stream of raw text becomes a numeric series a chart can render and an analysis can reason about.

Events are not annotations. They are forecast inputs: discovery tests every stream against your goals, validated streams feed models continuously, one important event can flip a live forecast into shock mode within seconds, and a known-future event bends the forecast before it happens.

How an event flows

  1. You record an event (or a webhook delivers one, or an ingestion mapping flags a column is_event).
  2. It's stored immediately with "status": "pending" — visible right away.
  3. Scoring runs in the background and fills in scores; the status becomes scored. Scoring is deterministic, so re-submitting the same event re-scores to the same row rather than duplicating it.

Two clocks matter, and they're stored separately:

FieldMeaning
occurred_atWhen the event actually happened (or will happen) — this is where it plots
timestampWhen it was recorded — when the platform learned about it

The two clocks make three arrival shapes possible, and the platform reacts differently to each:

  • Fresh — recorded within ~2 forecast cadences of occurring. The stream's model features refresh immediately, so the very next forecast sees the event; if it's important enough it can trigger the shock protocol.
  • Stale — recorded long after it occurred (a backfill). The platform performs a history revision: event features are rebuilt from the occurrence onward, affected goals are re-checked, and you get a history_revised notification. Old news never fires a shock.
  • Scheduled — occurred_at in the future (an earnings date, a planned promo). See scheduled events.

Backfilling history is therefore safe: record last month's incident with occurred_at set to when it happened, and it lands in the right place on the time axis — and the models that already trained past that date are told their history moved.

Record an event

curl -X POST "$API_BASE/v1/event/record" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-Id: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "press_mentions",
    "text": "Featured in the Sunday retail roundup — strong coverage of the summer line.",
    "occurred_at": "2026-07-12T09:00:00Z"
  }'
{
  "data": {
    "event_id": "9f2c41d0-…",
    "stream": "press_mentions",
    "status": "pending",
    "scheduled": false
  }
}

scheduled is true when occurred_at is in the future — the event was recorded as a known-future occurrence.

Request body

FieldMeaning
key requiredThe stream to record under. Created on first use.
text requiredThe event's content — what happened. This is what gets scored.
occurred_at optionalWhen it happened: epoch seconds, epoch milliseconds, or ISO 8601. Defaults to now. A future time (up to 400 days ahead) records a scheduled event.
name optionalA short display label. Defaults to the first 200 chars of text.
source optionalProvenance label ("who reported this"). Defaults to the stream key.
origin optionalOne of manual, api (default), ingestion.
value optionalA numeric payload (discount %, magnitude, headcount…). When the text carries no interpretable scale — or the event is purely numeric — value becomes the event's severity in the model features, normalized against the stream's own history.
data_type optionalContent type hint. Defaults to "text".
raw optionalThe original payload, kept for reference.

Errors

StatusWhyExample message
400No stream"Event stream ('key') is required"
400No content"Event 'text' is required"
400Too far out"Scheduled events can be at most 400 days in the future"

Fetch one event

Poll this after recording to see the scores land:

curl "$API_BASE/v1/event/$EVENT_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-Id: $WORKSPACE_ID"
{
  "data": {
    "event_id": "9f2c41d0-…",
    "key": "press_mentions",
    "name": "Featured in the Sunday retail roundup — strong coverage of the s…",
    "text": "Featured in the Sunday retail roundup — strong coverage of the summer line.",
    "source": "press_mentions",
    "origin": "api",
    "data_type": "text",
    "value": null,
    "occurred_at": 1783587600000,
    "timestamp": 1783842900000,
    "status": "scored",
    "scores": {
      "sentiment": "positive",
      "polarity": 0.6,
      "importance": 0.45,
      "relevance": 0.8,
      "impact": 0.35,
      "rank": 57
    },
    …
  }
}

The score fields:

FieldRangeMeaning
sentimentnegative / neutral / positiveOverall tone
polarity−1 … 1Signed tone strength
importance0 … 1How significant the event is in general
relevance0 … 1How relevant it is to this workspace's domain
impact−1 … 1Expected signed effect on your targets
rank0 … 100Composite headline score (importance + relevance + magnitude of impact)

Purely numeric content (a number column flagged as an event) has nothing to interpret, so it scores neutral (rank: 0) instantly — its value carries the weight instead, normalized against the stream's own history. An unknown event_id returns 404 ("Event not found").

How events move forecasts

Recording is half the story. Behind the scenes every stream is a candidate forecast driver:

  1. Featurization. Each stream is converted into continuous model features — decay kernels at several half-lives, counts, signed influence, time-since-last-event — on every goal's time grid. Severity comes from the LLM scores, or from value when the text carries no scale.
  2. Discovery. The discovery engine tests those features against each goal and, when a stream demonstrably moves a target, records a validated edge — including a fitted response curve (how the target typically reacts, step by step) and its half-life. Edges show up in drivers and in the graph, and the stream list summarizes them per stream.
  3. Live reaction. A fresh, high-importance event on an edged stream triggers the shock protocol: the goal flips to shock_state: "shock", serving blends the champion with a zero-shot generalist and the stream's measured response curve, and uncertainty bands widen until the response fades. The importance bar is outcome-calibrated per (goal, stream): a stream whose "important" events reliably preceded real moves earns a lower bar; one that cries wolf earns a higher one.
  4. Learning. Every shock-mode forecast is logged and later graded against what actually happened. Once enough graded episodes exist, the platform refits the shock blend weights per goal — the response to the next shock is shaped by how well the last ones were handled. Event alerts, scenario injections, and the timing sweep all read the same measured curves.

None of this needs configuration — record events on streams with honest timestamps, and discovery does the rest. Alert on the event flow itself with the event-native alert rules.

Scheduled (known-future) events

A future occurred_at records an event you know is coming — an earnings date, a planned promo, a maintenance window:

curl -X POST "$API_BASE/v1/event/record" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-Id: $WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "promotions",
    "text": "Summer sale goes live — 20% off the whole catalog.",
    "occurred_at": "2026-09-15T08:00:00Z",
    "value": 20
  }'

A scheduled event behaves differently from a past one, on purpose:

  • It's scored and stored immediately ("scheduled": true), and plots on charts as an upcoming marker.
  • When its stream holds a validated edge to a goal and the occurrence falls inside the forecast horizon, serving applies the stream's measured response curve at the scheduled offset — the forecast bends for the promo before the promo runs. The applied events ride along in the forecast's metadata, so the bend is always explained, never silent.
  • Its full reactions — feature refresh, shock check (at maximal freshness), event alerts — fire when the scheduled time arrives, not at recording time. Until then it cannot shock anything.
  • Per-goal opt-out: set options.scheduled_events: false on the goal to serve unbent forecasts.

List what's coming with GET /v1/event/upcoming.

List a stream's events

Page through one stream's history, newest occurrence first — the stream detail view:

curl "$API_BASE/v1/event/streams/press_mentions/events?limit=50" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-Id: $WORKSPACE_ID"
{
  "data": {
    "stream": "press_mentions",
    "events": [
      {
        "event_id": "9f2c41d0-…",
        "name": "Featured in the Sunday retail roundup — …",
        "occurred_at": 1783587600000,
        "timestamp": 1783842900000,
        "scheduled": false,
        "status": "scored",
        "value": null,
        "scores": { "importance": 0.45, "polarity": 0.6, "sentiment": "positive", "rank": 57 }
      }
    ],
    "has_more": true
  }
}
Query paramMeaning
limitPage size. Default 100, max 500.
beforeEpoch-ms cursor: only events that occurred strictly before this. Take the oldest occurred_at on the page and pass it back to fetch the next one.

Upcoming (scheduled) events

Known-future events across the workspace, soonest first:

curl "$API_BASE/v1/event/upcoming?within_hours=168" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-Id: $WORKSPACE_ID"
{
  "data": {
    "events": [
      {
        "event_id": "c81d92f0-…",
        "key": "promotions",
        "name": "Summer sale goes live — 20% off the whole catalog.",
        "occurred_at": 1789459200000,
        "scheduled": true,
        "value": 20,
        "scores": { "importance": 0.7, "polarity": 0.8, "…": "…" }
      }
    ]
  }
}
Query paramMeaning
within_hoursOnly events within this window from now. Default 720 (30 days).
streamsComma-separated stream keys to filter to.

List event streams

One row per stream, with a summary and a time-ordered points series (one point per event, ordered by occurred_at) ready to render as a sparkline:

curl "$API_BASE/v1/event/streams" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-Id: $WORKSPACE_ID"
{
  "data": {
    "streams": [
      {
        "key": "press_mentions",
        "count": 14,
        "latest_occurred_at": 1783587600000,
        "latest_timestamp": 1783842900000,
        "latest_text": "Featured in the Sunday retail roundup — strong coverage of the summer line.",
        "latest_sentiment": "positive",
        "max_rank": 82,
        "scheduled_count": 1,
        "next_scheduled_at": 1789459200000,
        "edges": {
          "goals_affected": 2,
          "max_lift": 0.21,
          "half_life_s": 21600,
          "weakening": 0
        },
        "points": [
          { "occurred_at": 1781000000000, "timestamp": 1781003600000, "rank": 41, "polarity": -0.2, "sentiment": "negative", "impact": -0.15, "importance": 0.4, "scheduled": false },
          …
        ]
      }
    ]
  }
}

The summary fields beyond the basics:

FieldMeaning
scheduled_count / next_scheduled_atPending known-future occurrences, and when the next one lands.
edgesHow the prediction engine sees the stream: how many goals it demonstrably moves (goals_affected), the strongest measured lift, the fitted response half-life in seconds, and how many of those edges are currently weakening. null until discovery validates a first edge.

Event streams also appear directly in GET /v1/signal alongside your signals — one row per stream, tagged "type": "event", with the same edges summary — so one call shows the whole workspace.

Delete a stream

Deletes every event recorded under the stream:

curl -X DELETE "$API_BASE/v1/event/streams/press_mentions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Workspace-Id: $WORKSPACE_ID"
{ "data": { "stream": "press_mentions", "deleted": 14 } }

Event streams shared into your workspace by subscription are read-only — deleting one returns 403 ("Subscribed … event streams are read-only.").

Events pair naturally with the event-style engineered features on segments: record what happened as events for context and scoring, and let release_flag / release_surprise capture when your data moved — the two views complement each other.

On this page