Congress Stock Trades API in Python
Query House and Senate stock trades with a Python Congress trading API. Read PTRs by company, member or feed, with a source filing link on every row.

Members of Congress disclose their stock trades on periodic transaction reports, and every one of those reports is a public document: a PDF on the House Clerk's site or a page on the Senate's electronic filing system. A Congress stock trades API is only as trustworthy as its link back to that document. If a row cannot be traced to the report it came from, you cannot tell a real trade from a parsing error.
This tutorial queries House and Senate trades in Python three ways (by company, by member and as a market-wide feed), and shows the request, the response and the source report side by side. Then it walks through the traps we found in real filings: rows that look like duplicates and are not, options mixed in with shares, paper filings that never reach a ticker query, open-ended amount bands, and a “45-day rule” that is really a 30-or-45-day rule. Every figure below is live API output pulled on 2026-10-25, and the three House reports we use as receipts (filings 20035669, 20035143 and 20035490) were checked line by line against the Clerk's PDFs.
What a periodic transaction report is (STOCK Act)
Under the STOCK Act, members of the House and Senate report their purchases, sales and exchanges of securities on a periodic transaction report (PTR). The report also covers assets held by a spouse, jointly or by a dependent child, and marks each line with an owner code. Amounts are not exact: each transaction is reported in a value band such as $1,001 - $15,000 or $1,000,001 - $5,000,000.
The deadline is shorter than most summaries say. The House Committee on Ethics' memo on the PTR due date calculator states it this way: “A PTR must be filed by the earlier of these two dates: (a) 30 days from being made aware of the transaction or (b) 45 days from the transaction.” The day a member is made aware of a trade (for example, when a spouse's broker reports it) is the notification date, and it matters for measuring lag correctly, which the last section covers.
The reports are published in two places:
- House: the Clerk's financial disclosure search, one PDF per report. Most are filed electronically and have a machine-readable table; some are filed on paper and scanned.
- Senate: the Senate eFD search (electronic financial disclosure). Electronic reports are web pages; paper reports are scanned images. The Senate Ethics Committee's financial disclosure page covers the Senate side of the rules.
Two things this data is not. It is not SEC data: corporate insiders file Form 4 with the SEC within two business days, a different regime covered in our insider trading API comparison and the SEC forms field guide. And it is not a full portfolio. The same House memo says “PTRs are not required for widely held investment funds such as mutual funds, exchange-traded funds, and index funds,” so the absence of fund trades in a report says nothing about whether a member traded funds.
The Congress trades API endpoints
StockFit serves the House and Senate as two parallel sets of four endpoints. The shapes are the same in both chambers, so code written for one works for the other with a different path segment.
| Access pattern | House | Senate | Unit and date filter |
|---|---|---|---|
| By company | /api/congress/house/trades | /api/congress/senate/trades | One row per transaction; startDate/endDate on the trade date |
| By member | /api/congress/house/trades/by-member | /api/congress/senate/trades/by-member | One item per report; dates on the filing date |
| Market-wide feed | /api/congress/house/trades/recent | /api/congress/senate/trades/recent | One item per report; since on the filing date, default 30 days |
| Member roster | /api/congress/house/members | /api/congress/senate/members | One row per member with at least one report |
The by-company endpoints take exactly one identifier: symbol, cik, cusip, composite_figi or share_class_figi. They also filter by owner (self, spouse, joint, child) and type (purchase, sale, exchange; sale includes partial sales). The trades endpoints page with page and pageSize, up to 250 per page. Authentication is a bearer token in the Authorization header, and the base URL is https://api.stockfit.io/v1.
The archive goes back to 2012 for the Senate and to January 2014 for the House. The roster endpoints are the way in when you start from a person rather than a ticker. Each row carries the member's bioguideId (the identifier the Congressional Bioguide uses, one letter and six digits) and counts that tell you up front how much of a member's history is machine-readable:
// GET /api/congress/senate/members (one element of the array)
{
"bioguideId": "W000802",
"name": "Sheldon Whitehouse",
"party": "Democrat",
"state": "RI",
"district": null,
"filingCount": 146,
"transactionCount": 1037,
"unparsedFilingCount": 21,
"firstFilingDate": "2012-08-17",
"lastFilingDate": "2026-10-01",
"lastTransactionDate": "2026-09-04"
}unparsedFilingCount is the number of reports with no machine-readable transactions, usually paper filings. Whitehouse has 21 of 146. We come back to why that number matters in the pitfalls section.
All eight endpoints are on the Pro plan: $99/month or $828/year ($69/month billed annually).
House and Senate trades by company in Python
Start with the question most people ask first: which members traded a given stock? For NVIDIA in the House:
curl "https://api.stockfit.io/v1/api/congress/house/trades?symbol=NVDA&pageSize=4" \
-H "Authorization: Bearer $STOCKFIT_API_KEY"The response, with the first row shown in full and a few fields left out:
{
"page": 1,
"pageSize": 4,
"totalPages": 95,
"totalResults": 377,
"data": [
{
"bioguideId": "F000110",
"party": "Democrat",
"state": "LA",
"district": "6",
"memberName": "Cleo Fields",
"filingId": "20035669",
"filingDate": "2026-10-22",
"filingUrl": "https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2026/20035669.pdf",
"isAmendment": false,
"owner": "self",
"assetName": "NVIDIA Corporation - Common Stock",
"assetTypeCode": "ST",
"ticker": "NVDA",
"transactionType": "purchase",
"transactionDate": "2026-10-01",
"notificationDate": "2026-10-01",
"amountRange": "$1,001 - $15,000",
"amountMin": 1001,
"amountMax": 15000,
"resolvedTicker": "NVDA",
"linkConfidence": "high"
}
// rows 2 and 3: the same values, same filing
// row 4: Daniel Meuser, filing 20035487, spouse, sale_partial
]
}Each row is one transaction with its member (bioguideId, memberName, party, state, district), its report (filingId, filingDate, isAmendment) and the link to the source document in filingUrl. The transaction itself has the owner code, the asset as disclosed (assetName, assetTypeCode, ticker), the transactionType, the transactionDate and notificationDate, and the band as text (amountRange) and as numbers (amountMin, amountMax). resolvedTicker and linkConfidence say how the row was matched to the company: high when the disclosed ticker resolved, lower when only the asset name matched.
The receipt: the House Clerk PDF
Open filing 20035669 and you find the report Cleo Fields signed on October 22, 2026: the NVIDIA purchases dated 10/01/2026 in the $1,001 - $15,000 band, plus a TSM purchase on 10/09/2026. The PDF also explains the first trap in this data, covered below: the three NVIDIA rows that look identical in the API sit in three different accounts.
All pages, both chambers
The Python version pages through every result. With pageSize=250 the House NVIDIA history is two requests:
import os
import requests
BASE = "https://api.stockfit.io/v1/api/congress"
HEADERS = {"Authorization": f"Bearer {os.environ['STOCKFIT_API_KEY']}"}
def get(path, **params):
r = requests.get(f"{BASE}/{path}", params=params, headers=HEADERS, timeout=60)
r.raise_for_status()
return r.json()
def trades_by_company(chamber, symbol, **filters):
"""Every transaction row for one company in one chamber, all pages."""
rows, page = [], 1
while True:
body = get(f"{chamber}/trades", symbol=symbol, page=page, pageSize=250, **filters)
rows.extend(body["data"])
if page >= body["totalPages"]:
return rows
page += 1
house = trades_by_company("house", "NVDA")
senate = trades_by_company("senate", "NVDA")
print(len(house), len(senate))377 114On 2026-10-25 that is 377 House transactions and 114 Senate transactions in NVIDIA. Senate rows have the same shape, with three differences: district is null, notificationDate is always null because the Senate data does not carry it, and filingUrl points to the report on eFD. The three newest Senate NVIDIA rows, trimmed:
// GET /api/congress/senate/trades?symbol=NVDA&pageSize=3 (totalResults 114)
{ "memberName": "Sheldon Whitehouse", "state": "RI", "district": null,
"filingId": "f8d003c0-ca1e-4c39-9d66-632d220180e1", "filingDate": "2026-09-02",
"filingUrl": "https://efdsearch.senate.gov/search/view/ptr/f8d003c0-ca1e-4c39-9d66-632d220180e1/",
"owner": "self", "transactionType": "sale_partial", "transactionDate": "2026-08-13",
"notificationDate": null, "amountRange": "$15,001 - $50,000" },
{ "memberName": "Sheldon Whitehouse", "filingId": "f8d003c0-ca1e-4c39-9d66-632d220180e1",
"owner": "spouse", "transactionType": "sale_partial", "transactionDate": "2026-08-13",
"notificationDate": null, "amountRange": "$1,001 - $15,000" },
{ "memberName": "Cory A. Booker", "state": "NJ",
"filingId": "e5144197-e49c-4f74-bec4-19f1f3124668", "filingDate": "2026-09-09",
"owner": "spouse", "transactionType": "sale", "transactionDate": "2026-08-11",
"notificationDate": null, "amountRange": "$15,001 - $50,000" }Filters narrow the query on the server. Dates here are trade dates:
# Spouse sales only (type=sale includes sale_partial), trades from 2026 on.
spouse_sales = trades_by_company(
"senate", "NVDA", owner="spouse", type="sale", startDate="2026-01-01"
)
# Purchases only, House, one quarter of trade dates.
q3_buys = trades_by_company(
"house", "NVDA", type="purchase", startDate="2026-07-01", endDate="2026-09-30"
)filingUrl may land on that page first and open the report after you accept. The House PDFs open directly, which is why the side-by-side checks in this post use House reports.Congress trades by member (bioguideId)
The by-member endpoints flip the query: every report one member filed, newest first, each with its transactions nested inside. Look the member up in the roster, then ask for their reports:
members = get("house/members")
pelosi = next(m for m in members if m["name"] == "Nancy Pelosi")
print(pelosi["bioguideId"]) # P000197
# startDate and endDate filter on the FILING date here, not the trade date.
body = get(
"house/trades/by-member",
bioguideId=pelosi["bioguideId"],
startDate="2026-08-21",
endDate="2026-08-21",
)
for report in body["data"]:
print(report["filingId"], report["filingDate"], report["parseStatus"], report["transactionCount"])
for t in report["transactions"]:
print(" ", t["transactionDate"], t["assetTypeCode"], t["ticker"], t["amountRange"])Nancy Pelosi has 67 reports on file. The one filed on 2026-08-21, trimmed to three of its 7 transactions:
{
"totalResults": 1,
"data": [
{
"filingId": "20035143",
"filingDate": "2026-08-21",
"filingUrl": "https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2026/20035143.pdf",
"parseStatus": "parsed",
"isAmendment": false,
"member": { "bioguideId": "P000197", "name": "Nancy Pelosi",
"party": "Democrat", "state": "CA", "district": "11" },
"transactionCount": 7,
"transactions": [
{ "owner": "spouse", "assetTypeCode": "ST", "ticker": "BE",
"transactionType": "purchase", "transactionDate": "2026-07-24",
"amountRange": "$1,000,001 - $5,000,000",
"description": "Purchased 10,000 shares." },
{ "owner": "spouse", "assetTypeCode": "OP", "ticker": "BE",
"transactionType": "purchase", "transactionDate": "2026-07-24",
"amountRange": "$1,000,001 - $5,000,000",
"description": "Purchased 100 call options with a strike price of $100 and an expiration date of 6/17/27." },
{ "owner": "spouse", "assetName": "REOF XXV, LLC", "assetTypeCode": "AB",
"ticker": null, "resolvedTicker": null, "linkConfidence": "none",
"transactionType": "purchase", "transactionDate": "2026-07-27",
"amountRange": "$500,001 - $1,000,000" }
// 4 more rows: BE shares and BE calls on 2026-07-28, INTC calls and INTC shares on 2026-07-24
]
}
]
}All seven rows match the PDF for filing 20035143: owner SP (spouse), asset type codes ST, OP and AB, the dates, the bands and the descriptions with share counts and option terms. Two things to notice. The description field carries detail the structured fields do not, like “100 call options with a strike price of $100”. And the report mixes shares, options and a private LLC stake, which is exactly what a by-company query flattens together (more on that below).
The difference in date filters is deliberate. On the by-company endpoints, startDate and endDate apply to the trade. On the by-member and recent endpoints, they apply to when the report was filed, because the unit is the report. If you want “everything this member disclosed in Q3,” use the by-member dates. If you want “trades this member made in Q3,” pull a wider filing window and filter the nested transactionDate yourself, since a trade can be reported weeks or months after it happens.
Paper reports are listed here too, with parseStatus set to unparsed_paper and an empty transactions list, so you can still follow filingUrl to the scanned original. parse_failed marks a report whose document could not be read. Amended reports appear next to the original, with isAmendment set to true.
Recent congressional trades feed and full backfill
The recent endpoints are the market-wide view: every report filed in a chamber since a date, newest filing first. Without since they return the last 30 days. They are ordered by filing date, not trade date, so a report about old trades shows up on the day it is filed. That is what you want for a feed, because it is the day the information became public.
from collections import Counter
def iter_reports(chamber, since):
"""Every report filed on or after `since`, newest filing first."""
page = 1
while True:
body = get(f"{chamber}/trades/recent", since=since, page=page, pageSize=250)
yield from body["data"]
if page >= body["totalPages"]:
return
page += 1
def flatten(reports):
"""One row per transaction, carrying the report it came from."""
for r in reports:
for i, t in enumerate(r["transactions"]):
yield {
**t,
"row_key": f"{r['filingId']}:{i}", # position in the report, not a content hash
"filingId": r["filingId"],
"filingDate": r["filingDate"],
"filingUrl": r["filingUrl"],
"isAmendment": r["isAmendment"],
"bioguideId": r["member"]["bioguideId"],
"memberName": r["member"]["name"],
}
reports = list(iter_reports("house", since="2026-09-25"))
print(len(reports), Counter(r["parseStatus"] for r in reports))
paper = [r for r in reports if r["parseStatus"] == "unparsed_paper"]
for r in paper:
print(r["filingDate"], r["member"]["name"], r["filingUrl"])
rows = list(flatten(reports))
print(len(rows), "transactions")36 Counter({'parsed': 30, 'unparsed_paper': 6})
2026-10-14 Michael T. McCaul https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2026/9116378.pdf
...
301 transactionsIn the 30 days to 2026-10-25, House members filed 36 reports. 30 were parsed into 301 transactions; 6 were paper filings with no transactions, from Michael T. McCaul, Ro Khanna, Tony Wied and three from Diana Harshbarger. Those six reports are real disclosures. A pipeline that counts only parsed rows reports a smaller, quieter Congress than the one that filed.
The flatten helper gives each transaction a row_key built from the filing ID and the row's position in the report. The API has no per-transaction ID, and the next section shows why a key built from the row's content is the wrong idea.
Backfill the whole archive
since=2012-01-01 with pageSize=250 pages through the complete history of a chamber, newest first. It is the documented bulk-backfill path:
# Full history, both chambers. Store raw reports keyed by filingId and re-run with a
# recent `since` on a schedule: late reports about old trades arrive by filing date.
import json
for chamber in ("senate", "house"):
with open(f"{chamber}_ptr_reports.jsonl", "w") as f:
for report in iter_reports(chamber, since="2012-01-01"):
f.write(json.dumps(report) + "\n")After the backfill, re-run the feed with a recent since on a schedule and upsert by filingId. Keep amendments as their own reports with isAmendment true rather than overwriting the original, so your history matches what was on file at each point in time. The same point-in-time discipline applies to any filing-based dataset; our 13F filing lag study shows what goes wrong when you date data by the period instead of the filing.
Congress trade data pitfalls, each with a receipt
Each of these comes from a real row in the API on 2026-10-25, with the report you can open to check it.
1. Rows that look like duplicates are separate trades
The House NVIDIA query returns 3 rows from filing 20035669 with identical values: Cleo Fields, owner self, purchase, 2026-10-01, $1,001 - $15,000. The obvious cleanup is to drop two of them. The PDF shows why that is wrong: the three lines sit under three different “Subholding Of” accounts (E*TRADE #2, E*TRADE - Fields Law Firm 2, LLC, and an E*TRADE IRA). The API has no account field, so the rows look the same, but they are three trades. Never deduplicate on member, ticker, date and amount. Use the report and the row's position in it, as row_key does above.
2. Options resolve to the stock ticker
In Pelosi's filing 20035143, 3 of the 7 rows are call options (assetTypeCode OP) on Bloom Energy and Intel, and they carry the tickers BE and INTC, the same as the share purchases. A by-company query for BE returns both. If you want share trades, filter assetTypeCode == "ST"; keep OP rows as their own series and read the strike and expiry from description.
3. Paper filings never reach a ticker query
By-company endpoints return transactions, and a paper report has none, so paper filers are absent from every ticker query by design. The roster shows how big the gap can be in the Senate:
- Richard Burr: 100 reports, 100 unparsed, 0 machine-readable transactions.
- Dianne Feinstein: 40 reports, 40 unparsed, 0 machine-readable transactions.
- Richard Blumenthal: 128 reports, 127 unparsed, 33 machine-readable transactions.
None of these members' paper-filed trades appear in a ticker query. The reports still exist, and the by-member and recent endpoints list each one with its filingUrl. Count them and show the count next to any statistic, instead of letting them disappear.
4. Amount bands are ranges, and some are open-ended
The top band has no ceiling. James C. Justice's report filed 2026-09-28 discloses a partial sale of a private hotel company:
// GET /api/congress/senate/trades/by-member?bioguideId=J000312, filing filed 2026-09-28
{ "assetName": "Greenbrier Hotel Corporation and Affiliates", "assetTypeCode": "PS",
"transactionType": "sale_partial", "transactionDate": "2026-08-14",
"amountRange": "Over $50,000,000", "amountMin": 50000000, "amountMax": null,
"ticker": null, "linkConfidence": "none" }amountMax is null because the band is “Over $50,000,000”. Summing amountMax as “dollars traded” is wrong twice: it overstates every bounded row and silently treats open-ended rows as zero. Carry both bounds and let the upper bound be unknown:
def amount_bounds(rows):
"""Lower and upper bound of the disclosed value. Upper is None if any band is open-ended."""
low = sum(t["amountMin"] for t in rows)
if any(t["amountMax"] is None for t in rows):
return low, None
return low, sum(t["amountMax"] for t in rows)
shares_only = [t for t in rows if t["assetTypeCode"] == "ST"]
options = [t for t in rows if t["assetTypeCode"] == "OP"]
print(amount_bounds(shares_only))5. Owner codes split one report
Sheldon Whitehouse's report filed 2026-09-02 has two NVIDIA partial sales on 2026-08-13: one owner self in the $15,001 - $50,000 band, one owner spouse in the $1,001 - $15,000 band. Both are disclosures by the member, and they are different holdings. Filter with owner on the server when you need one or the other, and report the owner next to every row you show.
6. sale and sale_partial
transactionType distinguishes a full sale (sale, as in Cory A. Booker's spouse's NVIDIA row) from a partial one (sale_partial, as in Whitehouse's). The type=sale filter returns both. If you only want positions that were closed, filter on transactionType == "sale" after the request.
7. No ticker is often the correct answer
Many disclosed assets are not listed stocks. Darrell Issa's report filed 2026-10-22 discloses a purchase and a sale of the same Treasury note, each in the $5,000,001 - $25,000,000 band:
// GET /api/congress/house/trades/recent, filing 20035700 (Darrell Issa), filed 2026-10-22
{ "assetName": "US Treasury Note 3.375% due 09/15/28 CUSIP 91282CNY3", "assetTypeCode": "GS",
"ticker": null, "transactionType": "purchase", "transactionDate": "2026-10-08",
"amountRange": "$5,000,001 - $25,000,000", "amountMin": 5000001, "amountMax": 25000000,
"resolvedTicker": null, "linkConfidence": "none" },
{ "assetName": "US Treasury Note 3.375% due 09/15/28 CUSIP 91282CNY3", "assetTypeCode": "GS",
"ticker": null, "transactionType": "sale", "transactionDate": "2026-10-14",
"amountRange": "$5,000,001 - $25,000,000", "amountMin": 5000001, "amountMax": 25000000,
"resolvedTicker": null, "linkConfidence": "none" }Government securities (GS), private stakes (PS, as in the Justice row) and LLC stakes such as Pelosi's REOF XXV row come back with linkConfidence none and no ticker. A join on ticker drops them, which is right for a stock screen and wrong for a full picture of a member's activity. The market-wide feed keeps them all.
8. One report can hold hundreds of transactions
On the by-member and recent endpoints, pageSize counts reports, not transactions. Alan Armstrong's Senate report filed 2026-07-21 holds 703 transactions, so a by-member request with pageSize=1 returns a 243,566-character response for one report. Set a generous timeout, stream pages to disk as the backfill above does, and do not assume a small page means a small payload.
Measure disclosure lag: the 30-day and 45-day rule
Disclosure lag is the time between a trade and the public report: filingDate minus transactionDate. Comparing it with a flat 45 days misses half the House rule. The deadline is the earlier of 45 days after the trade and 30 days after the member was notified, and House rows carry notificationDate, so you can compute it:
from datetime import date, timedelta
def _d(s):
return date.fromisoformat(s) if s else None
def due_date(t):
"""Earlier of 45 days after the trade and 30 days after notification (House rule).
Senate rows have no notificationDate, so only the 45-day leg applies. That is the
latest possible deadline, so for Senate rows days_after_due can only understate lateness."""
candidates = [_d(t["transactionDate"]) + timedelta(days=45)]
notified = _d(t.get("notificationDate"))
if notified:
candidates.append(notified + timedelta(days=30))
return min(candidates)
def lag(t):
if not t.get("transactionDate"):
return None
filed, traded, due = _d(t["filingDate"]), _d(t["transactionDate"]), due_date(t)
return {
"row_key": t["row_key"],
"lag_days": (filed - traded).days,
"due": due.isoformat(),
"days_after_due": max(0, (filed - due).days),
"filingUrl": t["filingUrl"],
}
lags = [x for x in map(lag, rows) if x]
flagged = [x for x in lags if x["days_after_due"] > 0]
for x in flagged:
print(x){'row_key': '20035490:0', 'lag_days': 53, 'due': '2026-10-08', 'days_after_due': 8, 'filingUrl': 'https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2026/20035490.pdf'}In the 30-day House window above, one row lands after its computed due date. It is from Laurel M. Lee's filing 20035490: a spouse sale of Bank of America stock on 2026-08-24, notification on 2026-09-21, report filed 2026-10-16. That is 53 days after the trade and 25 days after notification. The two legs give 2026-10-08 (45 days after the trade) and 2026-10-21 (30 days after notification); the earlier one is 2026-10-08, and the report is dated 8 days after it. The PDF matches the API on the dates, the band and the owner.
Treat a flag as a reason to open the report, not as a finding. The script counts calendar days, and the House Committee on Ethics, which publishes its own PTR due date calculator, is the authority on whether a report was late. What the code gives you is a reproducible list with a source link on every line.
Senate rows: only the 45-day leg
Senate rows have no notificationDate, so due_date falls back to 45 days after the trade. Because 45 days after the trade is the latest the deadline can be, this fallback can only understate lateness: a Senate report it flags is past the outer limit, but one it passes may still have missed the 30-day leg. Say which rule you applied when you publish a Senate lag number.
Reach back further than you think
A trade-date window cut too short loses reports that arrive late or disclose old activity. Tim Sheehy's one Senate report, filed 2026-08-13, lists 5 transactions in private holdings dated 423 to 282 days earlier. Each row carries the filer's own note: “It is unclear whether filer's indirect interest through multiple layers of ownership requires reporting the transaction. Filer is reporting in the interest of public disclosure.” So this is not a late report of a required trade; it is a voluntary disclosure of old ones, and it would be invisible to anyone who only queried trades from the last 90 days. Pull by filing date, keep everything, and compute lag per row.
For the same reason, a share-of-late-reports figure from one 30-day window says little about Congress as a whole. Run the lag code over the backfill instead and report the period, the chamber and the rule you used.
Congress trades API vs scraping the official sites
The Clerk and eFD are free, and everything above can be rebuilt from them. Doing it yourself means: crawling two different systems, getting past the eFD agreement page, parsing PDF tables and web pages into one schema, deciding what to do with scanned paper reports, matching filers to Bioguide IDs, resolving asset names to tickers, converting bands to numbers and tracking amendments. That is a reasonable project if Congress data is your product.
Whatever you use, a scraper you write, an API or a dataset, check it against the questions this post raised:
- Does every row link to the source report, so you can check it?
- Are paper reports listed and counted, or silently missing?
- Are identical-looking rows in one report kept as separate trades?
- Are options, government securities and private stakes typed, not forced onto a ticker?
- Is the notification date there, so the 30-day leg of the deadline can be tested?
- Are amounts given as both bounds, with open-ended bands left open?
The StockFit endpoints answer yes to all six for House data; for the Senate, the notification date is not available. The Congress endpoints are on the Pro plan. Every account starts with a . For how the Congress endpoints compare plan by plan with FMP's, see the Financial Modeling Prep alternatives post.
FAQ
Q.Is there an API for congress stock trades?
Q.How do I get Senate stock trades in Python?
Q.How late can members of Congress disclose stock trades?
Q.Does the congress trades API include spouse trades?
Q.Why are some congress trades missing a ticker?
Q.How far back does congressional trading data go?
Q.What is a periodic transaction report (PTR)?
Ready to build?
Free API key, no credit card.