DEV Community

FedSignals Data
FedSignals Data

Posted on

How to Track New SEC Form D Filings (Startup Funding Rounds) Every Day

Get each day's new Form D filings from SEC EDGAR, filtered by industry, state and round size, in Python or Slack.

Written with AI assistance and reviewed by the FedSignals Data team; we maintain these tools.

When a U.S. company raises money privately, whether it's a startup's seed round, a Series A, a real-estate syndication or a fund, it files a Form D with the SEC, within 15 days after the first sale of securities. The filing lists the issuer, its state and industry, the offering size, how much has been sold and how many investors bought in. It's public on SEC EDGAR the same day.

That makes Form D one of the earliest public signals that a company just raised money. Sales teams, investors and recruiters all watch it.

The usual options for getting the data:

  • Search EDGAR by hand. It's free, but you can't filter by round size or industry, and you have to open each filing.
  • Parse EDGAR yourself. Download the daily index, find the D entries, fetch each primary_doc.xml and parse it, while following the SEC's fair-access rules (a declared User-Agent, at most 10 requests per second). This dev.to walkthrough is a good start if you want to build it yourself.
  • Use a paid filings API such as sec-api.io, which covers every form type.

We built the SEC Form D Scraper: EDGAR Startup Funding Rounds Actor on Apify as a middle option, and this tutorial walks through it. It does the index-and-parse work for you, applies your filters, and returns only filings you haven't seen before.

What you'll build

  • A daily list of new Form D filings, filtered by industry group, issuer state and offering size.
  • Operating companies only, with funds and SPVs removed.
  • A daily run that returns only filings it hasn't delivered before.
  • A Slack message (or webhook to your CRM) with each new round.

Step 1: Run it once by hand

Open apify.com/fedsignals/sec-form-d-monitor and click Try for free. This is the exact input we used for this article:

{
  "daysBack": 3,
  "industryGroups": ["Other Technology", "Biotechnology"],
  "excludePooledFunds": true,
  "minOfferingAmount": 1000000,
  "onlyNew": false,
  "maxItems": 5
}
Enter fullscreen mode Exit fullscreen mode

What each setting does:

  • daysBack: 3 reads today's EDGAR daily index plus the previous business days. Use 1 for a daily schedule.
  • industryGroups uses the industry list from the Form D itself, such as "Other Technology", "Biotechnology", "Pharmaceuticals", "Other Health Care" or "Computers". Leave it empty for all industries.
  • excludePooledFunds: true drops VC, PE and hedge funds and SPVs, which make up a large share of Form D filings. You get operating companies only.
  • minOfferingAmount: 1000000 keeps offerings of $1M or more. Issuers can report the size as "Indefinite". Those rows are kept unless you set keepIndefiniteAmounts: false.
  • onlyNew: false is for this first test. You'll turn it on in Step 3.

Other filters: issuerStates (two-letter codes such as CA, NY, TX), maxOfferingAmount, incorporatedWithinFiveYearsOnly (a good proxy for young startups) and includeAmendments for Form D/A filings.

Step 2: Look at the output

Our run on Oct 29, 2026 took about 10 seconds. Its status read 5 new Form D filings delivered (maxItems 5 reached). Here's one row, trimmed:

{
  "issuerName": "Arms Cyber Defense, Inc.",
  "issuerCity": "Los Gatos",
  "issuerState": "CA",
  "jurisdictionOfInc": "DELAWARE",
  "entityType": "Corporation",
  "yearOfInc": null,
  "industryGroup": "Other Technology",
  "exemptions": ["06b"],
  "isAmendment": false,
  "dateOfFirstSale": "2026-10-13",
  "securitiesTypes": ["Equity"],
  "totalOfferingAmount": 9960000,
  "currency": "USD",
  "offeringAmountIndefinite": false,
  "totalAmountSold": 9960000,
  "totalRemaining": 0,
  "totalInvestors": 38,
  "accessionNumber": "0002161341-26-000001",
  "filingDate": "2026-10-28",
  "filingIndexUrl": "https://www.sec.gov/Archives/edgar/data/2161341/000216134126000001/0002161341-26-000001-index.htm"
}
Enter fullscreen mode Exit fullscreen mode

All five filings were filed on Oct 28, 2026:

Issuer State Offering Sold Investors
Accufy Diagnostics, Inc. MD $2.0M $2.0M 3
Arcline Systems, Inc. TN Indefinite $75K 2
Arms Cyber Defense, Inc. CA $9.96M $9.96M 38
BIOMETRICA HEALTH, INC. MN $2.0M $20K 1
CVAT.ai Corp DE $5.5M $2.5M 2

Two things to notice:

  • Arcline's offering size is null. The issuer reported it as Indefinite, so offeringAmountIndefinite is true. Arms Cyber's yearOfInc is also null because the issuer didn't give a year. Your code should handle both (see Step 3).
  • "Sold" can be much less than "Offering". A Form D is often filed after the first sale, while the round is still open. The gap tells you how much is still being raised.

The run also writes a summary to its key-value store (record SUMMARY):

{
  "indexEntries": 389,
  "filingsChecked": 34,
  "pushed": 5,
  "skippedAlreadySeen": 0,
  "parseErrors": 0
}
Enter fullscreen mode Exit fullscreen mode

