Graph
The discovered structure — nodes, scored lagged edges, multi-hop paths, and full edge evidence.
Discovery's lasting output is the goal's relationship graph: the target at the center, connected to the signals and event streams that predict it.
Get the graph
curl "$API_BASE/v1/goals/$GOAL_ID/graph" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID"from predictai import PredictAI
client = PredictAI(token="pa_live_…", workspace_id="ws_…")
data = client.goals.get_goals_by_goal_id_graph(GOAL_ID)
import { PredictAI } from "@predictai/sdk";
const client = new PredictAI({ token: "pa_live_…", workspaceId: "ws_…" });
const data = await client.goals.getGoalsByGoalIdGraph(GOAL_ID);
{
"data": {
"goal_id": "b7e9c2d4-…",
"target_key": "daily_sales",
"interval_seconds": 86400,
"horizon_bins": 14,
"nodes": [
{ "id": "daily_sales", "kind": "goal", "label": "daily_sales", "depth": 0, "related": true },
{ "id": "ad_spend", "kind": "signal", "label": "ad_spend", "depth": 1, "related": true },
{ "id": "supply_disruptions", "kind": "event", "label": "supply_disruptions", "depth": 1, "related": true },
{ "id": "office_temp", "kind": "signal", "label": "office_temp", "depth": null, "related": false }
],
"edges": [
{
"edge_id": "7d3f…",
"source": { "kind": "signal", "key": "ad_spend", "channel": null },
"target_key": "daily_sales",
"depth": 1,
"direction": "positive",
"lag_bins": 3,
"lifecycle": "validated",
"strength": { "corr": 0.62, "lift": 0.18 },
"confidence": { "q_value": 0.012 },
"score": 0.988,
"exploratory": false,
"mu": 0.94,
"impact": 0.61
}
]
}
}The response is the full workspace universe, not just the winners:
every signal and event stream discovery screened appears as a node, with
related: true only on those that cleared validation. That's deliberate —
you see how much was searched and rejected, not just what survived.
Reading an edge
| Field | Meaning |
|---|---|
lag_bins | How many intervals the source leads the target. |
direction | positive or negative effect. |
strength | corr (correlation at the best lag) and lift (incremental walk-forward predictive lift). |
confidence.q_value | The false-discovery-controlled q-value from validation. |
lifecycle | Where the edge stands: validated, revalidated, weakening, broken (live monitoring re-checks edges against fresh data), exploratory (suggestive but below the validation bar), or candidate (screened, never lift-tested). |
score | A single 0–1 strength for filtering, in clean bands: validated edges ≥ 0.9, exploratory 0.55–0.85, screen-only candidates ≤ 0.5. Sorting by score peels off weaker tiers in order. |
mu / impact | The belief axes: confidence in the relationship and how much the forecast rides on it. |
Graph edges are slim — heavy evidence arrays are omitted. Fetch an edge by ID for everything.
Edge detail
curl "$API_BASE/v1/goals/edges/$EDGE_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.goals.get_goals_edges_by_edge_id(EDGE_ID)
import { PredictAI } from "@predictai/sdk";
const client = new PredictAI({ token: "pa_live_…", workspaceId: "ws_…" });
const data = await client.goals.getGoalsEdgesByEdgeId(EDGE_ID);
{
"data": {
"edge": {
"edge_id": "7d3f…",
"source": { "kind": "signal", "key": "ad_spend", "channel": null },
"target_key": "daily_sales",
"lifecycle": "validated",
"lag_bins": 3,
"direction": "positive",
"strength": { "corr": 0.62, "lift": 0.18, "stability": 0.8 },
"confidence": {
"q_value": 0.012,
"folds": [{ "fold": 0, "lift": 0.21 }, "…"]
},
"evidence": {
"shap_shape": [["ad_spend_lag3", 0.42], "…"],
"event_response": null
},
"rolling": {
"baseline_corr": 0.62,
"last_strength": 0.59,
"history": [{ "t": "2026-07-14T…", "strength": 0.59, "ewma": 0.6 }, "…"]
},
"created_at": "2026-07-01T…",
"updated_at": "2026-07-15T…"
}
}
}The full document includes the per-fold validation table
(confidence.folds), the model's attribution shape
(evidence.shap_shape), the measured event-response curve for event-sourced
edges, and the rolling history that live monitoring maintains — the raw
material behind a weakening transition. Unknown IDs return 404 with
"Edge not found". Edge IDs are deterministic, so re-runs update the same
edge instead of duplicating it.
Paths
Validated multi-hop chains — fuel_costs → shipping_rates → daily_sales
— discovered by the expand stage:
curl "$API_BASE/v1/goals/$GOAL_ID/paths" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID"from predictai import PredictAI
client = PredictAI(token="pa_live_…", workspace_id="ws_…")
data = client.goals.get_goals_by_goal_id_paths(GOAL_ID)
import { PredictAI } from "@predictai/sdk";
const client = new PredictAI({ token: "pa_live_…", workspaceId: "ws_…" });
const data = await client.goals.getGoalsByGoalIdPaths(GOAL_ID);
{
"data": {
"paths": [
{
"path_id": "8e4a…",
"hops": [
{ "edge_id": "1b2c…", "source_key": "fuel_costs" },
{ "edge_id": "7d3f…", "source_key": "shipping_rates" }
],
"total_lag_bins": 8,
"confidence": { "min_hop_q": 0.03 },
"lifecycle": "validated",
"narrative": "fuel_costs leads shipping_rates by 5 steps, which leads daily_sales by 3."
}
]
}
}Paths are sorted by strongest evidence first (lowest weakest-hop q-value).
A path whose underlying edge breaks is marked broken rather than deleted.
The list is empty until multi-hop chains have validated for this goal.
Scenarios use these chains to propagate an upstream move through to the target — see Scenarios.

