Skip to content

KPI Equity Impact API

The KPI Equity Impact API tracks the company KPIs that move stocks — subscribers, deliveries, daily actives, cardholders, order volumes — before and after companies report them. For every upcoming print it puts three numbers side by side: what prediction markets currently expect (a live, real-money forecast with daily history and an uncertainty band), what Octagon's model estimates, and — once the company reports — the actual, with the beat/miss surprise scored automatically. One call returns a ranked board of upcoming and settled prints; a second returns the full event bundle for a single KPI, chart-ready. Liquidity is expressed as a tier (high / medium / low) instead of raw volume.

Like the Chat Completions and Responses endpoints, these are direct REST endpoints called relative to the Octagon API base URL:

text
https://api.octagonai.co/v1

Endpoints

MethodPathPurpose
GET/predictions/kpi-eventsThe board — list / rank / search / paginate KPI events
GET/predictions/kpi-events/{event_id}One KPI event — the full event bundle

Conventions

  • KpiValue — every KPI-unit quantity is an object of the form { "value": <number>, "unit": <string>, "formatted": <string> } (e.g., { "value": 28060000, "unit": "customers", "formatted": "28.06M" }). It is null when the underlying number is absent.
  • event_id — the primary key, owned by Octagon (e.g., hood_funded_customers_2026q2). Curated series get a readable id; uncurated events get an opaque evt_<hash> (and kpi_<hash>) — never an upstream ticker in any form.
  • period — the fiscal period the market forecasts, parsed from the event text ("in Q2 2026"Q2 2026; "in 2026"FY 2026). code / label / kind / start / end are populated for ~97% of events; null only for genuine non-period markets (e.g., a one-off corporate announcement). Quarter start / end are calendar quarters — a display window, not a fiscal-calendar mapping.
  • Probabilities are percentage points on a 0–100 scale (model_probability: 90.0 means 90%).
  • newsworthiness — a 0–100 desk sort key composed additively of edge magnitude (up to 45), liquidity tier (up to 25), and report-date proximity (up to 30).
  • Actual trust gate — a captured actual that fails validation against market-derived bounds is withheld: the event stays settled without an actual and never becomes reported. Categorical markets (outcomes are names, not numeric thresholds) never emit a numeric actual.
  • Units — curated series carry curated units; uncurated series infer a unit from the event text (e.g., "card members" → members). unit may be empty or absent only when genuinely unknown.
  • Errors — JSON { "detail": "…" }; 400 bad parameters, 401 authentication, 404 unknown event, 422 validation.

Authentication uses the standard bearer token — see Authentication. Requests without a valid key return 401 {"detail": "Missing or invalid credentials"}.

List KPI events

GET /predictions/kpi-events

The board / reporting calendar.

Query Parameters

ParameterTypeRequiredDescription
statusstringNoall (default) | active | settled | reported.
sortstringNonewsworthiness (default) | volume | edge | abs_edge | edge_pp | report_date | reported_at | close_time.
qstringNoSubstring search over company / KPI name.
periodstringNoFilter by period code (e.g. 2026q2; see Conventions). A comma-separated list matches any of the codes.
limitintegerNoNumber of records to return. Default 50; minimum 1; maximum 200.
cursorstringNoOpaque pagination cursor. Use the next_cursor returned from a previous response to continue.

The desk default is newsworthiness (highest first). report_date sorts by the reporting calendar (soonest expected report first); all other sorts are descending.

status semantics: settled means the event is past close, matching each row's status field — the actual may still be pending. reported means settled and a trusted actual is served (a captured-but-flagged actual — see the trust gate — does not count). "Settled but awaiting actual" is ?status=settled minus ?status=reported.

Response

jsonc
{
  "as_of": "2026-07-07T00:00:00Z",   // when this board snapshot was generated
  "aggregates": { "total_events": 146, "total_markets": 1039, "total_volume": 4874975.01 },  // illustrative — the board grows
  "sort": "newsworthiness",
  "status": "all",
  "data": [ /* rows, see below */ ],
  "next_cursor": null,
  "has_more": false
}

aggregates.total_volume is the summed contract volume across the filtered set; it is not exposed on individual rows.

Row fields (data[])

