Build a provenance check for SEC filing responses

Write a small Node.js check for source URLs, fetch timestamps, stale flags, filing identifiers, and document links without overstating what metadata proves.

WHAT YOU WILL BUILD

Validate the response-level source metadata and document-link shape before storing a filing result. This is an integration sanity check, not a guarantee of authenticity, accounting correctness, or complete history.

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 result = await request("/api/v1/filings?" + new URLSearchParams({
  cik: "320193", form: "10-K", limit: "5"
}));
const source = new URL(result.meta.source);
if (source.protocol !== "https:" || source.hostname !== "data.sec.gov") {
  throw new Error("Unexpected upstream source URL");
}
const fetchedAt = Date.parse(result.meta.fetchedAt);
if (!Number.isFinite(fetchedAt)) throw new Error("Invalid retrieval timestamp");
if (typeof result.meta.stale !== "boolean") throw new Error("Missing stale flag");
const invalidLinks = result.data.filter(row => {
  if (row.documentUrl === null) return false;
  try {
    const url = new URL(row.documentUrl);
    return url.protocol !== "https:" || url.hostname !== "www.sec.gov"
      || !url.pathname.startsWith("/Archives/edgar/data/");
  } catch {
    return true;
  }
});
if (invalidLinks.length) throw new Error("Unexpected document link");
console.log(JSON.stringify({
  checkedAt: new Date().toISOString(),
  source: result.meta.source,
  fetchedAt: result.meta.fetchedAt,
  retrievalAgeSeconds: Math.floor((Date.now() - fetchedAt) / 1000),
  stale: result.meta.stale,
  historyCoverage: result.meta.historyCoverage,
  requestId: result.meta.requestId,
  accessionNumbers: result.data.map(row => row.accessionNumber),
  missingDocumentLinks: result.data.filter(row => row.documentUrl === null).length
}, null, 2));

Check the source envelope, not an invented timestamp

fetchedAt belongs to this service’s response metadata. It records cache retrieval and must not be confused with a last-update field inside SEC submissions JSON. The script parses the value and reports retrieval age without relabeling it as source publication latency. Clock differences can affect a measured age, so treat an unexpected negative value as something to investigate. The stale flag describes how the service served the result; a recent-looking date is not a substitute for checking that explicit state.

Validate links without pretending to verify the document

The code checks HTTPS, the expected hostname, and the EDGAR archive path prefix. It deliberately uses URL parsing rather than a loose string search that could accept a lookalike domain. A link can satisfy these structural checks and still need investigation. This tutorial does not download the original document, compare its content, or cryptographically authenticate it. A null document URL is counted separately because absence and malformed structure are different cases. Preserve that distinction in your logs and interface.

Keep an audit record that helps someone debug

The output contains the request ID, source URL, retrieval timestamp, scope, and accession numbers. Those fields let a support investigation identify the exact integration result without exposing an API key. Keep your own checkedAt timestamp separate from fetchedAt so the act of checking does not make old source data appear new. Do not put the Authorization header into diagnostic output. If you persist these records, define a retention policy appropriate to your application and keep financial interpretation outside this transport-level check.

Decide how failures affect your workflow

A wrong source host or malformed timestamp should fail this integration check visibly. A stale result or missing document link may be acceptable for one research workflow and unacceptable for another, so the example reports those conditions instead of silently selecting a policy for you. An empty recent-filings list does not establish that the issuer has no historical documents. If the request itself fails, the shared request helper throws before any result is analyzed. Add bounded operational recovery only after deciding which errors are transient and how your application should communicate uncertainty.

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 ←