# Institutional Flows API

> SEC 13F-HR filing data: market flows, institutional holders, activist positions, and options activity. Track what funds and banks are buying and selling.

Base URL: `https://app.sentisense.ai/api/v1/institutional`
Tier: PRO (free preview available)

All API access requires an API key via the `X-SentiSense-API-Key` header. Keys look like `ss_live_...`.

> SDKs: [Python](https://github.com/SentiSenseApp/sentisense#institutional-flows-13f) · [Node](https://github.com/SentiSenseApp/sentisense-node#institutional-flows-13f) · example: [institutional-flows.ts](https://github.com/SentiSenseApp/sentisense-node/blob/main/examples/institutional-flows.ts)

## Overview

The Institutional Flows API provides access to SEC 13F-HR filing data, giving you visibility into what major institutional investors are doing with their portfolios. This data is sourced from mandatory SEC filings that institutions with over $100M in AUM must submit quarterly.

**Use cases:**
- Track aggregate buying/selling activity across all institutional filers
- See which institutions hold a specific stock and how their positions changed
- Monitor activist investors taking new or increased positions
- Analyze convertible bond activity for hedge fund arbitrage signals
- Track institutional options positioning (call vs put sentiment)
- Build quantitative strategies based on institutional flow signals

**Filer categories:** Each institutional filer is classified into one of 11 categories: `INDEX_FUND`, `HEDGE_FUND`, `ACTIVIST`, `PENSION`, `BANK`, `INSURANCE`, `MUTUAL_FUND`, `SOVEREIGN_WEALTH`, `ENDOWMENT`, `CONGLOMERATE`, `OTHER`.

**Access:** The `/quarters` endpoint is public. All other endpoints require a PRO subscription. FREE-tier callers see a limited preview (top 5 results for flows/holders, top 3 for other tabs) with `isPreview: true` in the response.

**Important: Getting valid `reportDate` values**

`/activist`, `/bonds` and `/options` require a `reportDate` parameter. `/quarters`, `/flows` and `/holders/{ticker}` do not: omit it for the latest quarter, or pass one for a specific quarter. **Do not hardcode dates:** available quarters change as new SEC filings are processed. Call `GET /quarters` first to get valid dates:

**Skip pending quarters.** The first entry in the list is the current quarter, and it carries `pending: true` while the SEC's 45-day 13F filing window is still open. Passing a pending `reportDate` to `/activist`, `/bonds`, or `/holders/{ticker}` is a valid call, but it returns few rows or an empty `data` array, because almost nothing has been filed yet. Take the first quarter with `pending: false` unless you specifically want early-filer coverage. (Omitting `reportDate` on `/holders/{ticker}` already applies this rule for you, per ticker.)

```python
# Step 1: Get available quarters, then take the first fully filed one
quarters = client.get_institutional_quarters()
filed = [q for q in quarters if not q.get("pending")]
latest_date = filed[0]["reportDate"]  # e.g., "2026-03-31"

# Step 2: Use the reportDate in other calls
flows = client.get_institutional_flows(latest_date)
holders = client.get_stock_holders("AAPL", latest_date)
```

---

## GET /quarters

Returns the list of available 13F reporting quarters with data.

**Authentication:** API key required

**Parameters:** None

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/quarters"
```

```python
from sentisense import SentiSenseClient

client = SentiSenseClient(api_key="ss_live_YOUR_KEY")
quarters = client.get_institutional_quarters()
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `value` | string | Quarter identifier (e.g., `"2024Q4"`) |
| `label` | string | Display label (e.g., `"Q4 2024"`) |
| `reportDate` | string | Quarter end date (e.g., `"2025-12-31"`) |
| `pending` | boolean | `true` if the SEC's 45-day 13F filing window has not yet closed for this quarter: filings may still be arriving and data is incomplete. Check this before drawing conclusions from the most recent quarter. |

**Example Response:**

```json
[
  {
    "value": "2026Q1",
    "label": "Q1 2026",
    "reportDate": "2026-03-31",
    "pending": true
  },
  {
    "value": "2025Q4",
    "label": "Q4 2025",
    "reportDate": "2025-12-31",
    "pending": false
  },
  {
    "value": "2025Q3",
    "label": "Q3 2025",
    "reportDate": "2025-09-30",
    "pending": false
  }
]
```

The list is sorted newest-first, so `quarters[0]` is the one most likely to be pending. Filter on `pending` rather than indexing blind.

---

## GET /flows

Returns aggregate institutional buying and selling activity per stock ticker for a given quarter, split into **inflows** (net buying) and **outflows** (net selling). Shows net position changes, new vs. closed positions, and breakdowns by filer category.

**Authentication:** PRO required. Free users receive a preview of the top 5 results per direction.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `reportDate` | date (ISO) | No | latest | Quarter to fetch (e.g., `2025-12-31`). Omit to get the latest available quarter, including a still-open one (labeled with `isPending` plus filer coverage). Pass one from `/quarters` for a specific quarter. |
| `limit` | integer | No | 50 | Max results per direction (capped at 100) |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/flows?reportDate=2025-12-31&limit=20"
```

```python
client = SentiSenseClient(api_key="ss_live_YOUR_KEY")
flows = client.get_institutional_flows("2025-12-31", limit=20)
for flow in flows.data["inflows"]:
    print(f"{flow['ticker']}: net buy {flow['netSharesChange']:,} shares")
```

**Response Schema:** All tiers return the unified wrapper `{isPreview, previewReason, data}`. The `data` field is an object carrying the served-quarter metadata plus two arrays: `inflows` (stocks with positive net institutional buying) and `outflows` (stocks with negative net institutional selling).

| Field | Type | Description |
|-------|------|-------------|
| `reportDate` | string | The quarter actually served (useful when you omitted the param) |
| `isPending` | boolean | `true` when the served quarter is still inside the SEC's 45-day 13F filing window, so only early filers are represented |
| `filerCount` | int \| null | Filers represented when `isPending` is true (e.g. `578`); `null` otherwise |
| `baselineFilerCount` | int \| null | Total expected filers for a complete quarter (e.g. `8789`), for coverage context; `null` when not pending |
| `inflows` | array | Stocks with net positive institutional activity (see flow object below) |
| `outflows` | array | Stocks with net negative institutional activity (see flow object below) |

**Flow object fields:**

| Field | Type | Description |
|-------|------|-------------|
| `ticker` | string | Stock ticker symbol |
| `companyName` | string | Company name |
| `totalSharesBought` | long | Total shares purchased across all filers |
| `totalSharesSold` | long | Total shares sold across all filers |
| `netSharesChange` | long | Net change (bought - sold) |
| `newPositions` | int | Number of filers opening new positions |
| `increasedPositions` | int | Number of filers increasing existing positions |
| `decreasedPositions` | int | Number of filers decreasing positions |
| `soldOutPositions` | int | Number of filers completely exiting |
| `indexFundNetChange` | long | Net share change from index funds |
| `hedgeFundNetChange` | long | Net share change from hedge funds |
| `activistActivity` | boolean | Whether any activist investors have activity |
| `activistNetChange` | long | Net share change from activist investors |
| `pensionNetChange` | long | Net share change from pension funds |
| `bankNetChange` | long | Net share change from banks |
| `insuranceNetChange` | long | Net share change from insurance companies |
| `mutualFundNetChange` | long | Net share change from mutual funds |
| `sovereignWealthNetChange` | long | Net share change from sovereign wealth funds |
| `endowmentNetChange` | long | Net share change from endowments |
| `conglomerateNetChange` | long | Net share change from diversified holding companies / conglomerates |
| `reportDate` | string | Report date for this data |
| `avgClosePrice` | float \| null | Quarterly average closing price for the ticker. `null` when not yet cached. |
| `dollarFlowUsd` | float | Dollar-weighted net flow: `netSharesChange × avgClosePrice`. `0` when `avgClosePrice` is null; clients should fall back to displaying `netSharesChange`. Inflows are sorted by `dollarFlowUsd` descending, outflows ascending. |

**Example Response:**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": {
    "inflows": [
      {
        "ticker": "NVDA",
        "companyName": "NVIDIA Corporation",
        "totalSharesBought": 245000000,
        "totalSharesSold": 89000000,
        "netSharesChange": 156000000,
        "newPositions": 42,
        "increasedPositions": 318,
        "decreasedPositions": 156,
        "soldOutPositions": 28,
        "indexFundNetChange": 45000000,
        "hedgeFundNetChange": 78000000,
        "activistActivity": false,
        "activistNetChange": 0,
        "pensionNetChange": 12000000,
        "bankNetChange": 8000000,
        "insuranceNetChange": 3000000,
        "mutualFundNetChange": 5000000,
        "sovereignWealthNetChange": 2000000,
        "endowmentNetChange": 1000000,
        "conglomerateNetChange": 0,
        "reportDate": "2025-12-31"
      }
    ],
    "outflows": [
      {
        "ticker": "TSLA",
        "companyName": "Tesla, Inc.",
        "netSharesChange": -70000000,
        "..."
      }
    ]
  }
}
```

FREE tier: same shape with `isPreview: true` and `data` truncated.

---

## GET /holders/{ticker}

Returns the list of institutional holders for a specific stock, showing each institution's position size, value, and how it changed from the previous quarter. Only equity positions are included (bonds and options are excluded). Institutions that file through multiple SEC CIKs (for example Vanguard's family of registered advisers) are rolled up into a single holder row under the parent institution; the `cikCount` field reports how many filers were merged.