FieldTypeDescription
idstringOctagon event_id (primary key).
kpi_idstringStable across periods.
company_name, company_tickerstring | nullcompany_ticker is the stock symbol; null for uncurated events.
kpi_namestring | nullHuman-readable KPI name.
period, period_label, period_kindstring | nullMachine + human period + kind (best-effort; see Coverage).
statusstringactive | settled.
expected_report_datestring | nullExpected report date.
market_impliedKpiValueMarket-implied central from the latest stored snapshot — may lag the detail response's live central by up to a day; see market_implied_as_of.
market_implied_as_ofstring | nullCapture time of the row's stored snapshot.
octagon_estimate_valueKpiValueOctagon model central estimate.
edge_absolute_valueKpiValueModel minus market, in KPI units.
actualKpiValue | nullSettled reported figure.
company_guidanceKpiValue | nullCompany-issued guidance for the KPI, when available.
model_probability, market_probability, edge_ppnumber | nullProbability-space signal (percentage points).
signalstring | nullabove_market | in_line | below_market.
near_settledbooleantrue when the market probability is ≥97% or ≤3% — the edge is settlement noise.
newsworthinessinteger0–100 desk sort key.
liquidity_tierstring | nullhigh | medium | low — replaces raw volume.
strike_count, strike_periodinteger / stringMarket structure summary (no ladder detail). strike_count is a count; strike_period is an upstream-formatted period string (e.g. "26Q2") — prefer period / period_label.
actual_sourcestring | nullPresent only when a trusted actual is served. A neutral method label (never a provider name).
reported_atstring | nullWhen the print's exact timestamp is known (market settlement/report time), that; otherwise a clearly-approximate fallback — the expected report date, then close time. Treat as "when the result landed, best available precision"; it can populate on settled rows even without a trusted actual.
close_timestring | nullWhen the underlying markets close.

Get one KPI event

GET /predictions/kpi-events/{event_id}

Query Parameters

ParameterTypeRequiredDescription
include_historybooleanNoInclude the prediction_market_estimate.trend series. Default true.
selected_estimate_idstringNoPick a specific Octagon estimate run.
start_ts, end_ts, period_intervalNoForecast window (day-aligned UTC for period_interval=1440).
percentilesstringNoAccepted for compatibility; the public trend is the p50 series.

The market central is a single basis — the median. The model central is the same statistic on the model side — the median (p50) of Octagon's model ladder — so edge_vs_market compares like with like and its direction always agrees with probability_signal.edge_pp.

Response

jsonc
{
  "event_id": "hood_funded_customers_2026q2",
  "kpi_id": "hood_funded_customers",

  "company": {
    "name": "Robinhood Markets, Inc.",
    "ticker": "HOOD",            // stock symbol, NOT an upstream market id
    "exchange": "NASDAQ",
    "sector": "Financials",
    "industry": "Capital Markets"
  },

  "kpi": {
    "title": "Funded Customers",
    "description": "Funded Customers for Robinhood Markets, Inc.",
    "unit": "customers",
    "type": "accounts",          // subscribers|deliveries|dau|mau|orders|accounts|revenue|margin|units|members|passengers|transactions|headcount|other
    "directionality": "higher_is_better"
  },

  "period": {                    // best-effort; null when non-standard
    "label": "Q2 2026", "code": "2026q2", "kind": "fiscal_quarter",
    "start": "2026-04-01", "end": "2026-06-30"
  },

  "prediction_market_estimate": {          // source-agnostic; no ticker/book/raw volume
    "central": { "value": 28060000, "unit": "customers", "formatted": "28.06M" },
    "as_of": "2026-07-06T00:00:00Z",       // latest trend point
    "trend": [ { "as_of": "2026-06-15T00:00:00Z", "value": 27500000 } ],  // p50 over time
    "liquidity_tier": "high",
    "source": "aggregated_prediction_markets"
  },

  "octagon_model_estimate": {
    "central": { "value": 28700000, "unit": "customers", "formatted": "28.7M" },
    "confidence": 82,
    "as_of": "2026-06-30T20:00:00Z",
    "trend": [ { "as_of": "2026-06-28T00:00:00Z", "value": 28650000 } ],
    "methodology_url": "https://octagonai.co/methodology/kpi"
  },

  "actual": {                              // null until a TRUSTED actual exists (see lifecycle)
    "value": { "value": 28100000, "unit": "customers", "formatted": "28.1M" },
    "reported_at": "2026-08-28T20:00:00Z", // exact when known (settlement/report time); else approximate (expected report date → close time)
    "precision": "exact",                  // exact|rounded|range
    "range": null,                         // market-derived cross-check band when available
    "verified": true,                      // true only for company_report
    "sources": [ { "name": "Company report", "url": "https://investors.robinhood.com/" } ],
    "source_method": "company_report"      // octagon_deep_research|company_report|market_ladder_reconstruction|market_settlement_value
  },

  "analysis": {
    "edge_vs_market": {
      "value": -640000, "unit": "customers", "formatted": "-640K",
      "percent": -0.0223, "direction": "negative",
      "signal": "below_market",            // above_market|in_line|below_market
      "model_as_of": "2026-06-30T20:00:00Z",   // the compared values can be ~a day apart —
      "market_as_of": "2026-07-06T00:00:00Z"   // place the model dot by ITS as_of, never after a newer market point
    },
    "edge_vs_consensus": null,
    "surprise": null,                      // populated once settled and reported
    "model_accuracy": null,
    "near_settled": false,                 // true when the market prob is ≥97% or ≤3%
    "probability_signal": {                // time-attributed: each side carries its own as_of
      "model_probability": 62.0,
      "market_probability": 58.0,
      "edge_pp": 4.0,                      // = model_probability − market_probability
      "badge": "leads",                    // leads (model above market) | rich (market above model) | confirms (aligned)
      "model_as_of": "2026-06-30T20:00:00Z",
      "market_as_of": "2026-07-06T00:00:00Z"
    },
    "newsworthiness": 74
  },

  "editorial": {
    "status": "scheduled",                 // scheduled|imminent|reported|settled (reported = trusted actual served)
    "expected_report_date": "2026-08-28",
    "date_confirmed": false,
    "change_since_last": null,
    "headline": "Market sees Robinhood Markets, Inc. Q2 2026 Funded Customers near 28.06M; Octagon models higher at 28.7M",
    "summary": "Prediction markets imply ~28.06M for Robinhood Markets, Inc.'s Q2 2026 Funded Customers, while Octagon's model points to 28.7M.",
    "chart_url": null,
    "octagon_report_link": "https://octagonai.co/reports/hood_funded_customers_2026q2",
    "permalink": "https://octagonai.co/company-kpi-tracker/hood-funded-customers-2026q2",
    "tags": [],
    "peers": []
  },

  "as_of": "2026-07-07T00:00:00Z"
}

