Events
Discrete, timestamped occurrences — recorded under named streams, automatically scored, and shown alongside your signals.
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.
How an event flows
- You record an event (or a webhook
delivers one, or an ingestion mapping
flags a column
is_event). - It's stored immediately with
"status": "pending"— visible right away. - Scoring runs in the background and fills in
scores; the status becomesscored. 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:
| Field | Meaning |
|---|---|
occurred_at | When the event actually happened (primary — this is where it plots) |
timestamp | When it was recorded (always ≥ occurred_at) |
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.
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"
}'from predictai import PredictAI
client = PredictAI(token="pa_live_…", workspace_id="ws_…")
data = client.signals.post_event_record(json={
"key": "press_mentions",
"text": "Featured in the Sunday retail roundup — strong coverage of the summer line.",
"occurred_at": "2026-07-12T09:00:00Z",
})
import { PredictAI } from "@predictai/sdk";
const client = new PredictAI({ token: "pa_live_…", workspaceId: "ws_…" });
const data = await client.signals.postEventRecord({
json: {
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"
}
}Request body
| Field | Meaning |
|---|---|
key required | The stream to record under. Created on first use. |
text required | The event's content — what happened. This is what gets scored. |
occurred_at optional | When it happened: epoch seconds, epoch milliseconds, or ISO 8601. Defaults to now. |
name optional | A short display label. Defaults to the first 200 chars of text. |
source optional | Provenance label ("who reported this"). Defaults to the stream key. |
origin optional | One of manual, api (default), ingestion. |
value optional | An optional numeric value attached to the event. |
data_type optional | Content type hint. Defaults to "text". |
raw optional | The original payload, kept for reference. |
Errors
| Status | Why | Example message |
|---|---|---|
400 | No stream | "Event stream ('key') is required" |
400 | No content | "Event 'text' is required" |
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"from predictai import PredictAI
client = PredictAI(token="pa_live_…", workspace_id="ws_…")
data = client.signals.get_event_by_event_id(EVENT_ID)
import { PredictAI } from "@predictai/sdk";
const client = new PredictAI({ token: "pa_live_…", workspaceId: "ws_…" });
const data = await client.signals.getEventByEventId(EVENT_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:
| Field | Range | Meaning |
|---|---|---|
sentiment | negative / neutral / positive | Overall tone |
polarity | −1 … 1 | Signed tone strength |
importance | 0 … 1 | How significant the event is in general |
relevance | 0 … 1 | How relevant it is to this workspace's domain |
impact | −1 … 1 | Expected signed effect on your targets |
rank | 0 … 100 | Composite 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. An unknown
event_id returns 404 ("Event not found").
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"from predictai import PredictAI
client = PredictAI(token="pa_live_…", workspace_id="ws_…")
data = client.signals.get_event_streams()
import { PredictAI } from "@predictai/sdk";
const client = new PredictAI({ token: "pa_live_…", workspaceId: "ws_…" });
const data = await client.signals.getEventStreams();
{
"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,
"points": [
{ "occurred_at": 1781000000000, "timestamp": 1781003600000, "rank": 41, "polarity": -0.2, "sentiment": "negative", "impact": -0.15 },
…
]
}
]
}
}Event streams also appear directly in
GET /v1/signal
alongside your signals — one row per stream, tagged "type": "event" —
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"from predictai import PredictAI
client = PredictAI(token="pa_live_…", workspace_id="ws_…")
data = client.signals.delete_event_streams_by_stream("press_mentions")
import { PredictAI } from "@predictai/sdk";
const client = new PredictAI({ token: "pa_live_…", workspaceId: "ws_…" });
const data = await client.signals.deleteEventStreamsByStream("press_mentions");
{ "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.