**Authentication:** PRO required. Free users receive a preview of the top 5 holders.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `ticker` | path | Yes | - | Stock ticker symbol (e.g., `AAPL`) |
| `reportDate` | date (ISO) | No | latest | Quarter end date (e.g., `2025-12-31`). Omit it and the endpoint resolves the most recent quarter in which this ticker actually has holders, preferring a settled quarter over a still-filing one, and echoes the quarter it used in `data.reportDate`. Pass one from `/quarters` for a specific quarter. |
| `limit` | int | No | - | Page size (1 to 1000). When present, the response is a sorted page and includes paging metadata (`returnedCount`, `offset`) plus a `notableChanges` summary. When omitted, the full holder list is returned (legacy behavior, unchanged). |
| `offset` | int | No | `0` | Start position within the sorted holder list. Only used with `limit`. |
| `sortBy` | string | No | `shares` | Sort field: `shares`, `valueUsd`, or `sharesChangePct`. Only used with `limit`. |
| `sortDir` | string | No | `desc` | Sort direction: `asc` or `desc`. Only used with `limit`. |

Paging applies to PRO (full) responses. Free-tier preview responses ignore the paging parameters. A mega-cap can have 5,000+ institutional holders, so paged requests are strongly recommended for interactive clients.

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/holders/AAPL?reportDate=2025-12-31"

