# SEC EDGAR Insider Trades (Form 4) & 13F Holdings (`devsolal/edgar-insider-13f`) Actor

- **URL**: https://apify.com/devsolal/edgar-insider-13f.md
- **Developed by:** [David-Solal Chalmeau](https://apify.com/devsolal) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 EDGAR Insider Trades (Form 4) & 13F Holdings

Read the SEC's own filings as flat JSON rows — no API key, no scraping. Two modes:

- **insider** — Form 4 (and optionally 4/A, 5, 5/A) transactions for any US issuer: who traded, their role, the date, the code, shares, price, value and their holding afterwards. One row per reported line: transactions *and* holdings statements, with every reporting owner on joint filings.
- **holdings** — the newest 13F-HR of an institutional manager (by **period of report**, so a late amendment to an old quarter cannot displace the current book): every holding line with CUSIP, shares, reported value, discretion and voting authority. One row per holding line; each row says whether the filing was sliced (`truncated`, `holdingLinesTotal`).

Rows are ready for portfolio monitoring, insider-flow research, compliance checks, dashboards or an AI agent.

### Example input — insider transactions

```json
{ "mode": "insider", "tickers": ["AAPL"], "maxFilingsPerIssuer": 3 }
```

```json
{ "mode": "insider", "ciks": ["320193", "789019"], "forms": ["4", "4/A"], "sinceDate": "2026-01-01", "transactionCodes": ["P", "S"], "includeDerivative": false, "maxRows": 300 }
```

### Example input — 13F holdings

```json
{ "mode": "holdings", "ciks": ["1067983"] }
```

13F mode needs the **manager's CIK** (a filer code, not a ticker — most 13F managers have no ticker). You can find it on the manager's page at sec.gov/edgar/searchedgar/companysearch.

### Example output (real run, one insider row)

```json
{
  "mode": "insider",
  "ticker": "AAPL",
  "issuerCik": "0000320193",
  "issuerName": "Apple Inc.",
  "ownerName": "Newstead Jennifer",
  "ownerCik": "0001780525",
  "officerTitle": "SVP, GC and Government Affairs",
  "isDirector": false,
  "isOfficer": true,
  "isTenPercentOwner": false,
  "formType": "4",
  "filingDate": "2026-10-22",
  "periodOfReport": "2026-10-20",
  "accessionNumber": "0001140361-26-040540",
  "filingUrl": "https://www.sec.gov/Archives/edgar/data/320193/000114036126040540/form4.xml",
  "searchedFrom": "2026-10-02",
  "fetchedAt": "2026-10-28T10:20:41.026Z",
  "rowType": "transaction",
  "isDerivative": false,
  "securityTitle": "Common Stock",
  "transactionDate": "2026-10-20",
  "transactionCode": "S",
  "transactionCodeLabel": "open market or private sale",
  "shares": 2399,
  "pricePerShare": 339.62,
  "totalValue": 814748.38,
  "acquiredDisposed": "D",
  "sharesOwnedAfter": 34795,
  "directOrIndirect": "D",
  "underlyingSecurityTitle": null,
  "ownerCount": 1,
  "reportingOwners": [
    { "name": "Newstead Jennifer", "cik": "0001780525", "officerTitle": "SVP, GC and Government Affairs", "isDirector": false, "isOfficer": true, "isTenPercentOwner": false }
  ]
}
```

### Example output (real run, one 13F holding row)

```json
{
  "mode": "holdings",
  "managerCik": "0001067983",
  "managerName": "BERKSHIRE HATHAWAY INC",
  "formType": "13F-HR",
  "filingDate": "2026-08-14",
  "periodOfReport": "2026-06-30",
  "accessionNumber": "0001193125-26-352200",
  "filingUrl": "https://www.sec.gov/Archives/edgar/data/1067983/000119312526352200/56757.xml",
  "searchedFrom": "2013-01-01",
  "isAmendment": false,
  "issuerName": "ALLY FINL INC",
  "titleOfClass": "COM",
  "cusip": "02005N100",
  "valueReported": 577211815,
  "valueUnit": "dollars",
  "valueUsd": 577211815,
  "shares": 12561737,
  "sharesType": "SH",
  "impliedPricePerShare": 45.95,
  "putCall": null,
  "investmentDiscretion": "DFND",
  "otherManager": "4",
  "votingSole": 12561737,
  "votingShared": 0,
  "votingNone": 0,
  "truncated": false,
  "holdingLinesTotal": 89,
  "fetchedAt": "2026-10-28T10:20:46.458Z"
}
```

### Fields

Shared by every row: `mode`, `fetchedAt`, `searchedFrom` (the first filing date the run actually read for that target; with `sinceDate`, the start of the window searched) and the filing context `formType`, `filingDate`, `accessionNumber`, `filingUrl` (the exact SEC document the row came from).

**Insider rows** add: `ticker`, `issuerCik`, `issuerName`, `ownerName`, `ownerCik`, `officerTitle`, `isDirector`, `isOfficer`, `isTenPercentOwner`, `reportingOwners` (every owner on a joint filing), `ownerCount`, `periodOfReport`, `rowType` (`transaction` or `holding`), `isDerivative`, `securityTitle`, `transactionDate`, `transactionCode`, `transactionCodeLabel`, `shares`, `pricePerShare`, `totalValue`, `acquiredDisposed`, `sharesOwnedAfter`, `directOrIndirect`, `underlyingSecurityTitle`, `truncated`, `filingLinesTotal`.

**13F rows** add: `managerCik`, `managerName`, `periodOfReport`, `isAmendment`, `issuerName`, `titleOfClass`, `cusip`, `valueReported`, `valueUnit`, `valueUsd`, `shares`, `sharesType`, `impliedPricePerShare`, `putCall`, `investmentDiscretion`, `otherManager`, `votingSole`, `votingShared`, `votingNone`, `truncated`, `holdingLinesTotal`.

Field types are explicit, not all strings: 14 are `number`, 6 are `boolean`, `reportingOwners` is an `array`, the other 34 are `string` (the array's elements are `{name, cik, officerTitle, isDirector, isOfficer, isTenPercentOwner}`), and a field the filing does not state is `null`, never a guessed value.

Error rows carry `input` and `error` instead: `TICKER_NOT_FOUND`, `CIK_NOT_FOUND`, `NO_FILINGS`, `NO_13F_FILING`, `NO_INFORMATION_TABLE`, `UPSTREAM_FAILED`, `PARSE_FAILED`, `SKIPPED_MAX_ROWS`. Absence errors (`NO_FILINGS`, `NO_13F_FILING`) also carry `searchedFrom` and name the window in `message`; `SKIPPED_MAX_ROWS` names a target that `maxRows` was reached before, and is free.

### Pricing

Pay per event: a small start fee per run, plus one charge per **delivered row** — one Form 4 / 5 transaction or holding line, or one 13F holding line. Tickers or CIKs that cannot be resolved, filings with nothing to deliver, failed upstream requests and targets `maxRows` was reached before (`SKIPPED_MAX_ROWS`) come back as free error rows and are not charged. If your spending limit is reached the Actor stops cleanly instead of running unpaid. Current prices are shown on this page.

Run stats report what the platform actually did: `deliveredFree` is the shared kit's own counter, and `charged` is the number of events billed. On an unmonetized run — charging available but returning `chargedCount: 0` with no limit — the rows are still delivered and `charged` is 0 (`deliveredFree` stays 0, because the kit counts a row it never billed as delivered, not free); read `charged`, never `delivered`, to know what you paid for.

### Good to know

- **Source:** the official SEC EDGAR endpoints `data.sec.gov/submissions/CIK##########.json`, `www.sec.gov/files/company_tickers.json` and the filing archives under `www.sec.gov/Archives/edgar/data/`. No key, no login, no proxy. This Actor is not affiliated with or endorsed by the U.S. Securities and Exchange Commission.
- **Rate limits:** the SEC fair-access policy allows 10 requests/second. Requests are made one at a time with a ~130 ms pause and identify the Actor with a descriptive User-Agent plus a contact address, as the SEC requires.
- **Coverage:** the submissions JSON lists the ~1,000 most recent filings per CIK. When `sinceDate` reaches further back than that window the Actor also reads the archived submissions files the SEC lists under `filings.files[]` (BRK, for example, goes back to 1998), so an old window is answered from the filings that exist — but only the archives whose own `filingFrom`/`filingTo` range can hold the window are requested (Vanguard lists 14 of them). Each row states the window it came from in `searchedFrom`, and a "nothing found" row names the window it searched.
- **13F values:** the reporting unit follows the **period of report**, not the filing date. Periods before 2023-01-03 report *thousands* of dollars, periods from 2023-01-03 report *dollars*. `valueReported` is the number exactly as filed, `valueUnit` says which unit it is (`thousands`, `dollars`, or `null` when the period is unknown) and `valueUsd` is always the normalised dollar figure. `impliedPricePerShare` is only derived for common shares (`sharesType: "SH"`, no `putCall`): an option's notional or a debt principal makes value ÷ quantity meaningless, so it is `null` there.
- **Sliced runs:** `maxRows` caps a run, and a large 13F (Vanguard's current book has 17,686 holding lines) can exceed it. Every delivered row — holding or insider — therefore carries `truncated` (true when its filing was cut, or when the run stopped at `maxRows` before finishing the targets/filings it was given) plus the filing's own total: `holdingLinesTotal` for 13F rows, `filingLinesTotal` for Form 4 / 5 rows. A target the cap never reached is never dropped silently: it comes back as a free `SKIPPED_MAX_ROWS` error row naming it, and the run stats count it in `skippedTargets`. A slice can therefore never be mistaken for the whole answer.
- **Joint Form 4s:** a filing can name several reporting owners (a parent and its affiliate). `reportingOwners` lists all of them with role flags and `ownerCount` says how many; `ownerName`/`ownerCik`/`officerTitle`/role flags describe the first owner. Form 4s that report only holdings (`<nonDerivativeHolding>`, `<derivativeHolding>`) are delivered too, with `rowType: "holding"` and a null `transactionCode`.
- **Derivative rows** (`isDerivative: true`, e.g. option exercises and RSU vests) often have `pricePerShare: null` when the filing gives only a footnote. They are delivered and charged like any other row unless you set `includeDerivative: false`.
- `forms` defaults to `["4"]` in insider mode (13F-HR in holdings mode). Amendments are opt-in (`4/A`, `13F-HR/A`).
- `maxFilingsPerIssuer` defaults to 10 (hard limit 100); `maxRows` defaults to 500 (hard limit 5000); up to 50 tickers/CIKs per run. A value above a hard limit is applied as the limit and reported back in the run stats (`truncatedInputs`), never silently discarded.
- Insider filings are due within two business days, but filings are filed by companies and individuals: expect occasional corrections, late filings and amendments. Nothing here is investment advice.
- The reporting owner's street address, which appears in the raw Form 4, is deliberately not copied into the output.

# Actor input Schema

## `mode` (type: `string`):

insider = Form 4 insider transactions for an issuer; holdings = latest 13F institutional holdings for a manager CIK.

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

Issuer tickers, for example AAPL. Resolved to a CIK with the official SEC ticker list. Up to 50.

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

SEC Central Index Keys, for example 320193. In insider mode: the issuer. In holdings mode: the 13F filing manager. Up to 50.

## `forms` (type: `array`):

Which ownership forms to read. 4 = statement of changes in beneficial ownership, 5 = annual statement.

## `sinceDate` (type: `string`):

Only filings with a filing date on or after this day (YYYY-MM-DD). When it reaches back further than the ~1,000-filing recent window, the SEC's archived submissions files are read too.

## `maxFilingsPerIssuer` (type: `integer`):

How many matching filings to read per issuer, newest first (hard limit 100; a larger value is applied as 100 and reported in the run stats).

## `transactionCodes` (type: `array`):

Optional filter on SEC transaction codes: P purchase, S sale, A grant/award, M exercise, F tax withholding, G gift. Leave empty for all codes.

## `includeDerivative` (type: `boolean`):

Include derivative-table rows (options, RSUs). Those rows carry isDerivative=true and an underlying security.

## `maxRows` (type: `integer`):

Upper bound on delivered rows in this run (hard limit 5000; a larger value is applied as 5000 and reported in the run stats). Keeps spend predictable; holding rows carry truncated/holdingLinesTotal when a 13F is cut.

## Actor input object example

```json
{
  "mode": "insider",
  "tickers": [
    "AAPL"
  ],
  "forms": [
    "4"
  ],
  "maxFilingsPerIssuer": 10,
  "includeDerivative": true,
  "maxRows": 500
}
```

# Actor output Schema

## `results` (type: `string`):

All delivered rows as dataset items.

# 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": [
        "AAPL"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("devsolal/edgar-insider-13f").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": ["AAPL"] }

# Run the Actor and wait for it to finish
run = client.actor("devsolal/edgar-insider-13f").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": [
    "AAPL"
  ]
}' |
apify call devsolal/edgar-insider-13f --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,devsolal/edgar-insider-13f"
        }
    }
}
```

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/M4lJ0Aff6tHT6WW5p/builds/Uw9fpvb2uoMyCmG5U/openapi.json
