Trackers API
Observational market trackers in one standardized envelope: institution rankings, hedge fund returns, Reddit positioning, and sentiment leaderboards.
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, with a driving story per row |
sentiment-movers |
table | free | Biggest 7-day sentiment shifts (improving and deteriorating) |
trending-products |
table | free | Products and services ranked by mention volume and week-over-week growth |
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 pro tracker returns a truncated preview to FREE callers (isPreview: true, previewReason: "PRO_REQUIRED", with totalCount) and the full snapshot to PRO; a free tracker returns the full snapshot to everyone.
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).
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. Phase 1 publishes "table". New viewType values are documented here when a tracker using them ships. |
accessTier |
string | "free" or "pro". pro trackers return a truncated preview to FREE callers; 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 |
For geographically-scoped trackers (none in Phase 1). Unknown keys are ignored. |
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 (the rows are truncated to a free preview). false for free trackers and for PRO callers. |
previewReason |
"PRO_REQUIRED" or null |
Only set when isPreview is true. |
totalCount |
integer | Present only on preview responses. The full row count before truncation. |
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. Phase 1 publishes "table"; 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 | Populated when viewType === "table". Each row carries its per-cell metrics[] (label + value + unit) so a generic renderer can derive column headers from rows[0].metrics. |
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.
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 |
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 also the Indexes vs. Trackers taxonomy on the methodology page). The standardized envelope plus the viewType taxonomy means:
- One renderer per
viewTypein 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
curl -H "X-SentiSense-API-Key: ssk_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/trackers"GET/api/v1/trackers/{trackerId}
Standardized snapshot envelope for one tracker
curl -H "X-SentiSense-API-Key: ssk_YOUR_KEY" \
"https://app.sentisense.ai/api/v1/trackers/{trackerId}"