# Or let the endpoint pick the latest quarter that has holders for this ticker
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/holders/AAPL?limit=25"
```

```python
client = SentiSenseClient(api_key="ss_live_YOUR_KEY")
holders = client.get_stock_holders("AAPL", "2025-12-31")
```

**Response Schema:** All tiers return the unified wrapper `{isPreview, previewReason, data}`. The `data` field contains the holder object described below.

| Field | Type | Description |
|-------|------|-------------|
| `ticker` | string | Stock ticker |
| `companyName` | string | Company name |
| `reportDate` | string | The quarter actually served (useful when you omitted the param) |
| `totalInstitutionalShares` | long | Total shares held by all institutions |
| `totalInstitutionalValue` | long | Total value in USD |
| `holderCount` | int | Number of institutional holders for the quarter (always the full count, even on paged responses) |
| `holders` | array | List of individual holders (see below) |
| `returnedCount` | int | Paged responses only: number of holders in this page |
| `offset` | int | Paged responses only: start position of this page in the sorted list |
| `notableChanges` | object | Paged responses only: `{count, top}` where `count` is the number of holders with a 10%+ position change on 10k+ shares, and `top` is the 5 largest such changes by dollar impact (holder objects) |

**Holder object:**

| Field | Type | Description |
|-------|------|-------------|
| `filerCik` | string | SEC CIK number |
| `filerName` | string | Institution name |
| `filerCategory` | string | Fund type: `INDEX_FUND`, `HEDGE_FUND`, `ACTIVIST`, `PENSION`, `BANK`, `INSURANCE`, `MUTUAL_FUND`, `SOVEREIGN_WEALTH`, `ENDOWMENT`, `CONGLOMERATE`, `OTHER` |
| `shares` | long | Current shares held |
| `valueUsd` | long | Position value in USD |
| `changeType` | string | `"NEW"`, `"INCREASED"`, `"DECREASED"`, `"SOLD_OUT"`, `"UNCHANGED"` |
| `sharesChange` | long | Change in shares from previous quarter |
| `sharesChangePct` | double | Percentage change |
| `entitySlug` | string | URL slug for the institution's detail page, or `null` if unmapped |
| `cikCount` | int | Number of sister filer CIKs merged into this row; `null` for ordinary single-filer rows |

**Example Response:**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": {
    "ticker": "AAPL",
    "companyName": "Apple Inc.",
    "reportDate": "2025-12-31",
    "totalInstitutionalShares": 12500000000,
    "totalInstitutionalValue": 2875000000000,
    "holderCount": 4521,
    "holders": [
      {
        "filerCik": "0001067983",
        "filerName": "Berkshire Hathaway Inc",
        "filerCategory": "HEDGE_FUND",
        "shares": 300000000,
        "valueUsd": 69000000000,
        "changeType": "DECREASED",
        "sharesChange": -100000000,
        "sharesChangePct": -25.0
      }
    ]
  }
}
```

