# SEC Form D Offering Monitor - Filings & Amendment Changes (`maydit/sec-form-d-offering-monitor`) Actor

Track official Form D offerings and amendments with co-issuer deduplication, reported sales, first-sale dates and verified predecessor comparisons. Export source-linked observations and saved changes.

- **URL**: https://apify.com/maydit/sec-form-d-offering-monitor.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 saved observations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Offering Monitor

Turn official private-offering notices into a review queue with clear dates, reported amounts and source evidence. This Actor reads SEC Form D and D/A XML, combines co-issuer duplicates, and can compare an amendment with the previous filing it explicitly names.

Built for investment operations, company research and B2B teams that need to review offering activity without maintaining an EDGAR parser.

### Start with five recent filings

No API key is needed. Run this input:

```json
{
  "maxResults": 5
}
```

Open **Offering observations** for the rows, **Scope and diagnostics** for machine-readable coverage, and **Readable run report** for the HTML summary. The default reads one recent feed response and saves up to five validated filings.

The feed is a moving window. If your filters match nothing, the run can legitimately return zero rows.

### What the output tells you

| Field | Meaning |
| --- | --- |
| `accessionNumber` | Stable filing identity. Co-issuer copies are combined. |
| `issuerName`, `primaryIssuerCik`, `issuers` | Primary issuer and all issuer identities declared in the XML. |
| `filedDate` | SEC filing date from the accession index. |
| `firstSaleDate`, `firstSaleYetToOccur` | First-sale date, or an explicit flag that a first sale has not occurred. |
| `amountSoldUsd` | Cumulative reported amount sold for this offering. |
| `totalOfferingAmountUsd`, `offeringAmountIndefinite` | Numeric offering amount, or null with an indefinite flag. Null is never converted to zero. |
| `totalRemainingUsd`, `remainingAmountIndefinite` | Remaining amount using the same distinction. |
| `industry`, `investmentFundType`, `securityTypes`, `exemptions` | Source classifications for screening and routing. |
| `totalInvestors`, `minimumInvestmentUsd` | Reported count and minimum accepted investment. |
| `previousAccessionNumber` | Predecessor explicitly identified by an amendment, when present. |
| `amendmentComparison` | Optional verified predecessor comparison: changed fields, previous values and reported amount/count differences. |
| `comparisonStatus`, `changedFields`, `previousObservedAt`, `previous` | Comparison with your saved observation of the same accession. |
| `url`, `sourceUrl`, `contentHash`, `observedAt` | Filing index, raw XML, stable snapshot hash and observation time. |

Related-person contact details, phone numbers and street addresses are not exported.

### Compare a real amendment

This example uses a real filing dated November 2, 2026. Its first sale dates to 2014, illustrating why a fresh filing must not be labeled a newly completed funding round.

```json
{
  "filingUrls": [
    "https://www.sec.gov/Archives/edgar/data/1620980/000162098026000001/0001620980-26-000001-index.htm"
  ],
  "includePredecessor": true,
  "maxResults": 3
}
```

A successfully fetched, identity-verified predecessor produces `amendmentComparison.status: "verified"`. Its `amountSoldChangeUsd` compares two cumulative reported values; it does not prove that new cash arrived during that interval. Negative changes remain visible.

Predecessor requests need at least 15 seconds and two requests left. If comparison cannot be completed, current filing facts can still be saved with a reason and SUMMARY marks incomplete coverage. A filing that supplies no predecessor accession is labeled `no_linked_accession`.

### Understand pre-sale and co-issuer records

```json
{
  "filingUrls": [
    "https://www.sec.gov/Archives/edgar/data/2155461/000215546126000003/0002155461-26-000003-index.htm"
  ],
  "maxResults": 3
}
```

This retained example declares two issuers, a first sale yet to occur, zero amount sold and an indefinite offering amount. One accession produces one observation.

### Build a recurring workflow

1. Use the recent feed for discovery or exact filing-index URLs for repeatable checks.
2. Filter by source industry, primary issuer state/country code, filing date or minimum reported amount sold.
3. Enable `comparePrevious` and reuse the same `snapshotName` and scope. First observations are labeled `new`.
4. Send confirmed rows to a sheet or review system with `accessionNumber` as the deduplication key. Use `contentHash` to avoid processing the same observation twice.
5. Enable `onlyChanges` after establishing a baseline. Check SUMMARY before interpreting a quiet run.

Two comparisons serve different purposes: `comparisonStatus` compares the same accession with your saved run; `amendmentComparison` compares a D/A accession with its explicitly linked older filing. An amendment normally has a new accession, so it first appears as `new` in saved monitoring.

History advances only for confirmed saved rows. Failed or spend-rejected rows never advance it. Use one writer per history scope. An optimistic conflict check protects an already changed baseline, but is not a distributed lock. Missing filings never imply a withdrawn offering or deleted issuer.

With a small output cap, an `onlyChanges` repeat may reach previously unseen filings further down the same feed. Use a complete bounded explicit URL list when proving a no-change repeat.

### Price and limits

