Read insider ownership XML without confusing holdings and trades
Find a Form4 accession and inspect parsed ownership records, transaction codes, decimal strings, and source footnotes.
Find a Form4, request the accession’s ownership XML records, and keep recordType beside every row. Holdings and derivative records should not silently become ordinary stock purchases.
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 cik = process.env.SEC_CIK || "320193";
const filings = await request("/api/v1/filings?" + new URLSearchParams({cik, form:"4", limit:"1"}));
if (!filings.data.length) throw new Error("No recent Form 4; choose another reporting CIK");
const result = await request("/api/v1/insider-trades?" + new URLSearchParams({
cik, accession:filings.data[0].accessionNumber, limit:"100"
}));
const byType = {};
for (const row of result.data) (byType[row.recordType] ??= []).push(row);
console.log(JSON.stringify({byType, context:result.meta, pagination:result.pagination}, null, 2));Resolve the reporting document first
The example searches recent Form4 metadata for the chosen CIK. An empty result can be a scope issue; select the relevant reporting entity or use a broader history request rather than assuming no insider activity occurred. The parser can choose an ownership XML only when the manifest identifies it unambiguously. When it cannot, list documents and pass an explicit actual filename.
Keep transaction semantics and precision
recordType separates non-derivative transactions, derivative transactions, and holdings. Transaction codes require interpretation with the filing’s context. The script groups records by type instead of labeling every row a buy or sell. Decimal values remain source strings, which avoids silently losing precision or inventing zeroes for absent values. Apply numeric conversion only in a separate, documented calculation.
Read footnotes and amendments
Footnote identifiers connect table entries to explanatory text in response metadata. Reporting-owner relationships and amendment indicators also matter. Keep them with any exported row. This example does not reconcile amended filings, infer missing transactions, or generate a trading signal. It retrieves one bounded page, so check pagination before counting the full document’s records.
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 ←