// guide
How to Get SEC Insider Trading Data in Python
Updated 2026-06-16. By Theodor Nielsen, founder of Form4API.
// answer
To get SEC Form 4 insider trading data in Python, send a GET request with the requests library to https://api.form4api.com/v1/transactions, passing a ticker and your API key in an X-Api-Key header. The response is parsed JSON — insider, transaction code, shares, price, and post-trade balance — with no EDGAR XML parsing required.
Get an API key
The raw filings are free on the SEC's EDGAR system, but parsing the XML and joining it to ticker / CIK / CUSIP metadata is the hard part — which is what the insider trading API does for you. Create a free key from the dashboard (no credit card; the free tier covers 15,000 calls a month), then keep it out of source control by reading it from an environment variable:
pip install requests export FORM4API_KEY="your_api_key" # from form4api.com/dashboard
Your first request
Fetch the most recent Form 4 transactions for a ticker. The API key goes in the X-Api-Key header; the query parameters control the filter:
import os
import requests
API_KEY = os.environ["FORM4API_KEY"]
BASE = "https://api.form4api.com"
resp = requests.get(
f"{BASE}/v1/transactions",
params={"ticker": "AAPL", "per_page": 50},
headers={"X-Api-Key": API_KEY},
timeout=30,
)
resp.raise_for_status()
transactions = resp.json()
print(f"Fetched {len(transactions)} transactions")
for t in transactions[:5]:
print(t["transactionDate"], t["transactionCode"],
t["sharesAmount"], "@", t["pricePerShare"])Each record is a parsed transaction with the insider, transaction code, share count, price, and post-trade balance. The full field list is in the API docs.
Filtering for the signal
Most Form 4 rows are mechanical — grants, tax withholding, option exercises. The high-signal subset is open-market purchases (transaction code P), because an insider generally buys for only one reason. Pass code=P to return only purchases, then drop pre-scheduled Rule 10b5-1 plan trades client-side, since they carry no information advantage:
resp = requests.get(
f"{BASE}/v1/transactions",
params={"ticker": "AAPL", "code": "P", "per_page": 50},
headers={"X-Api-Key": API_KEY},
timeout=30,
)
resp.raise_for_status()
# Open-market buys, excluding pre-scheduled 10b5-1 plan trades
buys = [t for t in resp.json() if not t.get("is10b5Plan")]
print(f"{len(buys)} discretionary open-market buys")For the full meaning of every transaction code, see the Form 4 guide; for why simultaneous buys matter more, see cluster buy signals.
Paging through history
One request returns the latest page. To walk further back, increase per_page or request successive pages until a short page comes back. A simple loop that collects everything for a ticker:
def all_transactions(ticker, code=None, per_page=100):
page, out = 1, []
while True:
params = {"ticker": ticker, "per_page": per_page, "page": page}
if code:
params["code"] = code
r = requests.get(f"{BASE}/v1/transactions", params=params,
headers={"X-Api-Key": API_KEY}, timeout=30)
r.raise_for_status()
batch = r.json()
out.extend(batch)
if len(batch) < per_page:
break
page += 1
return out
history = all_transactions("AAPL", code="P")
print(f"{len(history)} open-market buys in history")Check the docs for the exact pagination parameters and your plan's rate limits before running large backfills.
Real-time with webhooks
Polling is fine for analysis, but for alerts you want a push. Register a webhook from the dashboard and receive a POST on every new transaction within minutes of EDGAR publication. A minimal Flask receiver:
from flask import Flask, request
app = Flask(__name__)
@app.post("/form4-webhook")
def on_transaction():
event = request.get_json()
# TODO: verify the HMAC-SHA256 signature header before trusting the payload
tx = event["data"]
print("new Form 4:", tx["transactionCode"], tx["sharesAmount"])
return "", 204Payloads are signed with HMAC-SHA256 — always verify the signature before acting on a webhook. Webhooks are available on the paid plans; see the docs for the signing scheme and event types.
Full script
Putting it together — a single file that prints the recent discretionary open-market buys for a ticker, sorted by dollar value:
import os
import requests
API_KEY = os.environ["FORM4API_KEY"]
BASE = "https://api.form4api.com"
def recent_buys(ticker, limit=10):
r = requests.get(
f"{BASE}/v1/transactions",
params={"ticker": ticker, "code": "P", "per_page": 100},
headers={"X-Api-Key": API_KEY},
timeout=30,
)
r.raise_for_status()
buys = [t for t in r.json() if not t.get("is10b5Plan")]
buys.sort(key=lambda t: t["sharesAmount"] * t["pricePerShare"], reverse=True)
return buys[:limit]
for t in recent_buys("AAPL"):
value = t["sharesAmount"] * t["pricePerShare"]
print(f'{t["transactionDate"]} {t["sharesAmount"]:>10,.0f} sh ' +
f'@ {t["pricePerShare"]:>8,.2f} = {value:>14,.0f}')Ready to build it for real? Grab a free key on the insider trading API page, or read the full reference docs.
Frequently asked questions
How do I get SEC Form 4 data in Python?
The fastest way is to call a parsed REST API with the requests library. Send a GET request to https://api.form4api.com/v1/transactions with a ticker query parameter and your API key in an X-Api-Key header, and you get back the most recent Form 4 transactions as JSON — already parsed from EDGAR’s XML and joined to ticker, CIK, and CUSIP. You can do the same against raw EDGAR, but you would have to download and parse each filing’s XML yourself and maintain the reference data for the joins, which is roughly 200–400 lines of code per pipeline.
Is there a Python SDK for insider trading data?
Form4API publishes an official Python SDK, but you do not need it — the REST API is plain HTTP, so the requests library works everywhere with zero extra dependencies. Use the SDK if you want typed models and helpers; use raw requests if you want a single-file script or are running in a constrained environment. Both authenticate the same way, with an API key sent in the X-Api-Key header. See the docs for the SDK package name and installation.
How do I filter for insider buys only in Python?
Open-market purchases are transaction code P, which is the highest-signal Form 4 event because an insider generally buys for only one reason. Pass code=P as a query parameter to return only purchases, then drop any pre-scheduled Rule 10b5-1 plan trades client-side by filtering on the is10b5Plan field — those carry no information advantage. A typical signal filter is open-market buys, exclude 10b5-1, and focus on officers and directors.
How do I get real-time insider trading alerts in Python?
Instead of polling, register a webhook subscription and run a small Python web server (Flask or FastAPI) to receive a POST on every new transaction within minutes of EDGAR publication. The payload is a compact reference to the new filing, signed with HMAC-SHA256 — verify the X-Insider-Signature header, then fetch the full transaction from /v1/transactions. Webhooks are available on the paid plans; the free tier is poll-only.