Find and download SEC filing document text

Resolve a filing accession, inspect its real document manifest, and retrieve a bounded page of document text with Node.js.

WHAT YOU WILL BUILD

Use a filing’s accession number to list its actual archive filenames, then request the primary document by name. This prevents guessed archive paths and preserves the original source.

Requirements: Node.js 22 or later; no extra packages. An API key from your dashboard, stored in the SEC_API_KEY environment variable.

Run the workflow

Save this as workflow.mjs and run node workflow.mjs. The production base URL is used by default. Keep credentials out of source control.

// Node.js 22+. Set SEC_API_KEY before running.
const key = process.env.SEC_API_KEY;
if (!key) throw new Error("Set SEC_API_KEY first");
const base = process.env.SEC_API_BASE_URL || "https://sec-api.dev";
async function request(path) {
  const response = await fetch(base + path, {
    headers: { Authorization: "Bearer " + key }
  });
  if (!response.ok) {
    throw new Error("HTTP " + response.status + ": " + await response.text());
  }
  return response.json();
}
const filings = await request("/api/v1/filings?" + new URLSearchParams({
  cik: "320193", form: "10-K", limit: "1"
}));
if (!filings.data.length) throw new Error("No matching recent filing");
const filing = filings.data[0];
const identity = { cik: "320193", accession: filing.accessionNumber };

const manifest = await request("/api/v1/documents?" + new URLSearchParams(identity));
const document = manifest.data.find(row => row.name === filing.primaryDocument);
if (!document) throw new Error("Primary document missing from manifest");
const result = await request("/api/v1/documents?" + new URLSearchParams({
  ...identity, document: document.name, limit: "20000"
}));
console.log(JSON.stringify({document: result.data.document,
  text: result.data.text, pagination: result.pagination, source: result.meta}, null, 2));

Start from an observed accession

The script requests one recent annual filing, then carries its accession number into the document endpoint. It lists the archive manifest before choosing a document. A filing can include exhibits, schemas, and other attachments, so the first filename is not necessarily its primary report. Matching the primaryDocument name from submissions is a deliberate selection rule; if the manifest does not contain it, the script stops.

Know what text retrieval means

The service returns visible text for supported HTML and source text for supported plain or XML files. It does not execute the document’s HTML in your application. This example requests20,000characters, so it can be a partial document. Inspect nextOffset and totalCharacters before passing the result to a downstream tool that assumes it has the entire report. Binary assets and PDFs are outside this endpoint’s supported text formats.

Retain document identity in your storage

Store the selected filename, accession, CIK, source URL, and retrieval metadata with the text. Avoid using only a company name and calendar year as a unique key: the same issuer can file multiple relevant documents and amendments. Keep the original source link available to readers and do not present retrieved text as an independently verified financial statement.

Sources and further reading

The underlying SEC dataset behavior is documented in the official SEC API reference and SEC technical specifications. Response-field names shown here belong to the sec-api.dev endpoint contract. The scripts print actual results and do not embed fabricated filing or financial data.

All tutorials ←