The intended Store price is **$0.005 per validated filing observation**, plus **$0.00005 per Actor start event**. The platform scales start events by allocated memory, with a minimum of one; applicable plan discounts appear on the Store pricing panel. Five observations cost $0.025 in result charges before the start fee. Set Apify's maximum run charge to control spend. Unchanged skipped records and diagnostics are not paid rows.

Defaults: five saved filings, one feed of up to 100 entries, 40 source requests and a 60-second budget. Explicit lists allow up to 25 filing URLs; the output maximum is 50. Requests are serial, paced at least 200 ms apart, capped at 2 MiB each and share the remaining deadline. A 403 or 429 stops further SEC requests without route changes. Explicit transient connection failures and HTTP 502/503/504 can receive one retry inside the same time and request caps; SUMMARY records each retry.

A result cap can end a healthy sample with `status: "ok"` while `selectedWindowComplete` remains false. `remainingFilingsInWindow` records the unprocessed portion. Time, spending, source, request and requested-predecessor limits are visible separately. An all-source failure fails the run rather than producing paid error rows.

### Read offering data in context

- Form D is an offering notice, not an SEC approval, investment recommendation or proof of a closed round.
- A notice may precede the first sale. Annual amendments may describe an offering that began years ago.
- Changes in amount sold alone do not always require an amendment. This is not a complete ledger of fundraising activity.
- Filters apply within the selected response or URLs. Date filters do not backfill older EDGAR history.
- The SEC `type=D` feed also returns other D-prefixed forms. Only exact D and D/A categories are retained.
- Government source availability and corrections can change. Local checks do not guarantee access from every cloud IP.

### References and support

[SEC Form D overview](https://www.sec.gov/resources-small-businesses/capital-raising-building-blocks/what-form-d) | [Form D guide](https://www.sec.gov/files/formdguide.htm) | [EDGAR RSS guidance](https://www.sec.gov/files/about/secrss.shtml) | [EDGAR developer guidance](https://www.sec.gov/search-filings/edgar-application-programming-interfaces)

Open an Actor issue with the run URL and affected accession, or email **bmay@mayd-it.com**. Keep credentials and private customer data out of support messages.

# Actor input Schema

## `filingUrls` (type: `array`):

Optional: up to 25 https://www.sec.gov/Archives/edgar/data/.../...-index.htm URLs. Leave empty for one recent feed response. Each accession produces at most one row, including co-issuers.

## `maxResults` (type: `integer`):

Maximum confirmed observations. A result cap is a sample, not proof that every feed filing was processed.

## `includePredecessor` (type: `boolean`):

For D/A only, fetch its linked previous accession when at least 15 seconds and 2 requests remain. Shows cumulative reported differences. Unavailable comparisons are flagged.

## `formTypes` (type: `array`):

Exact D, D/A or both. Other D-prefixed forms are excluded.

## `industries` (type: `array`):

Case-insensitive substring match on source industry group, such as Oil and Gas or Pooled Investment Fund. Applies only within the selected feed or URLs.

## `issuerStates` (type: `array`):

Two-character SEC codes, such as TX or CA. Matches primary issuer business location, not every co-issuer or investor.

## `minAmountSoldUsd` (type: `number`):

Cumulative amountSoldUsd. Zero includes pre-sale offerings. Not a funding-round size or an amount raised since the previous run.

## `filedSince` (type: `string`):

Optional YYYY-MM-DD filter on SEC filing date, not first sale. Does not backfill older history.

## `filedUntil` (type: `string`):

Optional YYYY-MM-DD filter on SEC filing date.

## `comparePrevious` (type: `boolean`):

First run establishes history only for confirmed saved filings. Later runs classify the same accession as new, changed or unchanged. Separate from predecessor comparison.

## `onlyChanges` (type: `boolean`):

Enables comparison and skips unchanged accessions. Zero rows can be valid. With a small output cap, later runs may find unseen filings further down the feed.

## `snapshotName` (type: `string`):

Use 1-80 letters, numbers, underscores or hyphens. One writer per scope; an optimistic conflict check detects already changed history but is not a distributed lock.

## `feedEntries` (type: `integer`):

10-100 entries from one SEC Atom response. Exact form filtering and co-issuer deduplication can leave fewer filings. No historical pagination.

## `maxRequests` (type: `integer`):

Hard cap including feed, indices, XML and optional predecessors. No retries on 403/429. Serial requests are paced at least 200 ms apart.

## `maxRunSeconds` (type: `integer`):

Source work shares this deadline, with shutdown and platform timeout reserves. A time stop is reported as incomplete.

## Actor input object example

```json
{
  "filingUrls": [],
  "maxResults": 5,
  "includePredecessor": false,
  "formTypes": [
    "D",
    "D/A"
  ],
  "industries": [],
  "issuerStates": [],
  "minAmountSoldUsd": 0,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "feedEntries": 100,
  "maxRequests": 40,
  "maxRunSeconds": 60
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `report` (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 = {
    "filingUrls": []
};

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

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

```

## MCP server setup

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

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/FPD8bO3el2TcC79dN/builds/jElwd5pSNLw6As8Gz/openapi.json
