# SEC Filings to Markdown for AI (10-K, 10-Q, 8-K) (`plainpagelabs/sec-edgar-to-markdown`) Actor

Convert SEC 10-K, 10-Q and 8-K filings into clean, section-split markdown with tables and metadata. Official SEC endpoints only.

- **URL**: https://apify.com/plainpagelabs/sec-edgar-to-markdown.md
- **Developed by:** [Plainpage Labs](https://apify.com/plainpagelabs) (community)
- **Categories:** AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 filing converteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Filings to Markdown for AI (10-K, 10-Q, 8-K)

Get clean, structured SEC filing Markdown that AI systems can use immediately, with traceable sources, explicit coverage limits and predictable per-filing pricing. The public Apify Actor is `plainpagelabs/sec-edgar-to-markdown` (Actor ID `xSMbJOguF9LsXfUuu`). Choose `filings` for one nested filing result, `chunks` for token-bounded rows, or `artifacts` for a compact dataset row linking to the complete stored filing. One eligible accession is one billing unit per run, regardless of registrant count or chunk rows; a fully delivered useful partial may qualify, while errors, no-match, not-applicable-only results and incomplete delivery do not. See the [output field reference below](#output-field-reference) for fields and the run summary. The summary is a reporting snapshot, not an Apify invoice. The parser is provided as-is: labels are heuristic and do not promise lossless or complete extraction or accurate financial values. Check important sections and amounts against the original filing. This Actor is not affiliated with the SEC.

### Pricing: $0.003 per filing

You pay $0.003 for each eligible filing successfully delivered ($3 per 1,000). Apify platform usage is included. For example, 1 eligible filing is $0.003, 100 are $0.30 and 1,000 are $3.

One billing unit is one eligible filing accession delivered in a run, regardless of how many registrants it contains or how many chunk rows it creates. A fully delivered, useful partial filing may be eligible; check its coverage warnings. Fetch or conversion errors, `no-match`, not-applicable-only content, and incomplete delivery are not charged.

### Prefilled example

The input form is prefilled with one fixed public filing:

- JPMorgan Chase & Co. 8-K, filed June 24, 2026
- CIK `0000019617`; accession `0001628280-26-045167`
- Main document `jpm-20260624.htm`

The form starts with `tickers: []`, `ciks: ["0000019617"]`, `accessionNumbers: ["0001628280-26-045167"]`, `formTypes: ["8-K"]`, `maxFilings: 1`, `sections: []`, `outputMode: "filings"`, `includeExhibits: false`, `includeFullMarkdown: false`, and `chunkSize: 0`. `sections: []` asks for all detected sections. This sample is a UI prefill only; it does not add a company or accession default to custom API requests. Change or remove the CIK/accession before using a different filing.

If you leave contact blank, we use our own contact. If you supply yours, you’re responsible for its accuracy; use an email you monitor. All contact identities share the same SEC request limiter. Redis-backed global coordination is optional: without complete coordinator settings, the Actor logs `SEC_RATE_LOCAL_ONLY` at INFO and uses an in-process serialized 500 ms start gap that does not coordinate separate runs; if configured Redis becomes unavailable, requests fail closed.

### Use with AI agents (MCP)

Use this tool when an AI agent needs SEC EDGAR 10-K, 10-Q or 8-K text as Markdown or chunks. Connect through the [Apify MCP server](https://docs.apify.com/mcp). Find `plainpagelabs/sec-edgar-to-markdown` with `search-actors`, then inspect its inputs and pricing with `fetch-actor-details`.

Minimal `call-actor` arguments for one exact filing (a real run costing $0.003 if eligible output is delivered; platform usage included):

```json
{
  "actor": "plainpagelabs/sec-edgar-to-markdown",
  "input": {
    "ciks": ["0000019617"],
    "accessionNumbers": ["0001628280-26-045167"],
    "maxFilings": 1,
    "outputMode": "filings"
  },
  "callOptions": { "maxTotalChargeUsd": 0.003 }
}
```

Run limits belong in `callOptions`, outside Actor `input`. `call-actor` returns run status and storage IDs, not Markdown. If still running, wait with `get-actor-run`; do not start another paid run to poll. Read results with `get-dataset-items` (including further pages) and the `RUN_SUMMARY` record with `get-key-value-store-record`; check its `actorRunId`.

Start with `filings` mode. For flat chunk rows, set `outputMode: "chunks"` and `chunkSize: 2000`, leaving full Markdown and exhibits off. Artifacts contain the selected result, not automatically the full document. Check `recordType`, coverage warnings and billing status: useful partial results may be billed; `billed: null` means unknown, not zero. Never blindly restart an uncertain run or charge. See [Apify's MCP tools and result retrieval](https://docs.apify.com/mcp#available-tools).

### Start a run from Python

This standard-library example starts one real filing run, polls its status, and retrieves default-dataset rows and this run’s hashed run-summary key-value record. Set `APIFY_TOKEN` in your shell; email is optional. If supplied, use an accurate, monitored address. When omitted, we use our own contact. `SEC_CONTACT_NAME` is optional and defaults to `Plainpage Labs` in this example. This starts a real hosted run and may incur the filing charge shown above. Do not blindly repeat the start request if its response is uncertain, since the run may already have started.

```python
import hashlib
import json
import os
import time
from urllib.error import HTTPError
from urllib.request import Request, urlopen

API = "https://api.apify.com/v2"
ACTOR_ID = "plainpagelabs~sec-edgar-to-markdown"
TOKEN = os.environ["APIFY_TOKEN"]


def api(method, path, payload=None):
    body = None if payload is None else json.dumps(payload).encode("utf-8")
    request = Request(
        API + path,
        data=body,
        method=method,
        headers={
            "Authorization": f"Bearer {TOKEN}",
            "Content-Type": "application/json",
        },
    )
    with urlopen(request, timeout=30) as response:
        return json.loads(response.read())


input_data = {
    "tickers": [],
    "ciks": ["0000019617"],
    "accessionNumbers": ["0001628280-26-045167"],
    "formTypes": ["8-K"],
    "maxFilings": 1,
    "sections": [],
    "outputMode": "filings",
    "includeExhibits": False,
    "includeFullMarkdown": False,
    "chunkSize": 0,
    "contactName": os.environ.get("SEC_CONTACT_NAME", "Plainpage Labs"),
}
contact_email = os.environ.get("SEC_CONTACT_EMAIL")
if contact_email:
    input_data["contactEmail"] = contact_email
run = api("POST", f"/acts/{ACTOR_ID}/runs", input_data)["data"]
run_id = run["id"]
deadline = time.monotonic() + 900
while run["status"] in {"READY", "RUNNING", "STOPPING", "ABORTING", "TIMING-OUT"}:
    if time.monotonic() >= deadline:
        raise TimeoutError(f"Run is still active; inspect run {run_id} before taking action")
    time.sleep(3)
    run = api("GET", f"/actor-runs/{run_id}")["data"]

dataset_id = run["defaultDatasetId"]
store_id = run["defaultKeyValueStoreId"]
items = api("GET", f"/datasets/{dataset_id}/items?format=json")
summary_key = "RUN_SUMMARY-v1-" + hashlib.sha256(run_id.encode("utf-8")).hexdigest()[:20]
try:
    summary = api("GET", f"/key-value-stores/{store_id}/records/{summary_key}")
except HTTPError as error:
    if error.code != 404:
        raise
    summary = None

print(json.dumps({"runId": run_id, "runStatus": run["status"],
                  "items": items, "runSummary": summary}, indent=2))
```

### Limitations and support

This Actor is not affiliated with or endorsed by the SEC. It is provided as-is; verify amounts against the original filing.

The parser can miss or misplace unusual filing layouts. `complete` and `partial` describe heuristic coverage, not financial accuracy. Cross-reference and multi-registrant gaps are reported when identified, but not every gap can be detected. Some older multi-company filings, including Southern Company's FY2006 10-K filed in 2007, return partial results with a warning identifying missing registrant discussions. Review the original filing before relying on returned text or amounts.

The Actor is designed to operate with Limited permissions and on the current run's default storage. It does not administer a user's account.

For help, use the **Issues** tab on the Actor page in Apify. The repository's GitHub issues are private and are not a public customer-support channel.

### Output field reference

The dataset schema defines the versioned union of dataset rows. Every row requires `schemaVersion: 1`, a semantic-version `appVersion`, and `recordType`: `filing`, `chunk`, `artifact`, or `diagnostic`. `RUN_SUMMARY` is a separate key-value-store record with `recordType: "run-summary"`; it is not part of the dataset-row schema. Coverage and billing eligibility are different: a fully delivered useful partial filing may be billable, while a complete-looking parser result is not proof of financial accuracy. Compare important results with the original filing.

#### Dataset row types

| `recordType` | Output mode | Shape |
| --- | --- | --- |
| `filing` | `filings` | One filing object with filing metadata and a `sections` array. The schema requires `sections`, `filingContentHash`, and `filingChunkCount`. Sections may carry Markdown and/or section-local chunks. A no-match filing still has an explicit status and coverage metadata. |
| `chunk` | `chunks` | One dataset row per emitted chunk, with filing, section, selection, coverage, source and chunk metadata. The schema requires `text`, `contentHash`, `filingContentHash`, and filing-wide chunk index/count. One filing may create many rows. |
| `artifact` | `artifacts` | One compact discovery row that identifies the verified full-filing JSON artifact in the run's default key-value store. The schema requires `artifact`, `outputMode: "artifacts"`, `filingContentHash`, and `filingChunkCount`. The `artifact` object includes `storeId`, `manifestKey`, format, byte length, SHA-256 and part counts. `artifact.sha256` covers the complete serialized archived payload, not the content-only `filingContentHash`. |
| `diagnostic` | Lookup or processing issue | A status/error row for an issue that did not yield a normal filing record. It has schema/version metadata but does not receive an invented source URL or content hash. |

Each eligible filing accession can produce at most one billing event per run, independent of registrant count or dataset row count. A useful partial filing can be eligible after its selected output is completely delivered. Fetch/conversion failures, no-match, not-applicable-only output, and incomplete delivery are not charged. The `billableContent` field describes content eligibility; by itself it does not confirm a charge. See the run-level billing fields below and [Pricing: $0.003 per filing](#pricing-0003-per-filing).

#### Identity and content evidence

| Field | Meaning |
| --- | --- |
| `accessionNumber`, `cik`, `company`, `form`, `filingDate`, `reportDate`, `primaryDocument` | Filing identity and filing metadata when known. |
| `url` | Filing document URL used for retrieval. |
| `sourceUrl` | URL of the section or exhibit source. It can differ from the filing's primary document when content was recovered from an exhibit. |
| `canonicalUrl` | Optional deterministic SEC Archives URL for the primary document, derived only when the filing identity is known and CIK, accession, and document name pass validation. A diagnostic row may include it when that identity is complete; lookup failures without a known identity do not get a fabricated URL. It is not a substitute for section/exhibit `sourceUrl`. |
| `sourceHash` | SHA-256 of the retrieved filing source text. In chunk rows it links the chunk back to the source filing; it is not a checksum of returned Markdown. |
| `contentHash` | SHA-256 of section Markdown or an individual chunk's exact `text`, where present. |
| `filingContentHash` | SHA-256 over a stable JSON projection of delivered text: sections in order with Item identity and Markdown/chunk text, optional top-level Markdown/full Markdown, and optional exhibits in order with present `file`, `type`, `url`, `status`, `markdown`, `error`, and `omissionReason` values. Whitespace and Unicode are significant. Derived metadata such as dates, warnings, and indices are excluded. Different chunk representations can yield different hashes when chunking repeats table headers. |
| `schemaVersion`, `appVersion`, `parserVersion` | Output-contract version, Actor application version and filing parser version. Application and parser versions currently match (`0.4.0`); neither is a hosted-build identifier. |
| `markdown`, `sections[].markdown`, `sections[].chunks[].text` | `includeFullMarkdown:true` adds full converted main-document text in top-level `markdown`. Selected section text is in `sections[].markdown` without chunking, or `sections[].chunks[].text` with chunking. |

In `filings` mode, `filingChunkCount` gives the total chunks across the filing's sections when chunking is enabled. In `chunks` mode, each chunk keeps its section-local `chunkIndex`/`chunkCount` and also has zero-based `filingChunkIndex`/`filingChunkCount` across the whole filing. These indices describe output order; they do not replace `chunkId` or identify source page ranges.

Other coverage evidence can include `status`, `completeness`, `documentCompleteness`, `selectionStatus`, `expectedItems`, `missingItems`, `missingRequestedItems`, `partialRequestedItems`, `warnings`, section `contentStatus`/`detection`, `sourceCoverage`/`sourceCoverageScope`, and index/registrant fields such as `indexPageRanges`, `sourcePageRanges`, `missingSourcePageRanges`, `sourcePageLabels`, `missingSourcePageLabels`, `sourceRegistrant`, `sourceRegistrants`, `missingSourceRegistrants`, and `registrantSourceEvidence`. Page-range fields use exactly two nonnegative integer endpoints in `[first, last]` arrays; they are not objects. `sharedSourcePages` maps source Item keys to the same pair format. Registrant evidence entries can include the filed name, index/source page labels, character-span evidence (`sourceSpans` entries with numeric `start` and `end` offsets), and a body hash. Source mapping can also include `originalSourceItem`, `sourceContentRole`, and overlap details in `sharedContentWith` and `sharedSourcePages`. These fields expose source ranges and known gaps; they do not certify correct extraction. Heuristic status labels report detected coverage, not an audited accuracy score.

For an `artifact` row, retrieve `artifact.manifestKey` from `artifact.storeId` in the run's default key-value store. The manifest lists compressed parts and checksums. Read all parts and verify them before using the reconstructed filing; the exported `readFilingArtifact(store, manifestKey)` helper performs these checks for SDK consumers. A missing or unreadable artifact is not a partial result to consume.

#### `RUN_SUMMARY` record

The Actor writes one cumulative reporting snapshot under the canonical key `RUN_SUMMARY-v1-` followed by the first 20 lowercase hexadecimal characters of SHA-256 over the UTF-8 `actorRunId`. After the canonical record is successfully written and read back, it also writes an exact snapshot copy to `RUN_SUMMARY` in the run's default key-value store; the run output reference links to this display alias. The hashed key remains authoritative and is used for per-run recovery. The alias is never used for recovery or billing. In a shared key-value store, a later run can overwrite the alias, so it may refer to a different or stale run; check `actorRunId` and read the canonical per-run key before relying on it. The summary is not atomic with the filing ledger or dataset writes. A bounded key-value timeout can stop the run with `RUN_SUMMARY_UNAVAILABLE`, but it does not cancel the underlying storage operation. A missing, stale or failed summary read/write is not proof of the ledger state; the filing ledger remains the authority for delivery and charging. The summary never authorizes delivery replay or a charge. Same-run restarts carry forward filing entries and increment `executionCount`.

To read it over the Apify API, derive the key from the run ID using `RUN_SUMMARY-v1-` plus `sha256(actorRunId UTF-8)[:20]`; the [Python example above](#start-a-run-from-python) shows this calculation.

The record has this top-level structure:

| Field | Meaning |
| --- | --- |
| `recordType`, `schemaVersion`, `appVersion` | `run-summary`, schema `1`, and Actor application version `0.4.0`. |
| `actorRunId` | Apify run identity used to derive the per-run key and scope this summary. |
| `status`, `errorCode` | `running` while work is active, then `completed`, `failed`, or `killed`; `errorCode` is the optional machine-readable failure code. |
| `startedAt`, `updatedAt`, `executionCount` | ISO timestamps and number of executions recorded for this same run. |
| `selection` | Input-plan summary: `fingerprint`, `mode` (`explicit-accessions` or `latest-matching`), `maxFilings`, `requestedAccessionCount`, `tickerCount`, `cikCount`, and `planFrozen`. The fingerprint is an identity check, not a user-readable selection list. |
| `counts` | Accession-level `requested`, `selected`, `complete`, `partial`, `unsupported`, `failed`, `skipped`, and `billed` counts; these are not dataset-row counts. `requested` is the distinct explicit-accession count; for latest-matching selection it is `null` until the plan freezes, then reflects the selected plan. Outcome counts summarize recorded `filings[]` entries, which may include unselected discovery failures. `billed` is always `null` while running and remains `null` after a run if charge/accounting is uncertain; unknown is not zero. |
| `execution` | Counts of `skippedAlreadyDelivered` and `resumedCharges`; these explain same-run recovery. |
| `billing` | `status`, `billed`, `confirmedBilled`, `sdkReportedCount`, and `reason`. `confirmedBilled` is the lower bound of individually confirmed filing events. `sdkReportedCount` is a diagnostic aggregate, not a per-filing receipt. If the outcome or accounting cannot be established, `status` is `unknown` and `billed` remains `null`. |
| `filings` | Per-accession results and evidence, one entry per accession rather than one per dataset row. |
| `discoveryIssues` | Lookup/selection diagnostics with a code and message plus any known CIK, input, or accession. |
| `integrityHash` | SHA-256 integrity checksum over the JSON record body without this field. It detects record changes; it does not certify source accuracy or platform billing. |

Each `filings[]` entry includes `accessionNumber`, `selected`, `outcome`, and `reasons` (`code` and `message`). Depending on processing and reconciliation it may also include `cik`, `form`, `contentOutcome`, `contentHash`, `billableContent`, `billingReason`, `delivery`, `ledgerState`, `billed`, and `executionAction`. Outcomes are `complete`, `partial`, `unsupported`, `failed`, `skipped`, or transient `unknown`. While work is in progress, a parsed result keeps its `contentOutcome` but its `outcome` remains `unknown` with `OUTPUT_AWAITING_DELIVERY` until the filing ledger confirms delivery. If the final ledger read is unavailable, `outcome` becomes `failed`, `delivery` becomes `unknown`, `billingReason` is `LEDGER_STATE_UNKNOWN`, and the parser result remains in `contentOutcome`. `billed` is `true` only for a confirmed event, `false` when not charged, and `null` when the result is uncertain. `delivery` is `unstarted`, `confirmed`, or `unknown`; `executionAction` explains a same-run skip or resumed charge when present. `billingReason` can identify `NO_USABLE_CONTENT`, `NOT_APPLICABLE_ONLY`, `UNPRICED_RUN`, `DELIVERY_REQUIRED`, `AWAITING_FIRST_CHARGE`, `CONFIRMED_FILING_EVENT`, `CHARGE_OUTCOME_UNKNOWN`, or `LEDGER_STATE_UNKNOWN`. `OUTPUT_AWAITING_DELIVERY` is a reason code; inspect each reason and the filing row's warnings/source evidence before interpreting a partial outcome.

`billing.status: "confirmed"` means the per-accession ledger and billing accounting are internally consistent; for a pay-per-event run, an available SDK event count must agree with the confirmed ledger charges. `billing.status: "unknown"` means not to infer the total from dataset rows or a partial aggregate; `confirmedBilled` remains the lower bound and `billed` stays `null`, not zero. `sdkReportedCount` is only an aggregate diagnostic, never a per-filing receipt. A `delivery-pending` record means delivery is uncertain, but it cannot have reached the charge-delivered transition: its per-filing `delivery` is `unknown` and `billed` is `false`. If the ledger and SDK both validate zero charged filings, the confirmed billing total can be zero even while that delivery issue still needs review. A `charge-pending` record may have reached the platform and makes billing unknown (`billed: null`); reconcile it through the documented support process, never by retrying from this summary. You pay $0.003 for each eligible filing successfully delivered ($3 per 1,000); Apify platform usage is included. The summary itself is not an Apify invoice.

# Actor input Schema

## `tickers` (type: `array`):

Company stock symbols, for example \["JPM"]. Supply tickers or ciks; neither has an API default. Tickers require an extra SEC lookup. At most 32 characters per ticker and 1000 tickers plus CIKs combined. Clear the sample ciks and accessionNumbers when choosing a different company.

## `ciks` (type: `array`):

SEC company identifiers (Central Index Keys), for example \["0000019617"] for JPMorgan Chase. Use 1 to 10 digits as strings, with or without leading zeros. Supply ciks or tickers; neither has an API default. At most 1000 combined. Clear the sample accessionNumbers when changing company.

## `accessionNumbers` (type: `array`):

Exact SEC filing identifiers, for example \["0001628280-26-045167"]. Also supply that company's ticker or CIK. Up to 1000; standard hyphens are optional. Default is no exact filing filter. When set, formTypes and date filters are ignored, but unsupported forms are still excluded. maxFilings still caps the total.

## `formTypes` (type: `array`):

SEC report types to retrieve: 10-K annual, 10-Q quarterly, 8-K current reports, or their /A amendments. Default is \["10-K","10-Q","8-K"]; add /A forms explicitly for amendments. Example: \["8-K"]. Ignored when accessionNumbers is set. Forms 3, 4 and 5 are unsupported.

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

Optional earliest SEC filing date, inclusive, in YYYY-MM-DD format. Example: "2026-01-01". This is the filing date, not the financial reporting period. Omit for no lower date bound; do not send an empty string. Ignored when accessionNumbers is set.

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

Optional latest SEC filing date, inclusive, in YYYY-MM-DD format. Example: "2026-06-30". This is the filing date, not the financial reporting period. Omit for no upper date bound; do not send an empty string. Ignored when accessionNumbers is set.

## `maxFilings` (type: `integer`):

Maximum filings for the entire run across all companies and exact accessions, newest filing date first. Default and safe starting example: 1; allowed range 1 to 1000. Each eligible delivered filing costs $0.003 ($3 per 1,000), including useful partial results; sections and chunks do not add charges. A new run can bill the same filing again.

## `sections` (type: `array`):

Sections to return. Default and example: \[] for all detected sections. For a 10-K, use \["7"] or \["mdna"] for management discussion; other aliases include risk_factors, business, financial_statements, market_risk, controls, legal_proceedings and cybersecurity. Aliases depend on the form; 10-Q codes include II-1A and 8-K codes include 8.01. Up to 1000 selectors, 64 characters each. Inspect selectionStatus and warnings. No-match results are free. Not-applicable-only selections are free unless includeFullMarkdown delivers substantive full-document content.

## `includeFullMarkdown` (type: `boolean`):

Default and example: false. Set true to add the full converted main document after content exclusions in top-level markdown, alongside the selected sections. This can make a not-applicable-only selection billable when substantive full-document content is delivered. No-match results omit it. Keep false in chunks mode; true is rejected there. Large inline output may exceed the 4 MiB row limit; use artifacts mode for larger results.

## `includeExhibits` (type: `boolean`):

Default and example: false. Set true to also fetch indexed HTML EX-\* exhibits, up to 50 and 32 MiB total. Adds SEC requests; non-HTML files are not converted. Requires usable selected content or billable full-document output. Not-applicable-only selections skip downloads unless substantive full-document output makes the filing billable. Check warnings for omissions. Keep false in chunks mode; true is rejected there. No extra per-exhibit charge.

## `resolveIncorporatedByReference` (type: `boolean`):

Default and example: false. Set true to try recovering missing or referenced 10-K sections from indexed Exhibit 13 annual reports. Adds SEC requests and may still leave partial results. Source links and warnings show what was recovered. This is separate from includeExhibits and can be used with chunks mode. No extra per-exhibit charge.

## `chunkSize` (type: `integer`):

Maximum tokens per returned text chunk. Default: 0 (no chunking). Example: 2000; otherwise use an integer from 100 to 8000. Required above zero with outputMode chunks; in filings or artifacts mode, chunks stay nested inside sections. Tokens use o200k_base, so other models may count differently. Oversized table rows may become flagged tableFragment text. No extra per-chunk charge.

## `outputMode` (type: `string`):

Default and example: filings, returning sections nested in one row per filing. Choose chunks for flat rows with text: also set chunkSize to 100..8000 and leave includeFullMarkdown and includeExhibits false. Choose artifacts for a small row linking to the selected result JSON in the key-value store, not automatically the full document; includeFullMarkdown controls that. Inline rows have a 4 MiB limit; artifacts a 64 MiB limit. Diagnostic/no-match rows can also appear. Keep the default key-value store. One eligible filing costs $0.003 in any mode, not per row.

## `contactName` (type: `string`):

Optional name or company sent to SEC in the User-Agent, at most 200 characters. Default and example: "Plainpage Labs". All requests use the same SEC limiter regardless of the supplied contact.

## `contactEmail` (type: `string`):

Optional. Your monitored email, sent to SEC in the User-Agent. If blank, we use our own contact. If you supply one, you're responsible for its accuracy.

## Actor input object example

```json
{
  "tickers": [
    "JPM"
  ],
  "ciks": [
    "0000019617"
  ],
  "accessionNumbers": [
    "0001628280-26-045167"
  ],
  "formTypes": [
    "8-K"
  ],
  "dateFrom": "2026-01-01",
  "dateTo": "2026-06-30",
  "maxFilings": 1,
  "sections": [],
  "includeFullMarkdown": false,
  "includeExhibits": false,
  "resolveIncorporatedByReference": false,
  "chunkSize": 2000,
  "outputMode": "filings",
  "contactName": "Plainpage Labs"
}
```

# Actor output Schema

## `dataset` (type: `string`):

SEC filing Markdown and source links. filings mode: sections with markdown or nested chunks; chunks mode: flat rows with text and chunk indexes; artifacts mode: references to the stored selected result JSON. Diagnostic/no-match rows can also appear. Inspect recordType, status, completeness, selectionStatus and warnings; do not count rows as billed filings.

## `runSummary` (type: `string`):

Per-filing results and billing summary for this run: requested, complete, partial, unsupported, failed, skipped and billed counts with reasons. billed: null means unknown, not zero. Check actorRunId when reusing storage; RUN_SUMMARY is a display copy. Not an invoice or permission to retry an uncertain charge.

# 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 = {
    "tickers": [],
    "ciks": [
        "0000019617"
    ],
    "accessionNumbers": [
        "0001628280-26-045167"
    ],
    "formTypes": [
        "8-K"
    ],
    "maxFilings": 1,
    "sections": [],
    "includeFullMarkdown": false,
    "includeExhibits": false,
    "resolveIncorporatedByReference": false,
    "chunkSize": 0,
    "outputMode": "filings",
    "contactName": "Plainpage Labs"
};

// Run the Actor and wait for it to finish
const run = await client.actor("plainpagelabs/sec-edgar-to-markdown").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 = {
    "tickers": [],
    "ciks": ["0000019617"],
    "accessionNumbers": ["0001628280-26-045167"],
    "formTypes": ["8-K"],
    "maxFilings": 1,
    "sections": [],
    "includeFullMarkdown": False,
    "includeExhibits": False,
    "resolveIncorporatedByReference": False,
    "chunkSize": 0,
    "outputMode": "filings",
    "contactName": "Plainpage Labs",
}

# Run the Actor and wait for it to finish
run = client.actor("plainpagelabs/sec-edgar-to-markdown").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 '{
  "tickers": [],
  "ciks": [
    "0000019617"
  ],
  "accessionNumbers": [
    "0001628280-26-045167"
  ],
  "formTypes": [
    "8-K"
  ],
  "maxFilings": 1,
  "sections": [],
  "includeFullMarkdown": false,
  "includeExhibits": false,
  "resolveIncorporatedByReference": false,
  "chunkSize": 0,
  "outputMode": "filings",
  "contactName": "Plainpage Labs"
}' |
apify call plainpagelabs/sec-edgar-to-markdown --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,plainpagelabs/sec-edgar-to-markdown"
        }
    }
}
```

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/xSMbJOguF9LsXfUuu/builds/axdvuz4hgexOgZpNz/openapi.json
