# Politicians Trading API

> Track congressional STOCK Act trading disclosures: purchases, sales, and exercises by U.S. Senators and Representatives. Updated daily from official filings.

Base URL: `https://app.sentisense.ai/api/v1/politicians`
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) · [Node](https://github.com/SentiSenseApp/sentisense-node#congressional-trading)

## Overview

The Politicians Trading API provides access to congressional STOCK Act trading disclosures. Under the STOCK Act (2012), members of the U.S. Senate and House of Representatives must publicly disclose securities transactions within 45 days. This data reveals what elected officials are buying and selling in their personal portfolios.

**Use cases:**
- Track which stocks members of Congress are buying and selling
- Filter by chamber (Senate vs House), party, or state
- Identify stocks with heavy congressional interest
- Cross-reference politician trades with insider trading (Form 4) and institutional flows (13F)
- Build quantitative strategies based on congressional trading data

**Chambers:** `SENATE`, `HOUSE`.

**Transaction types:** `PURCHASE`, `SALE`, `EXCHANGE`, `OTHER`.

**Asset types:** `Stock`, `ETF`, `Stock Option`. Other asset classes that appear on filings (bonds, mutual funds) are currently excluded from API responses.

**Ownership types:** `Self`, `Spouse`, `Child`, `Joint`.

**Amount ranges:** STOCK Act disclosures report dollar amounts as ranges (e.g., "$1,001 - $15,000"), not exact values. The API returns the raw range string plus parsed `amountMin` and `amountMax` fields.

**Access:** All endpoints require an API key. PRO subscribers get the full data; FREE-tier callers receive a limited preview with `isPreview: true` in the response.

Migrating from a bulk JSON dump of congressional filings? Endpoint-by-endpoint mapping: [the migration guide](/blog/capitol-trades-api-senate-stock-watcher-alternative/).

Working in Python? Five runnable scripts: [Python political trading examples](/blog/python-political-trading-examples/). Comparing trackers: [the best congressional trading trackers in 2026](/blog/best-congressional-trading-trackers-2026/).

---

## GET /activity

Returns recent congressional trading activity across all politicians, sorted by disclosure date (most recently disclosed first), falling back to transaction date when a disclosure date is absent. Each entry is a single STOCK Act disclosure record. Note that "recent" means recently disclosed, not recently traded: a filing can disclose a transaction made up to 45 days earlier, so a trade with an older `transactionDate` can appear at the top when its `disclosureDate` is fresh.

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

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `lookbackDays` | integer | No | 90 | Size of the trailing window, applied to the disclosure date. Must be between 1 and 365 (inclusive); returns 400 otherwise |
| `limit` | integer | No | 200 | Rows per page. Values above 500 are clamped to 500 rather than rejected; a value below 1 returns 400 `invalid_limit` |
| `offset` | integer | No | 0 | Rows to skip, for paging through the window. A negative value returns 400 `invalid_offset` |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/politicians/activity?lookbackDays=90&limit=50&offset=0"
```

```python
from sentisense import SentiSenseClient

client = SentiSenseClient(api_key="ss_live_YOUR_KEY")
activity = client.get_politician_activity(lookback_days=90)
for trade in activity.data:
    print(f"{trade['politicianName']} ({trade['party']}-{trade['state']}): {trade['transactionType']} {trade['ticker']} {trade['amountRange']}")
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `isPreview` | boolean | `true` when response is limited (FREE tier) |
| `previewReason` | string | `"PRO_REQUIRED"` or `null` |
| `totalCount` | integer | Size of the whole window, not of the page. `offset + data.length < totalCount` means there is another page |
| `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` | array | Array of trade objects (see below) |

**Trade object:**

| Field | Type | Description |
|-------|------|-------------|
| `politicianName` | string | Full name (e.g., "Nancy Pelosi") |
| `firstName` | string | First name |
| `lastName` | string | Last name |
| `chamber` | string | `SENATE` or `HOUSE` |
| `party` | string | Political party (e.g., "Democrat", "Republican") |
| `state` | string | Two-letter state code (e.g., "CA") |
| `bioguideId` | string | Official Bioguide identifier |
| `imageUrl` | string | URL to politician's headshot image |
| `ticker` | string | Stock ticker symbol |
| `assetDescription` | string | Security description from filing |
| `assetType` | string | `Stock`, `ETF`, or `Stock Option` |
| `assetMetadata` | object | Structured asset detail, or `null` for plain stocks and ETFs. Discriminated by `kind`. For options: `{ "kind": "OPTION", "optionType": "CALL" or "PUT", "strikePrice": number, "expirationDate": "YYYY-MM-DD" }` |
| `transactionType` | string | `PURCHASE`, `SALE`, `EXCHANGE`, or `OTHER` |
| `transactionDate` | string | Date of the transaction (ISO format) |
| `disclosureDate` | string | Date the disclosure was filed |
| `disclosureDelayDays` | int | Days between transaction and disclosure |
| `amountRange` | string | Raw STOCK Act range (e.g., "$1,001 - $15,000") |
| `amountMin` | long | Minimum dollar amount of the range |
| `amountMax` | long | Maximum dollar amount of the range |
| `owner` | string | Who made the trade: `Self`, `Spouse`, `Child`, or `Joint` |
| `urlSlug` | string | Politician's URL slug for `/member/{slug}` lookup |
| `sentiSenseScore` | double\|null | Reserved for the politician's sentiment reading; currently always `null` |

**Example Response:**

```json
{
  "isPreview": false,
  "previewReason": null,
  "data": [
    {
      "politicianName": "Nancy Pelosi",
      "firstName": "Nancy",
      "lastName": "Pelosi",
      "chamber": "HOUSE",
      "party": "Democrat",
      "state": "CA",
      "bioguideId": "P000197",
      "imageUrl": "https://sentisense-image-gallery.s3.us-east-2.amazonaws.com/politicians/P000197.jpg",
      "ticker": "NVDA",
      "assetDescription": "NVIDIA Corporation",
      "assetType": "Stock",
      "transactionType": "PURCHASE",
      "transactionDate": "2026-03-15",
      "disclosureDate": "2026-03-28",
      "disclosureDelayDays": 13,
      "amountRange": "$500,001 - $1,000,000",
      "amountMin": 500001,
      "amountMax": 1000000,
      "owner": "Spouse",
      "urlSlug": "Nancy-Pelosi"
    },
    {
      "politicianName": "Nancy Pelosi",
      "firstName": "Nancy",
      "lastName": "Pelosi",
      "chamber": "HOUSE",
      "party": "Democrat",
      "state": "CA",
      "bioguideId": "P000197",
      "imageUrl": "https://sentisense-image-gallery.s3.us-east-2.amazonaws.com/politicians/P000197.jpg",
      "ticker": "NVDA",
      "assetDescription": "NVIDIA Corporation - Call Options",
      "assetType": "Stock Option",
      "assetMetadata": {
        "kind": "OPTION",
        "optionType": "CALL",
        "strikePrice": 50,
        "expirationDate": "2026-12-18"
      },
      "transactionType": "PURCHASE",
      "transactionDate": "2026-03-15",
      "disclosureDate": "2026-03-28",
      "disclosureDelayDays": 13,
      "amountRange": "$1,000,001 - $5,000,000",
      "amountMin": 1000001,
      "amountMax": 5000000,
      "owner": "Spouse",
      "urlSlug": "Nancy-Pelosi"
    }
  ]
}
```

FREE tier: same shape with `isPreview: true`, `previewReason: "PRO_REQUIRED"`, and `data` truncated to top 5.

---

## GET /filings/{ticker}

Returns congressional trades for a specific stock, sorted by disclosure date (most recently disclosed first), falling back to transaction date when a disclosure date is absent. Use this to see which politicians have been buying or selling a particular ticker.

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

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `ticker` | path | Yes | - | Stock ticker symbol (e.g., `AAPL`) |
| `lookbackDays` | integer | No | 90 | Size of the trailing window, applied to the disclosure date. Must be between 1 and 365 (inclusive); returns 400 otherwise |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/politicians/filings/NVDA?lookbackDays=180"
```

```python
filings = client.get_politician_filings("NVDA", lookback_days=180)
for f in filings.data:
    print(f"{f['politicianName']}: {f['transactionType']} {f['amountRange']} on {f['transactionDate']}")
```

**Response:** Same preview wrapper and trade object schema as `/activity`.

---

## GET /directory

Discover every tracked member of Congress and the page slug that identifies them, so you can find what is worth querying without knowing slugs upfront. Summary only: this endpoint returns no trade data. Use `GET /member/{slug}` for a member's filings.

Unlike `/members`, the directory includes members who have **left Congress**. That roster lists who currently holds office; this lists who we track. Former members carry `former: true` and the year they left, and are otherwise reachable only if you already know their slug.

**Authentication:** API key required. Not tier-gated, so FREE and PRO callers receive the same full response. Does not count against your monthly request quota.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `q` | string | No | - | Case-insensitive filter across display name, state and slug (max 100 chars) |
| `limit` | integer | No | 50 | Results per page (max 200) |
| `offset` | integer | No | 0 | Results to skip, for paging |

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/politicians/directory?q=pelosi&limit=5"
```

```python
directory = client.get_politician_directory(q="pelosi", limit=5)
for m in directory["members"]:
    seat = "Former " if m["former"] else ""
    print(f"{m['displayName']} ({m['party']}-{m['state']}) {seat}{m['chamber']} -> /member/{m['urlSlug']}")
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `data.members` | array | Array of directory entries (see below) |
| `data.totalCount` | integer | Size of the whole matched set. `offset + members.length < totalCount` means another page |

**Directory entry object:**

| Field | Type | Description |
|-------|------|-------------|
| `urlSlug` | string | URL-friendly identifier (use with `/member/{slug}`) |
| `displayName` | string | Full display name |
| `chamber` | string | `"SENATE"` or `"HOUSE"` |
| `party` | string | Political party |
| `state` | string | Two-letter state code |
| `bioguideId` | string | Official Congressional Biographical Directory id |
| `imageUrl` | string | Official portrait URL, or `null` |
| `former` | boolean | `true` for a member who has left Congress |
| `servedUntil` | string | Year the member left, e.g. `"2021"`. `null` for a sitting member |

**Example Response:**

```json
{
  "data": {
    "members": [
      {
        "urlSlug": "Nancy-Pelosi",
        "displayName": "Nancy Pelosi",
        "chamber": "HOUSE",
        "party": "Democrat",
        "state": "CA",
        "bioguideId": "P000197",
        "imageUrl": "https://sentisense-image-gallery.s3.us-east-2.amazonaws.com/politicians/P000197.jpg",
        "former": false,
        "servedUntil": null
      }
    ],
    "totalCount": 1
  }
}
```

---

## GET /members

Returns all tracked politicians with trading summary statistics, sorted by total trade count (most active first).

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

**Parameters:** None.

**Example Request:**

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

```python
members = client.get_politician_members()
for m in members.data:
    print(f"{m['displayName']} ({m['party']}-{m['state']}): {m['totalTrades']} trades ({m['purchaseCount']} buys, {m['saleCount']} sells)")
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `isPreview` | boolean | `true` when response is limited |
| `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` | array | Array of politician summary objects (see below) |

**Politician summary object:**

| Field | Type | Description |
|-------|------|-------------|
| `urlSlug` | string | URL-friendly identifier (use with `/member/{slug}`) |
| `displayName` | string | Full display name |
| `firstName` | string | First name |
| `lastName` | string | Last name |
| `chamber` | string | `SENATE` or `HOUSE` |
| `party` | string | Political party |
| `state` | string | Two-letter state code |
| `bioguideId` | string | Official Bioguide identifier |
| `imageUrl` | string | URL to headshot image |
| `totalTrades` | int | Total number of disclosed trades |
| `purchaseCount` | int | Number of purchase transactions |
| `saleCount` | int | Number of sale transactions |
| `latestTradeDate` | string | Date of most recent trade |
| `kbEntityId` | string\|null | Internal ontology entity ID |
| `sentiSenseScore` | double\|null | Reserved for the politician's sentiment reading; currently always `null` |

---

## GET /member/{slug}

Returns a detailed profile for a single politician, including their summary statistics, recent trades, and most-traded tickers.

**Authentication:** PRO required. Free users receive a preview-wrapped response.

**Parameters:**

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `slug` | path | Yes | - | Politician URL slug (e.g., `Nancy-Pelosi`). Get slugs from `/members` |
| `limit` | integer | No | 200 | Trades per page in `recentTrades`. Values above 500 are clamped to 500 rather than rejected; a value below 1 returns 400 `invalid_limit` |
| `offset` | integer | No | 0 | Trades to skip, for paging through the member's history. A negative value returns 400 `invalid_offset` |

> **Note:** slugs are Capitalized-Hyphenated (derived from the politician's name with case preserved, e.g. `Nancy-Pelosi`) and the lookup is case-sensitive: `nancy-pelosi` returns 404.

> **Paging:** `recentTrades` is one page of the member's history, newest transaction first, not the entire history. Most members disclose a few dozen trades and arrive complete in the default page; a handful have disclosed thousands. Read `totalCount` to size the whole history rather than treating `recentTrades.length` as the total. `profile` and `topTickers` always describe the whole history regardless of the page requested, so `profile.totalTrades` does not shrink when you pass a small `limit`.

**Example Request:**

```bash
curl -H "X-SentiSense-API-Key: ss_live_YOUR_KEY" \
  "https://app.sentisense.ai/api/v1/politicians/member/Nancy-Pelosi?limit=50&offset=0"
```

```python
detail = client.get_politician_member("Nancy-Pelosi", limit=50)
profile = detail.data["profile"]
print(f"{profile['displayName']} - {profile['totalTrades']} trades")
for trade in detail.data["recentTrades"]:
    print(f"  {trade['transactionDate']}: {trade['transactionType']} {trade['ticker']} {trade['amountRange']}")

# Walk the rest of the history
offset = 50
while offset < detail.total_count:
    page = client.get_politician_member("Nancy-Pelosi", limit=50, offset=offset)
    offset += len(page.data["recentTrades"])
```

**Response Schema:**

| Field | Type | Description |
|-------|------|-------------|
| `isPreview` | boolean | `true` when response is limited |
| `previewReason` | string | `"PRO_REQUIRED"` or `null` |
| `totalCount` | integer | Trades in the member's whole history, not in the page. `offset + data.recentTrades.length < totalCount` means there is another page |
| `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 | Politician detail object (see below) |

**Politician detail object:**

| Field | Type | Description |
|-------|------|-------------|
| `profile` | object | Politician summary (same schema as `/members` entries), describing the whole history |
| `recentTrades` | array | One page of trade objects, newest transaction first (same schema as `/activity` entries) |
| `topTickers` | array | Most-traded ticker symbols (strings) across the whole history |

**Example Response:**

```json
{
  "isPreview": false,
  "previewReason": null,
  "totalCount": 42,
  "data": {
    "profile": {
      "urlSlug": "Nancy-Pelosi",
      "displayName": "Nancy Pelosi",
      "chamber": "HOUSE",
      "party": "Democrat",
      "state": "CA",
      "bioguideId": "P000197",
      "imageUrl": "https://sentisense-image-gallery.s3.us-east-2.amazonaws.com/politicians/P000197.jpg",
      "totalTrades": 42,
      "purchaseCount": 28,
      "saleCount": 14,
      "latestTradeDate": "2026-03-15"
    },
    "recentTrades": [
      {
        "ticker": "NVDA",
        "transactionType": "PURCHASE",
        "transactionDate": "2026-03-15",
        "amountRange": "$500,001 - $1,000,000",
        "owner": "Spouse"
      }
    ],
    "topTickers": ["NVDA", "AAPL", "MSFT", "GOOG", "AMZN"]
  }
}
```
