# SEC Form D — Private Offerings & Reported Amount Sold (`yuvalstudios/sec-form-d`) Actor

Recent SEC Form D filings with issuer, offering amount and reported amount sold kept separate. Filter by filing date, first sale, industry and amounts. Source XML links; contact User-Agent required.

- **URL**: https://apify.com/yuvalstudios/sec-form-d.md
- **Developed by:** [Yuval Gabay](https://apify.com/yuvalstudios) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 filing results

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 Form D — Private Offerings & Reported Amount Sold

Local release candidate, version 0.2.0. **Not deployed.** Live SEC retrieval, cloud billing and real-source accuracy still require verification.

Track SEC EDGAR Form D filings and keep the proposed offering amount separate from the amount reported sold. A filing does not prove that a financing round has closed, or that the full offering amount has been raised. The filing date may be much later than the first sale.

### Changes from the restored version

- Adds `minAmountSold` and `firstSaleFrom`; missing or invalid values cannot satisfy these filters.
- Preserves the existing meaning of `minOfferingAmount` / `maxOfferingAmount` as proposed offering size.
- Requires a name/company and genuine contact email in `userAgent` before SEC requests. Placeholder identities and control characters are rejected. Syntax checking cannot prove you own the address.
- Makes pooled-fund exclusion default to `true` in both schema and runtime. It only excludes the `Pooled Investment Fund` industry classification; it does not identify every SPV.
- Rejects non-Form-D/HTML error documents and non-finite numeric values.
- Scopes seen history to the saved-search label and semantic filters. Only successfully delivered records enter the seen list.
- Uses SDK 3.7.2 save-and-charge handling and checks the combined custom/synthetic event cost before output. Custom event count is distinguished from aggregated event count. Billing failures are no longer swallowed.
- Bounds retries; 401/403 do not retry, long Retry-After stops the run rather than retrying early. Serial delay is 200ms. Multiple concurrent instances must still respect SEC's per-user limit together.

### Input

Provide your own contact identity; no invented example identity should be used for live requests. Relevant fields:

| Field | Meaning |
|---|---|
| `userAgent` | Required name/company and genuine contact email |
| `filedFrom`, `filedTo` | Filing-date window in YYYY-MM-DD |
| `daysBack` | Default filing lookback, 0–365, default 3 |
| `minAmountSold` | Minimum amount reported sold in USD |
| `firstSaleFrom` | Minimum reported first-sale date |
| `minOfferingAmount`, `maxOfferingAmount` | Proposed offering amount, not money raised |
| `states`, `industryGroups` | Normalized state codes and exact industry labels |
| `includeAmendments` | Default false |
| `excludePooledFunds` | Default true; classification-based only |
| `maxItems` | 1–10,000, default 200 |
| `newSinceLastRun`, `stateKey` | Optional delivered-record history |

### Local tests

Requires Node 22 or newer and npm. Installing dependencies downloads open-source packages but does not run an Actor in the cloud.

```text
npm ci --ignore-scripts
npm test
npm run test:smoke
```

The smoke test uses the real SDK and a synthetic XML fixture with intercepted HTTP. It does not connect to SEC or charge a user. It creates `.smoke-storage` locally. Run it in a separate clean folder if you need a fresh history; running it again with the same history may skip the fixture, as designed. Do not run the smoke script in the cloud.

`npm start` is different: it starts the real Actor entrypoint and may fetch live SEC data when valid input is supplied. It was not used for live verification here.

### Pricing and limits

The restored listing proposed $0.003 per `result`; the current cloud configuration was not inspected. Deployment requires PPE pricing with a registered `result` event. Synthetic events may also contribute to the total run price. There is no verified income or profit claim.

The summary reports search hits, scanned records, filtered records, delivered results, missing documents, and why the run stopped. Search results have a 10,000-hit window; use smaller date windows when `searchLimitReached` is true.

### State migration and reliability limits

Version 2 uses the named store `sec-form-d-state-v2` and a filter fingerprint. Version 1 state is not imported automatically: the first v2 run may deliver previously seen filings again. Filing-date windows, `maxItems` and contact identity are deliberately excluded from the fingerprint so rolling searches retain history. Change `stateKey` for an independent history.

Run a saved search with a single writer. Concurrent runs using the same fingerprint can race because the store does not provide an atomic deduplication transaction. Output saving, remote charging and state persistence are not a single atomic transaction: a platform failure between those actions can lead to a repeated result on retry. This candidate does not claim exactly-once billing or output.

State persistence on graceful abortion, real SEC access, live account pricing and multi-run concurrency have not been verified. Do not describe the release as production-validated until those checks are complete.

### Primary references

- [SEC Form D](https://www.sec.gov/files/FormD.pdf)
- [SEC developer and fair-access guidance](https://www.sec.gov/about/developer-resources)
- [Apify Actor SDK](https://docs.apify.com/sdk/js/reference/class/Actor)

Not affiliated with the SEC. All fixtures in `test/fixtures` are synthetic.

# Actor input Schema

## `daysBack` (type: `integer`):

Used when no dates are set: fetch Form D filings from the last N days.

## `filedFrom` (type: `string`):

Start of the filing date range, format YYYY-MM-DD.

## `filedTo` (type: `string`):

End of the filing date range, format YYYY-MM-DD.

## `keywords` (type: `string`):

EDGAR full-text search, e.g. "artificial intelligence"

## `states` (type: `array`):

2-letter US state codes of the issuer's business address, e.g. CA, NY. Leave empty for all.

## `industryGroups` (type: `array`):

e.g. Other Technology, Biotechnology, Commercial, REITS and Finance, Pooled Investment Fund, Other Health Care

## `excludePooledFunds` (type: `boolean`):

Skip only filings classified as Pooled Investment Fund. Other SPVs or investment entities may still appear.

## `minOfferingAmount` (type: `integer`):

Minimum total proposed offering amount in USD; not the amount reported sold.

## `maxOfferingAmount` (type: `integer`):

Maximum total proposed offering amount in USD. Indefinite/unknown offering amounts do not pass this filter.

## `includeAmendments` (type: `boolean`):

Also include amended filings (Form D/A).

## `newSinceLastRun` (type: `boolean`):

Only output filings not returned by a previous run that used the same state key.

## `stateKey` (type: `string`):

Saved-search label. Version 2 also fingerprints semantic filters. Filing-date windows and maxItems do not reset history; change this label to start an independent history. Version 1 state is not imported.

## `userAgent` (type: `string`):

Required: your own name/company and a genuine contact email for SEC fair access. Placeholder example.com/.net/.org or header-control characters are rejected before SEC requests.

## `maxItems` (type: `integer`):

Maximum number of filings to output. Each one is billed as a result.

## `minAmountSold` (type: `integer`):

Minimum amount reported sold in the filing. Unknown values do not pass. This does not prove the offering has closed.

## `firstSaleFrom` (type: `string`):

Optional lower bound for the reported first-sale date. Filings with missing first-sale date do not pass. Filing date and first-sale date are different.

## Actor input object example

```json
{
  "daysBack": 3,
  "states": [
    "CA",
    "NY"
  ],
  "excludePooledFunds": true,
  "includeAmendments": false,
  "newSinceLastRun": false,
  "stateKey": "default",
  "maxItems": 200
}
```

# Actor output Schema

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

No description

# 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 = {
    "states": [
        "CA",
        "NY"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("yuvalstudios/sec-form-d").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 = { "states": [
        "CA",
        "NY",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("yuvalstudios/sec-form-d").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 '{
  "states": [
    "CA",
    "NY"
  ]
}' |
apify call yuvalstudios/sec-form-d --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yuvalstudios/sec-form-d"
        }
    }
}
```

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/OsnYHdZAbETW99N5t/builds/914KJ5ibvgITshL81/openapi.json