FREE tier: same shape with `isPreview: true` and `data` truncated.

---

## GET /activist

Returns activist investor positions where the change type is `NEW` or `INCREASED`, indicating activists taking new stakes or increasing existing ones. Useful for monitoring potential activist campaigns.

**Authentication:** PRO required. Free users receive a preview of the top 3 positions.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `reportDate` | date (ISO) | Yes | - | Quarter end date (e.g., `2025-12-31`). Use a quarter with `pending: false` from `/quarters`; a pending quarter returns an empty `data` array because the filings have not arrived yet. |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/activist?reportDate=2025-12-31"
```

```python
client = SentiSenseClient(api_key="ss_live_YOUR_KEY")
activists = client.get_activist_positions("2025-12-31")
```

**Response Schema:** All tiers return the unified wrapper `{isPreview, previewReason, data}`. The `data` field is an array of activist position objects described below.

| Field | Type | Description |
|-------|------|-------------|
| `filerCik` | string | SEC CIK number |
| `filerName` | string | Activist investor name |
| `ticker` | string | Target company ticker |
| `companyName` | string | Target company name |
| `shares` | long | Current shares held |
| `valueUsd` | long | Position value in USD |
| `changeType` | string | `"NEW"` or `"INCREASED"` |
| `sharesChange` | long | Change in shares |
| `sharesChangePct` | double | Percentage change (0 for new positions) |
| `filedDate` | string | Date the 13F was filed |
| `reportDate` | string | Reporting quarter date |

**Example Response:**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": [
    {
      "filerCik": "0001336528",
      "filerName": "Pershing Square Capital Management",
      "ticker": "HLT",
      "companyName": "Hilton Worldwide Holdings Inc",
      "shares": 10250000,
      "valueUsd": 2460000000,
      "changeType": "INCREASED",
      "sharesChange": 1500000,
      "sharesChangePct": 17.1,
      "filedDate": "2025-12-31",
      "reportDate": "2024-12-31"
    }
  ]
}
```

FREE tier: same shape with `isPreview: true` and `data` truncated.

