# SEC Form 8-K Material Event Scraper: Cyber, Bankruptcy, Exec (`groundplanes/sec-edgar-8k-material-event-radar`) Actor

Material corporate events from official SEC EDGAR Form 8-K filings via the EDGAR daily index: cybersecurity incidents (1.05), bankruptcy (1.03), impairments (2.06), accountant changes (4.01) and executive changes (5.02), with cleaned item text. Filter by item code, date, ticker or CIK, and keyword.

- **URL**: https://apify.com/groundplanes/sec-edgar-8k-material-event-radar.md
- **Developed by:** [Groundplane Labs](https://apify.com/groundplanes) (community)
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 filings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## SEC Form 8-K Material Event & Filing Item Text Scraper

Monitor, filter, and extract material corporate disclosures from official U.S. Securities and Exchange Commission (SEC) Form 8-K filings, including cybersecurity incidents (Item 1.05), bankruptcy (1.03), executive leadership changes (5.02), asset impairments (2.06), and accountant changes (4.01), complete with clean, section-sliced item text.

### What it does

- Discovers SEC Form 8-K filings using official EDGAR feeds: either across the entire public market via the EDGAR daily index (form.idx) files or targeted to specific company tickers and CIKs via submission histories.
- Identifies triggered item codes from structured EDGAR metadata before downloading documents.
- Automatically fetches primary filing HTML documents and parses the exact text section for each triggered item code using structured slicing, removing inline XBRL tags and styling.
- Standardizes reporting entity metadata including 10-digit CIK, stock ticker, SIC industry description, headquarters city/state, and official EDGAR acceptance timestamps.
- Filters filings by triggered item codes, date range, company tickers/CIKs, and optional text search keywords.

### Who it's for

- **Corporate Intelligence & M\&A Teams:** Track executive departures, board changes, and material corporate agreements as they are filed.
- **Cybersecurity Researchers & Risk Officers:** Monitor Item 1.05 disclosures to identify material cybersecurity incidents and breach notifications as the daily index posts them (the daily index is updated through the filing day; this is not a real-time feed).
- **Equity Analysts & Quant Funds:** Ingest structured Form 8-K event streams to detect sudden leadership turnover, auditor resignations, or asset impairments.

### Input

Example input configuration (with default spending protection `"maxTotalChargeUsd": 50` in run options):

```json
{
  "customSecUserAgent": "Sample Company AdminContact@example.com",
  "itemCodesFilter": ["1.05", "1.03", "2.06", "4.01", "5.02"],
  "dateFrom": "2026-10-16",
  "dateTo": "2026-10-23",
  "tickersOrCiks": [],
  "keywordInFilingText": "",
  "extractCleanEventText": true,
  "maxItems": 50
}
```

Replace the example User-Agent with your own company name and real contact email before running; the SEC requires a truthful declared User-Agent and placeholder addresses are rejected, so the sample above (a placeholder the actor rejects) must be replaced with your real identity, exactly as in the labeled canary input below.

Recommended Apify run options set a default maximum charge of `$50` (`"maxTotalChargeUsd": 50`).

#### Input Fields

| Field | Type | Description |
|---|---|---|
| `customSecUserAgent` | `string` | **Required.** Your custom User-Agent in the format `User-Agent: Sample Company Name AdminContact@example.com` per SEC fair-access policy. Placeholder email domains are rejected: example, sample, or yourdomain in any form, at any TLD or subdomain (for example example.com, acme.example, sample.org, yourdomain.org). |
| `itemCodesFilter` | `string[]` | Form 8-K item codes to monitor (e.g. `1.05`, `1.03`, `2.06`, `4.01`, `5.02`). Empty = all 8-K items. |
| `dateFrom` | `string` | Earliest filing date (`YYYY-MM-DD`). Default: run date minus 7 days. |
| `dateTo` | `string` | Latest filing date (`YYYY-MM-DD`). Default: run date. |
| `tickersOrCiks` | `string[]` | Optional list of tickers (e.g. `AAPL`, `MSFT`) or 10-digit CIKs. Empty = scan all public filers. |
| `keywordInFilingText` | `string` | Optional case-insensitive keyword filter applied to the full filing body text (the whole primary document text, not only the extracted item section). Rows excluded by this filter are counted in the run status as keywordExcluded, so matched and emitted counts reconcile. |
| `extractCleanEventText` | `boolean` | When true, extracts and slices clean item section text from primary filing HTML. When false, `extractedItemText` is null on every row by your choice and the run status notes the opt-out (no extraction gap is implied). |
| `maxItems` | `integer` | Maximum number of filing records to return. If the cap truncates the matched set, the run ends PARTIAL and states the matched and delivered counts. |

### Output

| Field | Type | Description |
|---|---|---|
| `accessionNumber` | `string` | Unique SEC 20-character accession number (`0001193125-26-430512`) |
| `cik` | `string` | 10-digit Central Index Key (CIK) |
| `ticker` | `string\|null` | Stock ticker symbol |
| `companyName` | `string` | Official corporate entity name |
| `formType` | `string` | Form type (`8-K` or `8-K/A`) |
| `isAmendment` | `boolean` | True if the filing is an amendment (`8-K/A`) |
| `filingDate` | `string` | Official filing date (`YYYY-MM-DD`) |
| `acceptedTimestampEst` | `string` | EDGAR acceptance timestamp (Eastern) |
| `triggeredItemCodes` | `string[]` | Item codes triggered (e.g. `["5.02", "9.01"]`) |
| `triggeredItemDescriptions` | `string[]` | Official SEC item descriptions |
| `sicCode` | `string\|null` | Standard Industrial Classification description and code |
| `hqLocation` | `string\|null` | Principal corporate headquarters location |
| `extractedItemText` | `string\|null` | Cleaned, structured item text extracted from the filing. Null when no text could be isolated (the run status states the gap), or when `extractCleanEventText` is false (the run status notes the opt-out; no gap is implied). |
| `filingHtmlUrl` | `string` | Direct URL to the primary filing HTML document |

#### Sample Output Record (Synthetic Example)

```json
{
  "accessionNumber": "0001193125-26-000000",
  "cik": "0001234567",
  "ticker": "ACME",
  "companyName": "Acme Global Technologies Inc.",
  "formType": "8-K",
  "isAmendment": false,
  "filingDate": "2026-10-23",
  "acceptedTimestampEst": "2026-10-23T16:30:00 EST",
  "triggeredItemCodes": ["5.02"],
  "triggeredItemDescriptions": [
    "Departure of Directors or Certain Officers; Election of Directors; Appointment of Certain Officers; Compensatory Arrangements of Certain Officers"
  ],
  "sicCode": "SERVICES-PREPACKAGED SOFTWARE [7372]",
  "hqLocation": "SAN JOSE, CA",
  "extractedItemText": "[Item 5.02 Departure of Directors or Certain Officers; Election of Directors]\nOn October 20, 2026, Jane Doe notified Acme Global Technologies Inc. of her decision to step down from the Board of Directors effective immediately.",
  "filingHtmlUrl": "https://www.sec.gov/Archives/edgar/data/1234567/000119312526000000/acme-20261023.htm"
}
```

#### Labeled canary input (small, fast check)

```json
{
  "customSecUserAgent": "Sample Company AdminContact@example.com",
  "tickersOrCiks": ["AAPL", "MSFT"],
  "itemCodesFilter": ["5.02", "2.02"],
  "extractCleanEventText": true,
  "maxItems": 5
}
```

Replace the canary User-Agent with your own company name and real contact email before running; the SEC requires a truthful declared User-Agent and placeholder addresses are rejected.

### How pricing works

Pay per result. You only pay for rows returned.

### Data source and terms

- **Official Source:** [U.S. Securities and Exchange Commission (SEC) EDGAR System](https://www.sec.gov/edgar)
- **Policy Compliance:** Built in accordance with the [SEC EDGAR Access Policy](https://www.sec.gov/os/accessing-edgar-data). Requires a declared user-agent and enforces request pacing ($\le 5\text{ req/s}$, well under the SEC limit of 10 req/s).
- This Actor is an independent tool and is not affiliated with or endorsed by the U.S. Securities and Exchange Commission (SEC).

### Limits and FAQ

- **Declared User-Agent:** SEC fair-access policy requires all automated systems to declare their identity and contact email. Enter your real email in `customSecUserAgent`.
- **Item text slicing:** The scraper anchors section slicing to real item headings (the item code plus its official title) and validates each slice. If a printer's HTML layout prevents exact slicing for an item, the full cleaned body text is returned (capped at 15,000 characters) and marked `[UNSLICED BODY TEXT]`, or the row ships null text with the gap counted in the run status.
- **Date window caps:** a market-wide scan accepts a window of at most 90 days; a per-CIK scan (`tickersOrCiks` set) accepts at most 365 days. Wider windows are rejected as invalid input.
- **Long runs:** rows are pushed to the dataset incrementally as they are extracted, so a run that hits the platform timeout on a long window leaves the rows completed so far in the dataset instead of an empty dataset. A single market day takes roughly a minute; the full 90-day market window is a long run, so narrow the window or use `tickersOrCiks` when you only need specific filers.
- Found a problem or need a field? Open an issue on the Issues tab; we respond quickly.

### Troubleshooting

- **Zero matches:** a healthy scan with no filings matching your filters ends as `Complete: 0 material event filings matched your filters`, with the candidate count stated. Widen the date window, add item codes, or clear the keyword filter.
- **PARTIAL runs:** the status message states the concrete reason and the counts (candidates discovered, matched, emitted, skipped). Reasons caused by the source (header drift, fetch failures, unextractable item text) carry the Issues line; caps you set yourself (maxItems, charge limit) do not.
- **Caps:** if maxItems or the run charge limit truncates the matched set, the run ends PARTIAL and states how many filings matched versus how many were delivered. Raise the cap to get the rest.
- **Missing item text:** if a filing document cannot be fetched or its item section cannot be isolated, the row is still delivered with its metadata and `extractedItemText` null; the status message states how many rows are affected.
- **User-Agent errors:** the run fails before any request if `customSecUserAgent` is missing, blank, or uses a placeholder email domain. Supply your real company name and contact email.

### Changelog

- **v0.1.2**: Fix round. Keyword-filtered runs now count keyword exclusions in the status so matched and emitted reconcile. Item description table rebuilt from live disseminated EDGAR header wording: Item 5.05 corrected, Item 6.01 corrected to "ABS Informational and Computational Material", Items 6.02 to 6.05 added, and the live Item 5.08 wording "Shareholder Nominations Pursuant to Exchange Act Rule 14a-11" aliased. Item text slicing is anchored to real item headings with slice validation (no cross-reference fragments, no signature or exhibit-index contamination, 15,000 character cap enforced), with counted fallbacks. Placeholder User-Agent gate strengthened (example, sample, and yourdomain rejected in any form) and the example inputs now use a placeholder with a replace instruction. Rows are pushed incrementally during extraction. A single ITEM INFORMATION line carrying two descriptions now yields both item codes. candidatesDiscovered means the same on both discovery paths. extractCleanEventText false is noted in the status as a buyer opt-out. Window caps (90 days market, 365 days per-CIK) documented.
- **v0.1.1**: Review fixes. Restored the .actor package files (actor.json and schemas shipped empty in v0.1). Spec input name `tickersOrCiks` honored (the delivered build read a different name and ignored it). dateFrom and dateTo now default to the run date minus 7 days and the run date instead of hardcoded October 2026 dates. Retry standard unified to 6 tries with jittered backoff and Retry-After honored. Zero matches now ends Complete with counts instead of failing. Header failures, unparsed item values, and schema skips are counted and reported as PARTIAL reasons instead of being silently dropped. Item text is never fabricated: failed extractions ship null with the gap stated. maxItems and charge caps end PARTIAL without the Issues line (user limits only); the Issues line appears only on source-caused PARTIALs.
- **v0.1**: Initial release with EDGAR daily index discovery, CIK/ticker resolution, structured item filtering, and clean HTML section extraction.

# Actor input Schema

## `customSecUserAgent` (type: `string`):

Required by SEC fair-access rules: a truthful User-Agent naming the operator with a real contact email, in the format 'Sample Company AdminContact@example.com'. Replace that sample with your own company name and real contact email before running: placeholder domains (example, sample, or yourdomain in any form, at any TLD) are rejected. A run without it fails before any request is made.

## `dateFrom` (type: `string`):

Earliest filing date in YYYY-MM-DD format. Leave empty for the run date minus 7 days.

## `dateTo` (type: `string`):

Latest filing date in YYYY-MM-DD format. Leave empty for the run date.

## `extractCleanEventText` (type: `boolean`):

When true, the triggered item sections are sliced and cleaned from the primary filing document and shipped as extractedItemText. When a section cannot be isolated, the full cleaned body is returned capped at 15,000 characters and flagged as unsliced.

## `itemCodesFilter` (type: `array`):

Form 8-K item codes to keep (e.g. 1.05 material cybersecurity incidents, 1.03 bankruptcy, 2.06 material impairments, 4.01 accountant change, 5.02 officer or director change). Empty keeps all items.

## `keywordInFilingText` (type: `string`):

Optional case-insensitive keyword that must appear in the full filing text.

## `maxItems` (type: `integer`):

Maximum number of filing records to return. When the cap truncates the matched set, the run ends PARTIAL stating the matched and delivered counts.

## `tickersOrCiks` (type: `array`):

Optional ticker symbols (e.g. AAPL) or CIKs. When non-empty, discovery switches to the per-CIK submissions path for those filers only. Empty scans the whole market through the daily index.

## Actor input object example

```json
{
  "extractCleanEventText": true,
  "itemCodesFilter": [
    "1.05",
    "1.03",
    "2.06",
    "4.01",
    "5.02"
  ],
  "keywordInFilingText": "",
  "maxItems": 200,
  "tickersOrCiks": []
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "extractCleanEventText": true,
    "itemCodesFilter": [
        "1.05",
        "1.03",
        "2.06",
        "4.01",
        "5.02"
    ],
    "keywordInFilingText": "",
    "maxItems": 200,
    "tickersOrCiks": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("groundplanes/sec-edgar-8k-material-event-radar").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "extractCleanEventText": True,
    "itemCodesFilter": [
        "1.05",
        "1.03",
        "2.06",
        "4.01",
        "5.02",
    ],
    "keywordInFilingText": "",
    "maxItems": 200,
    "tickersOrCiks": [],
}

# Run the Actor and wait for it to finish
run = client.actor("groundplanes/sec-edgar-8k-material-event-radar").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "extractCleanEventText": true,
  "itemCodesFilter": [
    "1.05",
    "1.03",
    "2.06",
    "4.01",
    "5.02"
  ],
  "keywordInFilingText": "",
  "maxItems": 200,
  "tickersOrCiks": []
}' |
apify call groundplanes/sec-edgar-8k-material-event-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,groundplanes/sec-edgar-8k-material-event-radar"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ekRHqOnM56mxfjt5v/builds/gDHeREVkXNtpiXhdw/openapi.json
