How to monitor 8-K filings in real time

8-K filings announce material events the moment they happen — earnings surprises, CEO departures, major contracts. This guide shows you how to subscribe to 8-K filings for a list of tickers, filter to the item numbers you actually care about, and receive a real-time push via webhook or poll on a tight schedule.

The problem

An 8-K can move a stock before any analyst publishes a note. The window between SEC acceptance and widespread awareness is often measured in seconds, not minutes. Polling EDGAR directly is possible, but their index files update in batches and their per-filing endpoints are rate-limited at 10 requests per second per IP.

The three item numbers that drive most of the alpha-relevant 8-Ks are:

  • Item 5.02 — departure or appointment of directors and principal officers (CEO/CFO changes)
  • Item 2.02 — results of operations (earnings releases, guidance updates)
  • Item 1.01 — entry into a material definitive agreement (major contracts, partnerships, M&A)

Catching those three within seconds of filing is the whole task.

The approach

EdgarKit gives you two paths:

  1. Webhook — register an endpoint and EdgarKit pushes each matching filing to you as it's accepted. Best for production.
  2. Polling — hit the REST API on a schedule. Easier to prototype; fine for workflows where a 1-5 minute lag is acceptable.

This guide covers both. The webhook approach is the right long-term choice.

Step 1: Register a webhook for 8-K filings

Send a POST to /v1/webhooks with the form types and tickers you want to watch. You can also pass item_numbers to restrict to specific 8-K sections.

curl -X POST "https://api.edgarkit.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/sec-filings",
    "form_types": ["8-K"],
    "tickers": ["NVDA", "AAPL", "TSLA"],
    "item_numbers": ["5.02", "2.02", "1.01"],
    "secret": "your_webhook_signing_secret"
  }'

The response includes a webhook_id you'll use to update or delete the subscription later:

{
  "webhook_id": "wh_a1b2c3d4e5",
  "status": "active",
  "url": "https://your-server.com/webhooks/sec-filings",
  "form_types": ["8-K"],
  "tickers": ["NVDA", "AAPL", "TSLA"],
  "item_numbers": ["5.02", "2.02", "1.01"],
  "created_at": "2026-06-18T12:00:00Z"
}

Keep the secret value in your environment variables. EdgarKit uses it to sign every payload so you can verify it's actually from us — the webhook verification guide walks through the HMAC check.

Step 2: Understand the webhook payload shape

When a matching 8-K is accepted by the SEC, EdgarKit delivers a POST to your URL within seconds. Here's what the payload looks like:

{
  "event": "filing.new",
  "filing": {
    "id": "8k_0001234567_20260618",
    "form_type": "8-K",
    "issuer_ticker": "NVDA",
    "issuer_name": "NVIDIA Corporation",
    "issuer_cik": "0001045810",
    "filed_at": "2026-06-18T14:32:11Z",
    "period_of_report": "2026-06-18",
    "item_numbers": ["2.02", "9.01"],
    "accession_number": "0001045810-26-000123",
    "primary_document_url": "https://www.sec.gov/Archives/edgar/data/1045810/000104581026000123/nvda8k.htm",
    "filing_index_url": "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0001045810"
  },
  "webhook_id": "wh_a1b2c3d4e5",
  "delivered_at": "2026-06-18T14:32:14Z"
}

The item_numbers array contains every item declared in the filing. A single 8-K often covers multiple items (here, 2.02 earnings plus 9.01 financial statements). Your handler can match on whichever items you care about.

Step 3: Poll the API as an alternative

If you're not ready to expose a webhook endpoint, polling is a perfectly workable approach. Hit /v1/filings every 60 seconds with a since timestamp:

curl "https://api.edgarkit.com/v1/filings?form_type=8-K&ticker=NVDA,AAPL,TSLA&item_numbers=5.02,2.02,1.01&since=2026-06-18T14:00:00Z&limit=50" \
  -H "Authorization: Bearer YOUR_API_KEY"

Store the filed_at of the most recent result and use it as since on the next poll to avoid re-processing.

