Trackers API

Observational market trackers in one standardized envelope: institution rankings, hedge fund returns, Reddit positioning, and sentiment leaderboards.

Free (API key required); some trackers gate richer data to PRO2 endpoints

Overview

Trackers are observational data products. Each tracker has its own data source and refresh cadence; underneath, they all return the same standardized envelope, so a builder writes one renderer per viewType and gets every current and future SentiSense tracker for free.

Currently live trackers:

Tracker id viewType accessTier What it shows
institution-concentration table free 13F filers ranked by top-10 concentration (the most conviction-driven portfolios)
institution-aum table free Largest 13F filers by total disclosed long-equity AUM
hedge-fund-reported-returns table pro Net-of-fee annual returns large hedge funds publish, with a citation per number
reddit-picks table free Tradeable stocks finance-Reddit turned bullish on, scored vs SPY
media-darlings table free Stocks ranked by how bullish or bearish the curated financial press is on them
sentiment-leaderboard table free Most bullish and most bearish stocks by pure sentiment polarity (tone, not the SentiSense Score), with a minimum-mention confidence floor and a driving story per row
sentiment-movers table free Biggest 7-day shifts in tone, improving and deteriorating, with a minimum-mention confidence floor
trending-products table free Products and services ranked by mention volume and week-over-week growth
market-heatmap heatmap pro The whole board in one call: every stock in an index sized by market cap and coloured by the day's move, with sectors, sector Market Mood rollups, and sentiment, Score and options overlays per tile