Settled events & actuals — the lifecycle

What happens when a KPI event's period closes, and what consumers should expect:

  1. activesettled on close. The event immediately appears under ?status=settled; actual is still null (awaiting the print).
  2. Actual capture (usually within a day — the settlement pipeline runs daily). The source_method on the actual tells you how it was obtained:
    • market_settlement_value — the settlement venue published a clean numeric settlement figure that agrees with the market-derived range. Served as precision: exact (or rounded for abbreviated figures like 148.5M), with the cross-check range attached. Roughly two-thirds of actuals land this way.
    • octagon_deep_research — no usable settlement figure, so the reported number is researched from primary sources (filings, shareholder letters) with citations in sources, cross-checked against the market range when one exists.
    • company_report — a directly-verified company figure (verified: true); reconciles or overwrites earlier methods when available.
  3. settledreported the moment a trusted actual is served; surprise (actual vs. the pre-report market median) populates on the detail response.

The trust gate: every researched actual is validated against market-derived bounds. A value that fails validation is never served — the event stays settled without an actual rather than showing a suspect number. Categorical markets (outcomes are names, not numeric thresholds — e.g., "which company ships the top model") never emit a numeric actual; they remain settled permanently.

Coverage & known gaps

The board tracks every KPI-tagged prediction market event (146 and growing as of July 2026):

  • Uncurated events return company_ticker: null and a derived company_name; their event_id / kpi_id are opaque evt_<hash> / kpi_<hash>. Units are inferred from the event text (e.g., members, vehicles, USD). Market/model estimates, edge, and signal populate from the market data regardless of curation.
  • period is parsed from the event text (see Conventions) and is clean for ~97% of events; null only for the handful of genuine non-period markets.

Use Cases

  • Build a KPI reporting calendar or "earnings board" ranked by newsworthiness.
  • Surface where Octagon's model disagrees with the market (signal, edge_pp, edge_absolute_value) ahead of a print.
  • Track settled prints and surprises with ?status=reported and the detail response's analysis.surprise.
  • Power editorial workflows directly from the editorial block (headline, summary, permalink).
  • Monitor a single company KPI across periods via the stable kpi_id.

Examples

Today's board, desk-ranked

Python
import requests

url = "https://api.octagonai.co/v1/predictions/kpi-events"
headers = {"Authorization": "Bearer your-octagon-api-key"}
params = {"limit": 20}

response = requests.get(url, headers=headers, params=params)
response.raise_for_status()

for row in response.json()["data"]:
    print(f"{row['newsworthiness']:>3}  {row['company_name']}{row['kpi_name']} ({row['period_label']})")
JavaScript
const params = new URLSearchParams({ limit: "20" });

const response = await fetch(
  `https://api.octagonai.co/v1/predictions/kpi-events?${params}`,
  {
    headers: {
      Authorization: "Bearer your-octagon-api-key",
    },
  }
);

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const { data } = await response.json();
data.forEach((row) => {
  console.log(`${row.newsworthiness}  ${row.company_name} — ${row.kpi_name} (${row.period_label})`);
});
sh
curl -G "https://api.octagonai.co/v1/predictions/kpi-events" \
  -H "Authorization: Bearer <your-octagon-api-key>" \
  --data-urlencode "limit=20"

