Skip to main content
/v2/insider returns one trailing-90-day rollup plus the most recent transaction rows. The work is reading two summaries correctly: market_activity is the open-market buy/sell signal, and all_activity is every Form 4 kind including exercises and gifts. Mix them up and a quiet quarter looks like a sell-off.

One call

insider.py
import httpx

r = httpx.get(
    "https://api.stockcontext.com/v2/insider",
    params={"symbol": "AAPL", "limit": 10},  # limit 1-200, default 10
    headers={"X-API-Key": "sctx_..."},
)
data = r.json()["data"]
summary = data["summary_90d"]
The rollup scans the latest 200 Form 4 filings in the trailing 90 days. limit only caps how many recent_transactions rows come back; it does not change the summary math.

The summary, from a live AAPL response

insider.data.summary_90d
{
  "market_activity": {
    "buy_count": 0,
    "sell_count": 13,
    "net_shares_market_only": -397759,
    "net_value_usd": -111705105.08,
    "net_direction": "selling"
  },
  "all_activity": {
    "transactions": 43,
    "net_shares_all_kinds": 25895,
    "transactions_by_kind": {
      "open_market_sale": 13,
      "derivative_exercise": 22,
      "tax_withholding": 6,
      "gift": 2
    }
  },
  "unique_insiders": 7,
  "officer_share_pct": 42,
  "director_share_pct": 12,
  "ten_b5_1_plan_ratio_pct": 0,
  "notices": ["recent_transactions_limited_to_10"]
}
Read it straight:
  • Open-market: 0 buys, 13 sells, net -397,759 shares worth -$111.7M. net_direction is selling. These are the cash trades insiders chose to make, the part most people mean by “insider selling.”
  • All Form 4 activity: 43 transactions across 7 insiders. Of those, only 13 are open-market sales; the other 30 are 22 derivative exercises, 6 tax-withholding events, and 2 gifts. net_shares_all_kinds is positive (+25,895) because exercises add shares, which is why you never quote the all-activity net as a sell figure.
  • 10b5-1: ten_b5_1_plan_ratio_pct is 0. None of these sales were affirmatively disclosed as 10b5-1 plan sales: every row carries ten_b5_1: { "available": false, "reason": "trading_plan_not_disclosed" }, meaning the filing made no statement either way. Read a 0% ratio as undisclosed, not discretionary: you cannot conclude these were unplanned, only that no plan was reported. Plan sales (where ten_b5_1 is the literal true) carry less signal because they were set up in advance.

Recent rows

Each row carries a transaction_code (the raw Form 4 code) and a plain-English transaction_kind. The codes map as P open_market_purchase, S open_market_sale, M derivative_exercise, A award_grant, F tax_withholding, G gift. Two rows from the live response:
insider.data.recent_transactions[0..2] (trimmed)
[
  {
    "filing_date": "2026-05-29",
    "transaction_date": "2026-05-27",
    "insider_name": "Arthur D Levinson",
    "insider_role": "Director",
    "transaction_code": "S",
    "transaction_kind": "open_market_sale",
    "shares": 50000,
    "price_per_share": 311.02,
    "value_usd": 15551000.0,
    "shares_remaining": 3764576,
    "ten_b5_1": { "available": false, "reason": "trading_plan_not_disclosed" },
    "accession": "0001140361-26-023363"
  },
  {
    "filing_date": "2026-05-29",
    "transaction_date": "2026-05-27",
    "insider_name": "Arthur D Levinson",
    "insider_role": "Director",
    "transaction_code": "G",
    "transaction_kind": "gift",
    "shares": 65000,
    "price_per_share": { "available": false, "reason": "gift_no_market_price" },
    "value_usd": { "available": false, "reason": "gift_no_market_price" },
    "shares_remaining": 3764576,
    "ten_b5_1": { "available": false, "reason": "trading_plan_not_disclosed" },
    "accession": "0001140361-26-023363"
  }
]
The live response returns 10 rows here (the limit default). On the gift row, price_per_share and value_usd are objects with available: false and a reason, because a gift has no market price. Treat that as “no dollar figure,” never as a $0 trade. Exercises (derivative_exercise_price_not_disclosed) and tax withholding (tax_withholding_no_market_price) carry the same shape. ten_b5_1 is three-state and the API never returns a bare false: it is the literal true when the filing affirmatively discloses a 10b5-1 plan sale, or the envelope { "available": false, "reason": "trading_plan_not_disclosed" } when it does not. The not-disclosed envelope is silence, not a “no”; never render it as “insider was NOT on a plan.”

Notices

summary_90d.notices flags anything that bounds the rollup. Two you will see:
  • recent_transactions_limited_to_N: more rows exist than the limit you asked for; raise limit (up to 200) to see them.
  • scanned_latest_200_filings_only: the 90-day window held more than 200 Form 4 filings, so the rollup covers the most recent 200. Surface this; the summary is complete only up to that cap.
Pass notices through to the reader verbatim. Dropping it hides the boundary on the numbers.

A reportable answer

answer
AAPL insider activity, trailing 90 days (as_of 2026-06-05, end_of_day):
- Open-market: 0 buys, 13 sells, net -$111.7M across 7 insiders. Direction: selling.
- No 10b5-1 plan sales were disclosed (0% plan ratio); the filings made no plan statement.
- The other 30 Form 4 events were option exercises, tax withholding, and gifts:
  routine, not open-market trades.

This is a description of filed activity, not a buy or sell signal.
That last line is the guardrail. Net selling is not “bearish,” net buying is not “bullish”: insiders sell for taxes, diversification, and scheduled plans. Describe the activity and its sign; do not convert it to advice. That anti-advice rule lives in the agent instructions.

Scope

  • /v2/insider is Form 4 transactions plus Form 144 intent-to-sell notices. Institutional ownership and 13F holders are private beta, not part of this public-core route.
  • ETFs and foreign private issuers that file 20-F/40-F/6-K return unsupported here, because there are no domestic Form 4 filers to scan. See coverage and gaps.

SEC risk review

For the prose of a filing (risk factors, MD&A), walk the section endpoints instead.