The two sentiment trackers rank individual stocks by tone. For the sector-level and whole-universe cuts of that same tone metric, use /api/v1/sentiment/sectors (the 11 GICS sectors versus the market's own tone) and /api/v1/sentiment/breadth (the bullish/neutral/bearish share of the roughly 1,000 covered stocks) in the Market Mood API.

More tracker types ship over time; the discovery endpoint is the source of truth for what's live.

Access: an API key is required on every tracker endpoint. Each tracker declares an accessTier of "free" or "pro" in the discovery listing. A free tracker returns the full snapshot to everyone. A pro tracker returns a preview to FREE callers (isPreview: true, previewReason: "PRO_REQUIRED", with totalCount carrying the full row count) and the full snapshot to PRO, in one of two shapes:

  • Fewer rows. A ranked leaderboard returns its top N rows; hedge-fund-reported-returns works this way.
  • Fewer columns. A tracker whose value is that the dataset is complete returns every row and withholds the proprietary columns instead, naming them in data.meta.previewWithheld. market-heatmap works this way: every tile on every tier, with the sentiment and options overlays reserved for PRO.

Methodology: every tracker carries a methodologyAnchor field in the discovery listing that points at its section on sentisense.ai/methodology (e.g. #institution-rankings for the concentration and AUM rankings). An empty methodologyAnchor means the tracker has no dedicated section yet; link the page itself.


GET /api/v1/trackers

Discovery endpoint. Returns every publicly-visible tracker the platform knows about, with the metadata you need to render a hub or build a navigation menu.

Response

{
  "trackers": [
    {
      "trackerId": "institution-concentration",
      "displayName": "Most concentrated institutions",
      "category": "institutional",
      "description": "13F filers ranked by the share of their disclosed book held in their top 10 positions.",
      "viewType": "table",
      "accessTier": "free",
      "methodologyAnchor": "#institution-rankings",
      "refreshIntervalSeconds": 86400,
      "canonicalUrl": "/api/v1/trackers/institution-concentration"
    }
  ]
}
Field Type Notes
trackerId string Slug for the detail endpoint
displayName string Hub-card title; also surfaced inside the snapshot envelope
category string Coarse grouping for hub filtering ("institutional", etc.)
description string One sentence; suitable for a hub card subtitle
viewType string Renderer hint, "table" or "heatmap". New viewType values are documented here when a tracker using them ships.
accessTier string "free" or "pro". pro trackers return a preview to FREE callers, either fewer rows or fewer columns (see Access above); free trackers return the full snapshot to everyone.
methodologyAnchor string Fragment on /methodology for the tracker (link out without per-tracker logic)
refreshIntervalSeconds integer Expected snapshot refresh cadence in seconds
canonicalUrl string Detail endpoint path

GET /api/v1/trackers/{trackerId}

Standardized snapshot envelope for one tracker.

Path parameter

Parameter Description
trackerId Slug from the discovery listing, e.g. institution-concentration. Unknown ids return 404 unknown_tracker.

Query parameters (optional, provider-specific)

Parameter Description
scope Which universe a scoped tracker should return. market-heatmap accepts sp500 (default), nasdaq100 or popular; any other value returns 400 invalid_scope listing the valid ones. Ignored by trackers that are not scoped.
category For the institution-ranking trackers (concentration, aum): overrides the default filer-category filter. Pass ?category= (empty) to open the universe across all categories instead of the default hedge-fund filter.

Response shape (the envelope)

Every tracker returns the same wire shape:

{
  "isPreview": false,
  "previewReason": null,
  "data": {
    "trackerId": "institution-concentration",
    "schemaVersion": "1.0",
    "displayName": "Most concentrated institutions",
    "description": "13F filers ranked by the share of their disclosed book held in their top 10 positions.",
    "viewType": "table",
    "asOf": "2026Q1",
    "generatedBy": "InstitutionRankingsService",
    "headline": [
      { "label": "Institutions ranked", "value": 28, "unit": "filers" }
    ],
    "rows": [
      {
        "rank": 1,
        "rowId": "0001067983",
        "name": "Berkshire Hathaway",
        "category": "HEDGE_FUND",
        "url": "/institutions/Berkshire-Hathaway",
        "metrics": [
          { "label": "Top-10 concentration", "value": 91.2, "unit": "percent" },
          { "label": "Disclosed AUM", "value": 264000000000, "unit": "usd" },
          { "label": "Holdings",      "value": 40,  "unit": "count" }
        ]
      }
    ]
  }
}
Envelope field Type Notes
isPreview boolean true only when a pro-tier tracker is served to a non-PRO caller. Something is withheld: either the rows past the free limit, or the proprietary columns named in data.meta.previewWithheld. false for free trackers and for PRO callers.
previewReason "PRO_REQUIRED" or null Only set when isPreview is true.
totalCount integer The full row count, before any truncation. Present on every response, so you never have to know your tier to size a board. On a column-gated tracker it therefore equals the number of rows you were served. null on a tracker whose viewType carries no rows.
upgrade object Present only when isPreview is true. Carries plan, message, price, url and relay: surface message and url to your user in one line, then continue with the preview data.
data object The standardized TrackerSnapshot (below).
Snapshot field Type Notes
trackerId string Echoes the request path.
schemaVersion string "1.0" today. Bumped when the envelope shape changes incompatibly.
displayName string Same as the discovery listing. Surfaced here so renderers don't need to cross-reference.
description string Same as the discovery listing.
viewType string The renderer hint, "table" or "heatmap"; dispatch on this to pick a renderer.
asOf string Free-form 'data as of' label, typically a quarter ("2026Q1") or ISO date for daily trackers.
headline array Top-of-page stat tiles. Each item is { label, value, unit?, asOf?, methodologyNote?, trend? }.
rows array One row per entity. Each row carries its per-cell metrics[] (label + value + unit) so a generic renderer can derive column headers from rows[0].metrics. A wide dataset tracker such as market-heatmap also writes its columns as named fields directly on the row (rows[].marketCap), which is cheaper to read and far smaller on the wire than repeating a label and unit on every one of 500 rows.

Reading the table-row metrics

Each rows[].metrics[] entry is a { label, value, unit } tuple. Column headers come from the labels on the first row; the order is stable across rows in a single response.

For the institution-ranking trackers, the metric set per row is:

Tracker Metrics (in order)
institution-concentration Top-10 concentration, Disclosed AUM, Holdings
institution-aum Disclosed AUM, Holdings

unit is one of "percent", "usd", "count"; a renderer can use it to format value without per-tracker logic.

The market-heatmap tracker

One call returns a whole index as tiles, which is what makes it renderable as a self-contained
treemap with no follow-up requests. GET /api/v1/trackers/market-heatmap?scope=sp500.

Every caller gets every tile. Rows sort by market cap descending, and neither tier is
row-limited: a FREE key, a PRO key and the web app all receive the whole index, the full
headline, and the full meta including the eleven sector rollups. This tracker gates columns
instead. A non-PRO response carries isPreview: true, previewReason: "PRO_REQUIRED" and
meta.previewWithheld, and omits the proprietary overlay fields from every row:

Withheld layer Fields removed for a non-PRO caller
sentiment sentiment7d, sentimentChange7d, sentisenseScore, mentionsZ
options optionsInterestScore

meta.previewWithheld is a list of those layer names, and it lists only layers this snapshot
actually has: if the options layer did not run today it is absent from meta.layers and absent
from previewWithheld too, because a PRO caller would see nothing for it either. The field is
absent entirely on a PRO response. Everything else is open on every tier: ticker, name, sector,
industry, market cap, the delayed quote, the sector rollups and the Market Mood headline.

A withheld field is simply not present on the row, exactly like a ticker with no reading. So read
meta.previewWithheld, not an absent field, when deciding whether to show a locked control: an
absent sentisenseScore means "no reading for this ticker" on a PRO response and "upgrade" on a
FREE one.

Each row carries these named fields alongside the standard rank, rowId, name (company
name), category (the sector) and url:

Field Notes
ticker The tile's symbol
sector Canonical GICS-11 name, or Unclassified. Never a provider variant, so the eleven sectors always bucket cleanly
industry Vendor industry, finer than the sector
marketCap USD. The tile's size
price, previousClose, changePercent, volume Delayed quote. changePercent is the tile's colour
priceAsOf When the quote is from. Absent outside regular hours, where the vendor dates nothing
sentiment7d, sentimentChange7d Seven-day mean tone in [-1, 1], and its change over a week
sentisenseScore Today's SentiSense Score
mentionsZ Today's mention volume in standard deviations of its 30-day baseline
optionsInterestScore Options interest, for tickers with options coverage

Within the layers you are served, a field that is absent has no reading for that tile. It is
never a zero, and a zero is never a missing value.
A measured 0.0 is always written, including a genuinely flat changePercent
and a genuinely neutral Score. Whether an overlay ran at all is answered by meta.layers, not by
the rows: a layer that failed or is not shipped is absent from that object entirely, so
layers.sentiment present with sentiment7d missing on a row means "we looked and there is
nothing for this ticker".

meta carries the board-level picture: scope, universeSize, tileCount, missingPrice[]
(tickers dropped for having no quote, listed rather than silently omitted), breadthUp,
breadthDown, capWeightedChangePct, equalWeightedChangePct, marketMoodScore,
marketMoodPhase, previewWithheld (non-PRO responses only, see above), the layers stamps
above, and sectors[] with one rollup per sector
(sector, marketMoodScore, marketMoodPhase, marketMoodWeeklyChange, count,
capWeightedChangePct, equalWeightedChangePct, capUsd, up, down). Sectors with no Market
Mood reading carry nulls there, not zeros.

Snapshots are rewritten every 15 minutes during the US regular session and hourly outside it.
Prices are delayed by about 15 minutes (meta.layers.prices.delayMinutes), so do not present the
board as real time. Before the first write of a scope the answer is 404 no_snapshot, which is a
warm-up state rather than an outage: retry in 15 minutes.

Error responses

Status Body Cause
404 unknown_tracker { "error": "unknown_tracker", "message": "No registered tracker with id '...'" } Slug not in the registry
404 no_snapshot { "error": "no_snapshot", "message": "Tracker '...' has no snapshot available" } Tracker registered but hasn't produced data yet
400 invalid_scope { "error": "invalid_scope", "message": "Unknown scope '...'. Valid values: ..." } A scope value the tracker does not serve. It is never silently coerced to the default.
503 tracker_unavailable { "error": "tracker_unavailable", "message": "Tracker '...' is temporarily unavailable" } The provider threw; retry with backoff

SDK usage

Python:

from sentisense import SentiSenseClient

client = SentiSenseClient(api_key="...")

for tracker in client.list_trackers().trackers:
    print(tracker.trackerId, tracker.displayName)

snapshot = client.get_tracker("institution-concentration")
print(snapshot.data.displayName, snapshot.data.asOf)
for row in snapshot.data.rows[:5]:
    print(row.rank, row.name, row.metrics[0].value)  # first metric = top-10 concentration

Node:

import { SentiSense } from "sentisense";

const client = new SentiSense({ apiKey: "..." });

const { trackers } = await client.trackers.list();
for (const t of trackers) console.log(t.trackerId, t.displayName);

const snap = await client.trackers.get("institution-concentration");
console.log(snap.data.displayName, snap.data.asOf);
for (const row of (snap.data.rows ?? []).slice(0, 5)) {
  console.log(row.rank, row.name, row.metrics[0].value);
}

Why this shape

Trackers are observational dashboards (see the methodology page for how each one is built). The standardized envelope plus the viewType taxonomy means:

  • One renderer per viewType in your code, and you cover every tracker we ship.
  • Adding a new tracker is additive: no breaking changes to the contract, no parallel endpoints, no per-tracker shape work for consumers.
  • Discovery (GET /api/v1/trackers) returns enough metadata to render a navigation menu without hitting any tracker's detail endpoint.

This is the same convention used by CDC NNDSS (US disease surveillance), FRED (economic indicators), World Bank, OECD, and EIA dashboards.

Try It

Test endpoints directly from your browser. Paste your API key once: it's saved locally and shared across all widgets. Get a free key

GET/api/v1/trackers

List every publicly-visible tracker

Try It
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \ "https://app.sentisense.ai/api/v1/trackers"
Enter your API key to send requests

GET/api/v1/trackers/{trackerId}

Standardized snapshot envelope for one tracker

Try It
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \ "https://app.sentisense.ai/api/v1/trackers/sentiment-leaderboard"
Enter your API key to send requests