---

## GET /bonds

Returns convertible bond flows grouped by base ticker. Convertible bonds are detected from SEC 13F filings where the ticker contains bond notation (e.g., "ABNB 0 03/15/26"). Useful for identifying hedge fund arbitrage strategies.

**Authentication:** PRO required. Free users receive a preview of the top 3 results.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `reportDate` | date (ISO) | Yes | - | Quarter end date (e.g., `2025-12-31`) |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/bonds?reportDate=2025-12-31"
```

**Response Schema:** All tiers return the unified wrapper `{isPreview, previewReason, data}`. The `data` field is an array of bond flow objects described below.

| Field | Type | Description |
|-------|------|-------------|
| `baseTicker` | string | Base equity ticker (e.g., `"ABNB"`) |
| `companyName` | string | Company name |
| `positionCount` | int | Number of institutional positions in this bond |
| `totalValue` | long | Total position value in USD |
| `netSharesChange` | long | Net change in shares/units |
| `bondTickers` | string | Comma-separated bond notations (e.g., `"ABNB 0 03/15/26, ABNB 0.5 06/15/27"`) |
| `hedgeFundCount` | int | Number of hedge funds holding this bond |

**Example Response:**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": [
    {
      "baseTicker": "ABNB",
      "companyName": "Airbnb Inc",
      "positionCount": 24,
      "totalValue": 850000000,
      "netSharesChange": 5200000,
      "bondTickers": "ABNB 0 03/15/26",
      "hedgeFundCount": 18
    }
  ]
}
```

FREE tier: same shape with `isPreview: true` and `data` truncated.

---

## GET /options

Returns institutional options activity with call vs put breakdown per ticker. High call-to-put ratios indicate bullish institutional positioning; high put-to-call ratios indicate bearish positioning.

**Authentication:** PRO required. Free users receive a preview of the top 3 results.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `reportDate` | date (ISO) | Yes | - | Quarter end date (e.g., `2025-12-31`) |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/options?reportDate=2025-12-31"
```

**Response Schema:** All tiers return the unified wrapper `{isPreview, previewReason, data}`. The `data` field is an array of options activity objects described below.

| Field | Type | Description |
|-------|------|-------------|
| `ticker` | string | Stock ticker symbol |
| `companyName` | string | Company name |
| `callValue` | long | Total value of call option positions in USD |
| `putValue` | long | Total value of put option positions in USD |
| `callPositions` | int | Number of call option positions |
| `putPositions` | int | Number of put option positions |
| `callNetChange` | long | Net change in call option shares |
| `putNetChange` | long | Net change in put option shares |
| `hedgeFundCount` | int | Number of hedge funds with options in this ticker |

**Example Response:**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": [
    {
      "ticker": "TSLA",
      "companyName": "Tesla, Inc.",
      "callValue": 2400000000,
      "putValue": 1800000000,
      "callPositions": 156,
      "putPositions": 98,
      "callNetChange": 12000000,
      "putNetChange": 8000000,
      "hedgeFundCount": 45
    }
  ]
}
```

FREE tier: same shape with `isPreview: true` and `data` truncated.

---

## GET /institutions

Discover the universe of institutions: a paginated, AUM-ranked list of filers with their slug and metadata, so you can find what is worth querying without knowing slugs upfront. Each institution is rolled up by parent filer, so a multi-filer manager (e.g. Vanguard, which files under a parent plus multiple subsidiary CIKs) appears exactly once with its combined AUM. This endpoint is summary only; use `GET /institution/{slugOrCik}` for a filer's full holdings.

**Authentication:** API key required. This is a discovery endpoint: it does not consume your monthly quota (per-minute rate limits still apply), and every API key holder receives the full list.