Settled prints with a captured actual

Python
import requests

url = "https://api.octagonai.co/v1/predictions/kpi-events"
headers = {"Authorization": "Bearer your-octagon-api-key"}
params = {"status": "reported"}

response = requests.get(url, headers=headers, params=params)
response.raise_for_status()

for row in response.json()["data"]:
    actual = row["actual"]["formatted"] if row["actual"] else "—"
    print(f"{row['company_name']} {row['kpi_name']}: actual {actual}")
JavaScript
const params = new URLSearchParams({ status: "reported" });

const response = await fetch(
  `https://api.octagonai.co/v1/predictions/kpi-events?${params}`,
  {
    headers: {
      Authorization: "Bearer your-octagon-api-key",
    },
  }
);

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const { data } = await response.json();
data.forEach((row) => {
  console.log(`${row.company_name} ${row.kpi_name}: actual ${row.actual?.formatted ?? "—"}`);
});
sh
curl -G "https://api.octagonai.co/v1/predictions/kpi-events" \
  -H "Authorization: Bearer <your-octagon-api-key>" \
  --data-urlencode "status=reported"

One event — full event bundle

Python
import requests

event_id = "hood_funded_customers_2026q2"
url = f"https://api.octagonai.co/v1/predictions/kpi-events/{event_id}"
headers = {"Authorization": "Bearer your-octagon-api-key"}

response = requests.get(url, headers=headers)
response.raise_for_status()
event = response.json()

market = event["prediction_market_estimate"]["central"]["formatted"]
model = event["octagon_model_estimate"]["central"]["formatted"]
print(f"Market: {market} | Octagon model: {model}")
print(event["editorial"]["headline"])
JavaScript
const eventId = "hood_funded_customers_2026q2";

const response = await fetch(
  `https://api.octagonai.co/v1/predictions/kpi-events/${eventId}`,
  {
    headers: {
      Authorization: "Bearer your-octagon-api-key",
    },
  }
);

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const event = await response.json();
console.log(
  `Market: ${event.prediction_market_estimate.central.formatted} | Octagon model: ${event.octagon_model_estimate.central.formatted}`
);
console.log(event.editorial.headline);
sh
curl -s "https://api.octagonai.co/v1/predictions/kpi-events/hood_funded_customers_2026q2" \
  -H "Authorization: Bearer <your-octagon-api-key>"

Paginate through the board

Python
import requests

url = "https://api.octagonai.co/v1/predictions/kpi-events"
headers = {"Authorization": "Bearer your-octagon-api-key"}
cursor = None

while True:
    params = {"limit": 50}
    if cursor:
        params["cursor"] = cursor

    response = requests.get(url, headers=headers, params=params)
    response.raise_for_status()
    page = response.json()

    for row in page["data"]:
        print(row["id"], row["status"])

    if not page["has_more"]:
        break
    cursor = page["next_cursor"]
JavaScript
const headers = { Authorization: "Bearer your-octagon-api-key" };
let cursor = null;

while (true) {
  const params = new URLSearchParams({ limit: "50" });
  if (cursor) params.set("cursor", cursor);

  const response = await fetch(
    `https://api.octagonai.co/v1/predictions/kpi-events?${params}`,
    { headers }
  );

  if (!response.ok) throw new Error(`Request failed: ${response.status}`);

  const page = await response.json();

  for (const row of page.data) {
    console.log(row.id, row.status);
  }

  if (!page.has_more) break;
  cursor = page.next_cursor;
}
sh
# First page
curl -G "https://api.octagonai.co/v1/predictions/kpi-events" \
  -H "Authorization: Bearer <your-octagon-api-key>" \
  --data-urlencode "limit=50"

# Next page (use next_cursor from previous response)
curl -G "https://api.octagonai.co/v1/predictions/kpi-events" \
  -H "Authorization: Bearer <your-octagon-api-key>" \
  --data-urlencode "limit=50" \
  --data-urlencode "cursor=<next_cursor_value>"

Notes

  • All probability values (model_probability, market_probability, edge_pp) are percentage points on a 0–100 scale.
  • octagon_model_estimate.central — and everything derived from it (edge_vs_market, the list row's octagon_estimate_value / edge_absolute_value) — is the median (p50) of Octagon's model ladder, the same statistic as the market central. If you cached edge values captured before July 2026 (when the model central was a weighted mean), expect a small one-time shift; edge direction now never contradicts probability_signal.edge_pp.
  • Never parse formatted strings for computation — use the value field of each KpiValue object.
  • An event under ?status=settled may not yet have an actual; use ?status=reported when you need trusted actuals only.
  • near_settled: true means the market is effectively decided (probability ≥97% or ≤3%) — treat any remaining edge as settlement noise, not signal.