Step 4: Handle a 5.02 executive-change filing

Item 5.02 filings are particularly time-sensitive. Here's a minimal Python handler that checks incoming webhook payloads for 5.02 and logs the alert:

import hmac
import hashlib
import json
import os
from datetime import datetime

SIGNING_SECRET = os.environ["EDGARKIT_WEBHOOK_SECRET"]

def handle_payload(raw_body: bytes, signature_header: str) -> None:
    # Verify signature first (always do this before processing)
    expected = "sha256=" + hmac.new(
        SIGNING_SECRET.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(expected, signature_header):
        raise ValueError("Invalid webhook signature")

    payload = json.loads(raw_body)
    filing = payload["filing"]

    if "5.02" in filing.get("item_numbers", []):
        print(
            f"[{datetime.utcnow().isoformat()}] EXEC CHANGE: "
            f"{filing['issuer_ticker']} filed 8-K item 5.02 "
            f"at {filing['filed_at']} — {filing['primary_document_url']}"
        )

The HMAC verification step is non-optional. Anyone who knows your webhook URL could POST fake payloads without it.

Putting it together

Here's a complete Python polling script that checks every 60 seconds and fires an alert on matching 8-Ks:

import os
import time
import requests
from datetime import datetime, timezone

API_KEY = os.environ["EDGARKIT_API_KEY"]
BASE_URL = "https://api.edgarkit.com/v1/filings"

TICKERS = ["NVDA", "AAPL", "TSLA"]
ITEM_NUMBERS = ["5.02", "2.02", "1.01"]
POLL_INTERVAL = 60  # seconds

def poll(since: str) -> tuple[list[dict], str]:
    params = {
        "form_type": "8-K",
        "ticker": ",".join(TICKERS),
        "item_numbers": ",".join(ITEM_NUMBERS),
        "since": since,
        "limit": 50,
    }
    resp = requests.get(
        BASE_URL,
        params=params,
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=10,
    )
    resp.raise_for_status()
    data = resp.json()
    filings = data["filings"]
    new_since = filings[0]["filed_at"] if filings else since
    return filings, new_since

def main():
    since = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
    print(f"Polling for 8-Ks on {', '.join(TICKERS)} since {since}")

    while True:
        try:
            filings, since = poll(since)
            for f in filings:
                items = ", ".join(f.get("item_numbers", []))
                print(f"[{f['filed_at']}] {f['issuer_ticker']} 8-K — items: {items}")
                print(f"  {f['primary_document_url']}")
        except Exception as e:
            print(f"Poll error: {e}")

        time.sleep(POLL_INTERVAL)

if __name__ == "__main__":
    main()

FAQ

What's the difference between item 2.02 and item 2.01?

Item 2.02 is results of operations — it's the earnings press release wrapper. Item 2.01 is completion of an acquisition or disposition, which is an M&A event. They're easy to mix up; always check the item number, not just the form type.

Can I subscribe to all 8-Ks without filtering by item number?

Yes. Omit the item_numbers field from your webhook registration or polling request. You'll receive every 8-K for your tickers, including boilerplate filings like Item 8.01 (other events) and Item 9.01 (financial statements). Volume goes up significantly for active tickers.

How quickly does an 8-K appear after the company files it?

EdgarKit picks up new filings within roughly 30 seconds of SEC acceptance. The SEC itself typically accepts a filing within a few minutes of submission, so the end-to-end latency from submission to your webhook is usually under 5 minutes.

What happens if my webhook endpoint is down when a filing comes in?

EdgarKit retries failed deliveries with exponential backoff over 24 hours. If your endpoint returns a non-2xx status, the delivery is queued for retry. You can also fetch missed filings retroactively via the polling endpoint using a since timestamp.

Can I filter to a specific executive role in a 5.02 filing?

The item number filter only tells you a 5.02 was filed. To know whether it's a CEO departure versus a board addition, you need to read the filing text itself. Pull primary_document_url and parse the HTML, or check our structured fields in the details object returned with each 8-K (available for common 5.02 patterns).