**Parameters:** (all optional)

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `category` | string | No | - | Filter by filer category: `INDEX_FUND`, `HEDGE_FUND`, `ACTIVIST`, `PENSION`, `BANK`, `INSURANCE`, `MUTUAL_FUND`, `SOVEREIGN_WEALTH`, `ENDOWMENT`, `CONGLOMERATE`, `OTHER` |
| `minAumUsd` | long | No | - | Minimum total AUM in USD (e.g. `10000000000` for $10B and up) |
| `q` | string | No | - | Name search: case-insensitive match on institution display name or URL slug (max 100 chars). Combines with the other filters. |
| `limit` | integer | No | 50 | Page size (capped at 200) |
| `offset` | integer | No | 0 | Pagination offset |
| `sort` | string | No | `aumDesc` | `aumDesc`, `aumAsc`, or `nameAsc`. Ordering is deterministic (stable tie-break), so pagination is consistent across requests. |
| `quarter` | string | No | latest | AUM snapshot quarter as `YYYYQN` (e.g. `2026Q1`). Defaults to the latest available quarter. |

Bad inputs (unknown `category`, unknown `sort`, negative `offset`/`minAumUsd`, a `q` over 100 characters, or a `quarter` with no data) return `400` with `{error, message}`.

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/institutions?category=HEDGE_FUND&minAumUsd=10000000000&limit=20"
```

```python
client = SentiSenseClient(api_key="ss_live_YOUR_KEY")
page = client.list_institutions(category="HEDGE_FUND", min_aum_usd=10_000_000_000, limit=20)
for inst in page["institutions"]:
    print(inst["urlSlug"], inst["totalValueUsd"])
```

**Response Schema:** Returns the unified wrapper `{isPreview, previewReason, data}`. For this endpoint `isPreview` is always `false` and `previewReason` is always `null`. The `data` object is described below.

| Field | Type | Description |
|-------|------|-------------|
| `data.quarter` | string | Quarter of the AUM snapshot (e.g. `"2026Q1"`) |
| `data.totalCount` | int | Total institutions matching the filters, before pagination |
| `data.offset` | int | Offset applied to this page |
| `data.limit` | int | Page size applied to this page |
| `data.institutions` | array | The page of institution summaries (see below) |

**Institution object:**

| Field | Type | Description |
|-------|------|-------------|
| `cik` | string | SEC Central Index Key of the institution |
| `urlSlug` | string | URL slug for routing to `GET /institution/{slugOrCik}` |
| `displayName` | string | Cleaned display name |
| `filerCategory` | string | Filer category (may be `null` if unclassified) |
| `totalValueUsd` | long | Total AUM in USD for the quarter (rolled-up across the filer group) |
| `holdingsCount` | int | Distinct equity tickers held this quarter (rolled-up, de-duped) |
| `multiCikRollup` | boolean | `true` when this institution aggregates multiple related filer CIKs |
| `childCikCount` | int | Number of subsidiary filers rolled up under this institution (`0` when not a rollup) |

**Example Response:**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": {
    "quarter": "2026Q1",
    "totalCount": 7842,
    "offset": 0,
    "limit": 50,
    "institutions": [
      {
        "cik": "0001067983",
        "urlSlug": "Berkshire-Hathaway",
        "displayName": "Berkshire Hathaway",
        "filerCategory": "HEDGE_FUND",
        "totalValueUsd": 314000000000,
        "holdingsCount": 38,
        "multiCikRollup": false,
        "childCikCount": 0
      }
    ]
  }
}
```

---

## GET /institution/{slugOrCik}

Returns the full profile, summary stats, and current-quarter equity holdings for a specific institutional filer. Resolution checks the URL slug first, then the exact CIK, then the CIK zero-padded to 10 digits; CIK inputs accept 1 to 10 digits with optional leading zeros (e.g. `1067983` or `0001067983`).

