# Trackers API

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

Base URL: `https://app.sentisense.ai/api/v1/trackers`
Tier: Free (API key required); some trackers gate richer data to PRO

All API access requires an API key via the `X-SentiSense-API-Key` header. Keys look like `ss_live_...`.
## 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](https://sentisense.ai/methodology) (e.g. [#institution-rankings](https://sentisense.ai/methodology#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

```json
{
  "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:

```json
{
  "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:**

```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:**

```ts
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](https://sentisense.ai/methodology#institution-rankings) on the methodology page). 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.
