← Blog

How to get SEC SC 13D activist stakes as JSON (without parsing EDGAR yourself)

When an investor crosses 5% of a company's voting stock with intent to influence it, they have ten days to file a Schedule 13D. That filing is the public record of an activist campaign starting: Starboard taking a position, Elliott building a stake, a founder consolidating control. If you trade event-driven or build research tooling, you want those as structured records the moment they land. SEC EDGAR will not hand them to you that way. This walks through why, and how to skip the parsing entirely.

Why 13D is annoying to get as data

The first surprise: a 13D is filed under the holder's CIK, not the company's. So if you poll a target ticker's submissions feed waiting for an activist, you will miss the initial 13D — it shows up on the reporting person's filing history, and the issuer is only listed as the subject. To catch every new stake you have to watch the form type across all filers, which means EDGAR full-text search (efts.sec.gov), not a per-company scan.

The second surprise is the form-type string itself. The submissions API and the filing cover page call it SC 13D. The full-text-search index calls the same form SCHEDULE 13D. Query with the wrong one and you get zero hits and no error.

The third surprise is the payload. Once you find the filing, the numbers you actually want — percent of class, shares beneficially owned, who the reporting person is — live on the cover page. Newer filings carry a primary_doc.xml with real elements (reportingPersonInfo, percentOfClass, aggregateAmountOwned, soleVotingPower). Older ones bury the same facts in narrative text like Percent of class represented by amount in Row (11): 5.1%. You end up writing one parser for the structured schema and a regex fallback for the prose, then maintaining both as the SEC rotates schema versions.

None of this is hard. It is just fiddly, and it breaks quietly. That is the worst kind of data plumbing to own.

The shortcut: one GET request

EDGAR Events does that pipeline and hands you the result. The activist-stakes endpoint resolves the full-text search, follows each hit to its cover-page XML, and extracts holder, target, percent of class, and share count into a typed record.

curl -s -H "X-API-Key: $EDGAR_KEY" \
  "https://api.edgarevents.com/activist-stakes?min_percent=5&limit=10"

A single event looks like this (a real SC 13D/A pulled from the live feed):

{
  "event_id": "0001493152-26-029689",
  "event_type": "activist_stake",
  "form": "SCHEDULE 13D/A",
  "filed_date": "2026-06-23",
  "accession": "0001493152-26-029689",
  "target": {
    "name": "AST SpaceMobile, Inc.",
    "ticker": "ASTS",
    "tickers": ["ASTS"],
    "cik": "0001780312"
  },
  "holders": [
    {
      "name": "Abel Avellan",
      "cik": "0001680225",
      "shares": 78252625.0,
      "percent_of_class": 20.8,
      "sole_voting": 78252625.0,
      "shared_voting": 0.0,
      "type_of_reporting_person": "IN"
    }
  ],
  "percent_of_class": 20.8,
  "shares": 78252625.0,
  "security_class": "Class A Common Stock",
  "date_of_event": "06/22/2026",
  "filing_url": "https://www.sec.gov/Archives/edgar/data/1680225/000149315226029689/primary_doc.xml",
  "parsed_structured": true
}

The top-level percent_of_class and shares are the largest values across the reporting persons, so a single-number filter does what you expect. Every holder is also itemized under holders if you need the breakdown. When a filing is too old to carry structured XML, parsed_structured is false and you get a percent_narrative field with the raw cover-page text instead of guessed numbers — the service does not fabricate a percent it could not read.

Filtering down to what you trade

The endpoint takes the filters you would otherwise apply by hand:

# Only a specific target
curl -s -H "X-API-Key: $EDGAR_KEY" \
  "https://api.edgarevents.com/activist-stakes?ticker=ASTS"

# Skip amendments, stakes of 10%+ only, in a date window
curl -s -H "X-API-Key: $EDGAR_KEY" \
  "https://api.edgarevents.com/activist-stakes?include_amendments=false&min_percent=10&startdt=2026-06-01&enddt=2026-06-26"

include_amendments controls whether 13D/A amendments (a holder updating an existing position) come through alongside fresh 13D filings. min_percent filters on percent of class. ticker narrows to one target.

Getting them pushed instead of polled

Polling is fine for backfill. For live campaigns you want the filing the moment it clears, so register a webhook and let the service POST matching events to you:

curl -s -X POST -H "X-API-Key: $EDGAR_KEY" -H "Content-Type: application/json" \
  -d '{"event_types":["activist_stake"],"min_percent":5,"url":"https://your-app.com/hooks/edgar"}' \
  "https://api.edgarevents.com/webhooks"

Each delivery is signed with HMAC-SHA256 in an X-Edgar-Signature: sha256=... header so you can verify it came from the service. Sign the raw request body with your webhook secret and compare:

import hmac, hashlib

def verify(secret: str, raw_body: bytes, header: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)

The webhook body wraps the same event record under {"type": "filing.created", "event": {...}}.

When to build it yourself instead

To be straight about it: if you only need 13D data occasionally and do not mind running the pipeline, open-source libraries like edgartools and py-sec-edgar parse EDGAR well and cost nothing but your time and a cron box. The reason to pay for this is that you would rather not own the full-text-search quirks, the two-schema cover-page parser, the SEC rate-limit throttling, and a webhook delivery loop — and you want a signed push within seconds of a filing rather than a nightly batch. That is the entire pitch: a narrow, hosted, real-time slice of EDGAR for people whose product is the thing they build on top of the data, not the scraper.

It is $29/month, self-serve, cancel anytime. Live from data.sec.gov. Get a key at edgarevents.com and the interactive reference is at api.edgarevents.com/docs.

SEC filings, already parsed.

Typed JSON for 8-K item codes, SC 13D activist stakes, IPO forms and merger proxies. $29/mo, self-serve, cancel anytime.

Get an API key