filingsChecked is how many Form D documents the Actor fetched and parsed before it reached maxItems. parseErrors counts filings it couldn't read. Newer builds also list indexDaysRead and indexDaysNotPublished, so you can see which EDGAR days were covered. Today's index usually appears in the evening, US Eastern, so a run before then reads only the earlier business days. In a wider test (daysBack: 1, five tech and health industry groups, operating companies, $1M+), Oct 28 alone produced 11 matching filings out of 142 checked.

Step 3: Call it from Python

This runs the Actor synchronously and prints each new filing. It reads your Apify token from an environment variable (never paste it into code). maxTotalChargeUsd caps the run's charges.

import os
import requests

ACTOR = "fedsignals~sec-form-d-monitor"
URL = f"https://api.apify.com/v2/acts/{ACTOR}/run-sync-get-dataset-items"

run_input = {
    "daysBack": 3,
    "industryGroups": ["Other Technology", "Biotechnology"],
    "excludePooledFunds": True,
    "minOfferingAmount": 1000000,
    "onlyNew": True,                    # only filings this stateKey hasn't returned before
    "stateKey": "tech-bio-1m-rounds",   # one key per saved search
    "maxItems": 4,
}

resp = requests.post(
    URL,
    params={"maxTotalChargeUsd": 0.05},
    headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"},
    json=run_input,
    timeout=300,
)
resp.raise_for_status()

def money(x):
    return f"${x:,.0f}" if x is not None else "indefinite"

for n in resp.json():
    investors = n.get("totalInvestors") or 0
    print(
        f"{n['filingDate']}  {n['issuerName']} ({n.get('issuerState') or '??'})  "
        f"offering {money(n.get('totalOfferingAmount'))}, sold {money(n.get('totalAmountSold'))}, "
        f"{investors} investor{'' if investors == 1 else 's'}  {n['filingIndexUrl']}"
    )
Enter fullscreen mode Exit fullscreen mode

Run it twice. The second run returns the next filings, not the same ones: onlyNew remembers every filing delivered for that stateKey.

Step 4: Schedule it daily

EDGAR posts each day's index in the evening (U.S. Eastern), so run it once a weekday night.

  1. In the Apify console, click Save as a new task, set daysBack: 1, onlyNew: true and a stateKey.
  2. Go to Schedules → Create new, use the cron expression 0 22 * * 1-5 with the timezone set to America/New_York, and attach the task.

If a run is missed, raise daysBack for one run to catch up. onlyNew prevents duplicates.

Step 5: Send new rounds to Slack or a webhook

Apify has a built-in Slack integration (Integrations → Slack on your task). For one line per filing, add a webhook for ACTOR.RUN.SUCCEEDED that points at a small function you host. The payload includes resource.defaultDatasetId:

import os
import requests

def handler(payload: dict) -> None:
    dataset_id = payload["resource"]["defaultDatasetId"]
    items = requests.get(
        f"https://api.apify.com/v2/datasets/{dataset_id}/items",
        headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"},
        timeout=60,
    ).json()
    if not items:
        return  # no new filings today

    lines = [f"*{len(items)} new Form D filings*"]
    for n in items[:25]:
        sold = n.get("totalAmountSold")
        offered = n.get("totalOfferingAmount")
        size = f"${offered / 1e6:,.1f}M offered" if offered else "size indefinite"
        raised = f", ${sold / 1e6:,.2f}M sold" if sold else ""
        lines.append(
            f"• <{n['filingIndexUrl']}|{n['issuerName']}> ({n.get('issuerState') or '??'}, "
            f"{n.get('industryGroup') or 'n/a'}): {size}{raised}"
        )
    requests.post(os.environ["SLACK_WEBHOOK_URL"], json={"text": "\n".join(lines)}, timeout=30)
Enter fullscreen mode Exit fullscreen mode

The same webhook can feed Google Sheets, HubSpot, Zapier or Make.

What it costs

The Actor uses pay-per-event pricing: $0.006 per filing delivered ($6 per 1,000), plus Apify's $0.00005 run-start fee. The 5-filing test above costs about $0.03. A daily run that matches about 10 filings costs about $0.06 a day. A night with no new matches costs only the start fee.

FAQ

Do I need an SEC API key?
No. EDGAR is public and keyless. The Actor sends the declared User-Agent the SEC requires and stays under its rate limit. You only need a free Apify account.

Does it return founders' or executives' names?
No. Form D lists "related persons" with names and addresses. The Actor drops them on purpose, along with the issuer's phone number. You get company-level data only.

Is a Form D proof that a company raised money?
It's a notice filed by the issuer, and the SEC doesn't review it. totalAmountSold is what the issuer reported at filing time. Treat it as a strong signal, not audited data.

What do the exemption codes mean?
06b is Rule 506(b), 06c is Rule 506(c) (general solicitation allowed), and 04 is Rule 504.

Can I include funds?
Yes. Leave excludePooledFunds off, or set industryGroups to ["Pooled Investment Fund"] to get only funds.

Is this investment advice?
No. It's a feed of public filings.

Related


Last updated: Nov 5, 2026 (tested against Actor build 0.1.16).

FedSignals Data builds small public-data monitors on Apify. FedSignals is not affiliated with, or endorsed by, the U.S. Securities and Exchange Commission. Questions or feature requests: fedsignals.alerts@gmail.com.

Top comments (0)