Home / Guides / Getting started
Getting started

Use SecFeed from TypeScript and Node.js

A small typed client for the SecFeed SEC EDGAR API in TypeScript, using the fetch built into Node.js. Map a ticker to a CIK and list its latest 10-Q filings.

SecFeed is a plain HTTPS API that returns JSON, so you do not need an SDK to use it from TypeScript. Node.js 18 and later ship fetch, and Node.js 22.18 and later run .ts files directly by stripping the types, so the whole client below is one file with no dependencies and no build step.

What you need

  • Node.js 22.18 or later (or Node.js 18+ with tsx or ts-node to run TypeScript)
  • A SecFeed API key from your dashboard, exported as SECFEED_KEY
export SECFEED_KEY="sf_your_key_here"

A typed client in 40 lines

Save this as secfeed.ts. The interfaces describe the fields this example reads; the API returns a few more, which TypeScript will simply ignore.

// secfeed.ts: a tiny typed client for the SecFeed API (Node 18+ has fetch built in)
const BASE = process.env.SECFEED_BASE ?? "https://secfeedapi.com";
const KEY = process.env.SECFEED_KEY ?? "";

interface Filing {
  accessionNo: string;
  cik: string;
  ticker: string;
  companyName: string;
  formType: string;
  filedAt: string;
  linkToFilingDetails: string;
}

interface FilingSearch {
  total: { value: number; relation: "eq" | "gte" };
  filings: Filing[];
}

interface TickerMatch {
  cik: number;
  name: string;
  ticker: string;
  exchange: string;
}

async function get<T>(path: string, params: Record<string, string | number> = {}): Promise<T> {
  const url = new URL(path, BASE);
  for (const [k, v] of Object.entries(params)) url.searchParams.set(k, String(v));
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${KEY}` },
    signal: AbortSignal.timeout(60_000),
  });
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  return (await res.json()) as T;
}

const [match] = await get<TickerMatch[]>("/v1/mapping/ticker", { ticker: "MSFT" });
console.log(`${match.ticker} -> CIK ${match.cik} (${match.name}, ${match.exchange})`);

const search = await get<FilingSearch>("/v1/filings", {
  query: `cik:${match.cik} AND formType:"10-Q"`,
  size: 3,
});
console.log(`${search.total.value} 10-Q filings (${search.total.relation})`);
for (const f of search.filings) {
  console.log(`${f.filedAt}  ${f.formType}  ${f.accessionNo}`);
}

Run it

node secfeed.ts

Output:

MSFT -> CIK 789019 (MICROSOFT CORP, Nasdaq)
98 10-Q filings (eq)
2026-04-29  10-Q  0001193125-26-191507
2026-01-28  10-Q  0001193125-26-027207
2025-10-29  10-Q  0001193125-25-256321

Microsoft has filed 98 quarterly reports on EDGAR, and the three newest come back first.

How the pieces fit

Authentication. Every request carries Authorization: Bearer <key>. You can also pass ?token=<key> in the URL, which is handy in a browser address bar but easier to leak in logs, so prefer the header in code.

Totals. total.relation is "eq" when the count is exact and "gte" when the API stopped counting at 10,000. Market-wide queries such as every Form 4 ever filed return { value: 10000, relation: "gte" } so the response stays fast.

Timeouts. AbortSignal.timeout(60_000) cancels a request that takes longer than a minute. Most endpoints answer in well under a second; full-text search and PDF rendering take longer.

Paging. /v1/filings returns up to 200 results per call. Pass from to page:

const page2 = await get<FilingSearch>("/v1/filings", {
  query: 'formType:"8-K" AND filedAt:[2026-10-01 TO 2026-10-09]',
  size: 200,
  from: 200,
});

Using it in a browser or edge runtime

The same code works in Deno, Bun, Cloudflare Workers and modern browsers because they all implement fetch. Keep the key on the server: call SecFeed from your backend or an edge function and send only the data your page needs to the browser.

Next steps

More getting started guides

Run this guide with your own key

500 free API calls a month. Every example on this page works on the free plan.

Get free API key →