**Authentication:** PRO required. Free users receive the profile and summary stats in full plus the top 10 holdings; PRO users get the full holdings array.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `slugOrCik` | path | Yes | - | URL slug (e.g. `Berkshire-Hathaway`) or SEC CIK of 1 to 10 digits with optional leading zeros (e.g. `1067983` or `0001067983`) |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/institutional/institution/Berkshire-Hathaway"
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `isPreview` | boolean | `true` when the caller is on the FREE tier |
| `previewReason` | string | `"PRO_REQUIRED"` or `null` |
| `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.filerCik` | string | SEC Central Index Key |
| `data.displayName` | string | Cleaned filer display name |
| `data.urlSlug` | string | URL slug for routing |
| `data.filerCategory` | string | Filer category (e.g. `INDEX_FUND`, `HEDGE_FUND`, `ACTIVIST`, `BANK`, `INSURANCE`, `MUTUAL_FUND`, `PENSION`, `SOVEREIGN_WEALTH`, `ENDOWMENT`, `CONGLOMERATE`) |
| `data.totalValueUsd` | long | Total AUM in USD (sum of equity position values for the latest quarter) |
| `data.holdingsCount` | int | Number of holdings rows, including `SOLD_OUT` rows (shares `0`); positions held is `holdingsCount` minus `soldOutPositions`. Full count, even when `holdings` is truncated |
| `data.positionsHeld` | int | Number of equity positions held in the latest quarter, computed as `max(0, holdingsCount - soldOutPositions)` for the full portfolio even when `holdings` is paged or truncated |
| `data.latestReportDate` | string | Report date of the latest quarter (ISO date) |
| `data.quartersTracked` | int | Number of quarters with data |
| `data.newPositions` | int | Count of NEW positions in the latest quarter |
| `data.increasedPositions` | int | Count of INCREASED positions |
| `data.decreasedPositions` | int | Count of DECREASED positions |
| `data.soldOutPositions` | int | Count of SOLD_OUT positions |
| `data.multiCikRollup` | boolean | `true` when this institution aggregates 13F filings across multiple related filer CIKs (e.g. a parent plus subsidiaries) |
| `data.childCikCount` | int | Number of subsidiary filers rolled up under this institution (`0` when not a rollup) |
| `data.childCiks` | array | The subsidiary CIKs rolled up under this institution (`null` when not a rollup) |
| `data.holdings` | array | Holdings array sorted by value descending (PRO: full list; FREE: top 10) |
| `data.optionPositions` | array | Long put/call legs disclosed on the same 13F, sorted by notional descending. PRO only, and omitted entirely when the filer disclosed no option legs |

**Holding object:**

| Field | Type | Description |
|-------|------|-------------|
| `ticker` | string | Stock ticker |
| `companyName` | string | Company name |
| `shares` | long | Shares held |
| `valueUsd` | long | Position value in USD |
| `changeType` | string | `NEW`, `INCREASED`, `DECREASED`, `SOLD_OUT`, or `UNCHANGED` |
| `sharesChange` | long | Share count change vs previous quarter |
| `sharesChangePct` | double | Percent change vs previous quarter |
| `portfolioWeight` | double | Position weight in the institution's total portfolio (%) |

**Option position object:**

A 13F discloses long option legs alongside equity positions. Each leg carries the underlying's ticker, the underlying share count the contracts represent, and the notional value of that exposure. Some filers express a view on an underlying *only* through options, so a ticker can appear in `optionPositions` without appearing in `holdings`.

Option legs are kept in their own array rather than merged into `holdings`, and their notional is excluded from `totalValueUsd` and from every `portfolioWeight`. A 13F notional is not a stake and not premium paid, so summing the two would misstate the portfolio.

| Field | Type | Description |
|-------|------|-------------|
| `ticker` | string | Underlying ticker |
| `companyName` | string | Issuer name as disclosed on the filing |
| `putCall` | string | `PUT` or `CALL` |
| `valueUsd` | long | Notional exposure in USD as disclosed. Not premium paid, not a directional P&L |
| `shares` | long | Underlying shares represented by the contracts |
| `changeType` | string | `NEW`, `INCREASED`, `DECREASED`, or `UNCHANGED` vs the prior quarter's same leg |

One row per (ticker, put/call): a filer holding both a put and a call on the same underlying gets two entries.

Returns 404 if the slug or CIK does not match a known filer.
