# Company Buying Signals: Hiring, SEC Filings & News (`s3nafps/company-why-now-signals`) Actor

Find why a company is worth contacting now: hiring spikes, SEC filings and news, ranked with dates and source URLs. Use this when a sales agent needs cited reasons to reach out. From $0.03.

- **URL**: https://apify.com/s3nafps/company-why-now-signals.md
- **Developed by:** [mohamed senator](https://apify.com/s3nafps) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $100.00 / 1,000 why-now packs

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

## Company Why-Now Signals (MCP) — Hiring, SEC Filings, News with Sources

**Use this tool when** an AI agent (or a person) needs to know *why a company is worth contacting right now* and wants evidence it can cite: who is hiring and for which senior roles, what the company just filed with the SEC, and what the news says (funding, layoffs, leadership change, M\&A, launches, expansion, legal). Input is a company **domain** (plus an optional name or ticker). Output is compact JSON: an entity with a confidence score, dated signals — each with a source URL, fetch time and confidence — and, in `why_now_pack`, a ranked **top 3 reasons to reach out now** with `whyNow` text and machine-readable `actions`.

![Company Why Now Signals demo](https://s3nafps.github.io/media/company-why-now-signals/promo.gif)

[▶ Watch the full video](https://s3nafps.github.io/media/company-why-now-signals/promo.mp4)

It is a normal pay-per-event (PPE) Actor — **not** Standby — so it works from the Apify MCP server (`https://mcp.apify.com`), the API, schedules and agent-payment flows. Everything is built from passive public data (the company's own public pages, public job-board APIs, SEC EDGAR, GDELT). Classification and ranking are **rule-based; no LLM is involved**, so results are deterministic and every signal can be traced to its source.

![Hiring, SEC filings and news combined into a ranked answer with timing and suggested actions](https://s3nafps.github.io/media/company-why-now-signals/whynow-1.png)

### Modes (one tool per mode)

| `mode` | Use it to… | Returns |
| --- | --- | --- |
| `why_now_pack` | Get everything and the ranked answer in one call | hiring + filings + news signals, top-3 ranking with evidence, timing score, `actions` |
| `hiring` | See growth and senior hires | ATS detected, open roles by department/location, new roles since a date, senior and first-in-function hires |
| `filings` | Catch corporate events | recent 8-K, 10-K/10-Q, S-1 and Form D filings with item codes translated to plain English |
| `news` | Catch announced events | GDELT news classified into funding, layoffs, leadership change, M\&A, product launch, expansion, legal; syndicated copies merged |

#### Calling it from an MCP client

```json
{ "tool": "<your-username>/company-why-now-signals", "arguments": { "mode": "why_now_pack", "domain": "acme-widgets.example", "since": "2026-09-01" } }
```

For scheduled monitoring, pass `since` = the date of your last run: only signals newer than it are returned (and only those are billed).

### Entity resolution comes first

1. The homepage is read (respecting `robots.txt`): JSON-LD `Organization`, `og:site_name`, `<title>`, the © line and the domain label give name candidates.
2. Candidates are matched against SEC `company_tickers.json` (and the ticker you pass, if any). Private companies that file Form D are looked up by exact name in EDGAR.
3. `entity.confidence` (0–1) is the noisy-OR of the evidence weights, listed in `entity.evidence` (type, value, weight, source). A name you pass is accepted at 0.6 unless the site clearly says something else, in which case the match is flagged and capped at 0.55.

**Below 0.6 the match is `lowConfidence`.** Signals that depend on the name (**filings** and **news**) are still returned but labelled `lowConfidence: true` and are **never charged**; the item gets `outcome: "no_match"` with `reason: "low_confidence_entity_match…"`. Hiring signals come from the company's own site/ATS and do not depend on the name match. Fix a low-confidence match by passing `companyName` and/or `ticker`.

### Output at a glance

![Example output: ranked signals, each with its source, and a hot, warm or cold score](https://s3nafps.github.io/media/company-why-now-signals/whynow-2.png)

- `outcome` — `found` | `no_match` | `unavailable` | `error`. **Only `found` is ever charged.**
- `entity` — name, legal name, `confidence`, `lowConfidence`, `evidence[]`, `sec` (CIK, ticker, match type).
- `signals[]` — `{ id, mode, kind, title, date, strength, confidence, lowConfidence, source{url,fetchedAt}, evidence[], data }`.
- `topSignals[]` (pack) — `{ rank, headline, whyNow, date, score, confidence, source, evidence, corroboratedBy }`. Ranking = strength × recency (21-day half-life) × confidence, with a bonus when another source corroborates the same event (e.g. funding news + Form D) and a discount for repeating the same kind.
- `actions[]` — `{ id, priority, type: "reach_out", basedOn, text }`.
- `score` — `{ value 0–100, label hot | warm | cold }` timing score from the top signals.
- `sources[]` — URL and fetch time for every fact.

> The examples below were produced from the project's offline test fixtures for the **fictional company "Acme Widgets, Inc." (`acme-widgets.example`)**. They show the exact shape of real output (long arrays are shortened with `"..."`), not measurements of a real company.

#### `why_now_pack` — $0.10

```json
{
  "domain": "acme-widgets.example",
  "mode": "why_now_pack",
  "outcome": "found",
  "summary": "Acme Widgets (acme-widgets.example): timing hot (75/100). Top reasons to reach out now: 1) 8-K filed 2026-10-02: Executive or board change (5.02, 9.01) [2026-10-02]; 2) Acme Widgets raises $80 million Series C led by Northwind Capital [2026-09-29]; 3) 9 new roles since 2026-09-06 (12 open) on greenhouse [2026-09-30].",
  "checkedAt": "2026-10-06T12:00:00.000Z",
  "windows": {
    "hiring": "2026-09-06T12:00:00.000Z",
    "filings": "2026-07-08T12:00:00.000Z",
    "news": "2026-09-06T12:00:00.000Z"
  },
  "entity": {
    "name": "Acme Widgets",
    "legalName": "Acme Widgets, Inc.",
    "confidence": 0.99,
    "lowConfidence": false,
    "evidence": [
      {
        "type": "jsonld_name",
        "value": "Acme Widgets",
        "weight": 0.7
      },
      {
        "type": "jsonld_legal_name",
        "value": "Acme Widgets, Inc.",
        "weight": 0.6
      },
      {
        "type": "og_site_name",
        "value": "Acme Widgets",
        "weight": 0.55
      },
      {
        "type": "sec_name_match",
        "value": "Acme Widgets, Inc.",
        "weight": 0.5
      },
      "..."
    ],
    "sec": {
      "cik": 1234567,
      "ticker": "ACMW",
      "title": "Acme Widgets, Inc.",
      "matchType": "name_exact"
    }
  },
  "score": {
    "value": 75,
    "label": "hot"
  },
  "topSignals": [
    {
      "rank": 1,
      "kind": "exec_change_filing",
      "headline": "8-K filed 2026-10-02: Executive or board change (5.02, 9.01)",
      "whyNow": "Leadership change (2026-10-02): new leaders reassess priorities, teams and vendors in their first months.",
      "date": "2026-10-02",
      "score": 78.5,
      "confidence": 0.99,
      "source": {
        "url": "https://www.sec.gov/Archives/edgar/data/1234567/000123456726000041/acmw-20261001.htm",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "5.02 Director or executive officer departure, election or appointment"
      ],
      "corroboratedBy": [
        "news-leadership_change-2026-09-26-1",
        "senior_hire-acme-widgets.example-vp-of-sales"
      ]
    },
    {
      "rank": 2,
      "kind": "funding",
      "headline": "Acme Widgets raises $80 million Series C led by Northwind Capital",
      "whyNow": "Fresh funding (2026-09-29): new budget and a mandate to scale are likely.",
      "date": "2026-09-29T14:30:00Z",
      "score": 70.3,
      "confidence": 0.96,
      "source": {
        "url": "https://techcrunch.example/acme-widgets-series-c",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "category: funding",
        "publisher: techcrunch.example",
        "syndicated by reuters.example, siliconnews.example"
      ],
      "corroboratedBy": [
        "filing-0001234567-26-000038"
      ]
    },
    {
      "rank": 3,
      "kind": "hiring_surge",
      "headline": "9 new roles since 2026-09-06 (12 open) on greenhouse",
      "whyNow": "Hiring ramp (2026-09-30): teams are scaling and tooling gaps open up.",
      "date": "2026-09-30T13:00:00.000Z",
      "score": 67.6,
      "confidence": 0.98,
      "source": {
        "url": "https://boards.greenhouse.io/acmewidgets",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "Engineering: 4 open",
        "Sales: 3 open",
        "Customer Success: 1 open",
        "new: Data Analyst",
        "new: Senior Software Engineer, Platform"
      ],
      "corroboratedBy": [
        "news-expansion-2026-09-18-3"
      ]
    }
  ],
  "actions": [
    {
      "id": "action-1",
      "priority": "high",
      "type": "reach_out",
      "basedOn": "filing-0001234567-26-000041",
      "text": "Leadership change (2026-10-02): new leaders reassess priorities, teams and vendors in their first months. Reference: \"8-K filed 2026-10-02: Executive or board change (5.02, 9.01)\""
    },
    "..."
  ],
  "signals": [
    "... 15 signals (see hiring/filings/news modes)"
  ],
  "hiring": "{ ... section ... }",
  "filings": "{ ... section ... }",
  "news": "{ ... section ... }",
  "sources": [
    {
      "url": "https://acme-widgets.example/",
      "fetchedAt": "2026-10-06T12:00:00.000Z"
    },
    {
      "url": "https://www.sec.gov/files/company_tickers.json",
      "fetchedAt": "2026-10-06T12:00:00.000Z"
    },
    {
      "...": "9 more"
    }
  ]
}
```

#### `hiring` — $0.03

The ATS is detected from links on the homepage and careers pages (Greenhouse, Lever, Ashby, Workable, SmartRecruiters). If no link is found, Greenhouse/Workable/SmartRecruiters boards are probed by name and accepted **only if the board's own name matches the company**.

```json
{
  "domain": "acme-widgets.example",
  "mode": "hiring",
  "outcome": "found",
  "summary": "Acme Widgets (acme-widgets.example): 5 signals (1 open roles, 1 hiring surge, 1 senior hire, 2 first function hire). Latest: 12 open roles on greenhouse; most in Engineering [2026-10-06].",
  "checkedAt": "2026-10-06T12:00:00.000Z",
  "windows": {
    "hiring": "2026-09-06T12:00:00.000Z"
  },
  "entity": {
    "name": "Acme Widgets",
    "legalName": "Acme Widgets, Inc.",
    "confidence": 0.99,
    "lowConfidence": false,
    "evidence": [
      {
        "type": "jsonld_name",
        "value": "Acme Widgets",
        "weight": 0.7
      },
      {
        "type": "jsonld_legal_name",
        "value": "Acme Widgets, Inc.",
        "weight": 0.6
      },
      {
        "type": "og_site_name",
        "value": "Acme Widgets",
        "weight": 0.55
      },
      {
        "type": "sec_name_match",
        "value": "Acme Widgets, Inc.",
        "weight": 0.5
      },
      "..."
    ],
    "sec": {
      "cik": 1234567,
      "ticker": "ACMW",
      "title": "Acme Widgets, Inc.",
      "matchType": "name_exact"
    }
  },
  "score": {
    "value": 49,
    "label": "warm"
  },
  "signals": [
    {
      "id": "open-roles-acme-widgets.example",
      "kind": "open_roles",
      "title": "12 open roles on greenhouse; most in Engineering",
      "date": "2026-10-06T12:00:00.000Z",
      "strength": 39,
      "confidence": 0.95,
      "lowConfidence": false,
      "source": {
        "url": "https://boards.greenhouse.io/acmewidgets",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "Engineering: 4",
        "Sales: 3",
        "Customer Success: 1",
        "Design: 1"
      ]
    },
    {
      "id": "hiring-surge-acme-widgets.example",
      "kind": "hiring_surge",
      "title": "9 new roles since 2026-09-06 (12 open) on greenhouse",
      "date": "2026-09-30T13:00:00.000Z",
      "strength": 73,
      "confidence": 0.9,
      "lowConfidence": false,
      "source": {
        "url": "https://boards.greenhouse.io/acmewidgets",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "Engineering: 4 open",
        "Sales: 3 open",
        "Customer Success: 1 open",
        "new: Data Analyst",
        "new: Senior Software Engineer, Platform",
        "new: Software Engineer, Backend"
      ]
    },
    {
      "id": "senior_hire-acme-widgets.example-vp-of-sales",
      "kind": "senior_hire",
      "title": "Senior hire: VP of Sales (Sales)",
      "date": "2026-09-22T13:00:00.000Z",
      "strength": 80,
      "confidence": 0.9,
      "lowConfidence": false,
      "source": {
        "url": "https://boards.greenhouse.io/acmewidgets/jobs/1006",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "VP-level title",
        "location: New York, NY"
      ]
    },
    "..."
  ],
  "hiring": {
    "ats": {
      "ats": "greenhouse",
      "token": "acmewidgets",
      "detectedVia": "careers_page_link",
      "boardUrl": "https://boards.greenhouse.io/acmewidgets"
    },
    "openRoles": 12,
    "byDepartment": [
      {
        "name": "Engineering",
        "count": 4
      },
      {
        "name": "Sales",
        "count": 3
      },
      {
        "name": "Customer Success",
        "count": 1
      },
      "..."
    ],
    "byLocation": [
      {
        "name": "New York, NY",
        "count": 3
      },
      {
        "name": "Remote - US",
        "count": 3
      },
      "..."
    ],
    "window": {
      "since": "2026-09-06T12:00:00.000Z",
      "basis": "posted"
    },
    "newRolesCount": 9,
    "newRoles": [
      {
        "title": "Data Analyst",
        "department": "Engineering",
        "location": "Remote - US",
        "url": "https://boards.greenhouse.io/acmewidgets/jobs/1011",
        "postedAt": "2026-09-30T13:00:00.000Z"
      },
      {
        "title": "Senior Software Engineer, Platform",
        "department": "Engineering",
        "location": "San Francisco, CA",
        "url": "https://boards.greenhouse.io/acmewidgets/jobs/1001",
        "postedAt": "2026-09-28T13:00:00.000Z"
      },
      "..."
    ],
    "seniorRoles": [
      {
        "title": "VP of Sales",
        "department": "Sales",
        "level": "vp",
        "firstInFunction": false,
        "reasons": [
          "VP-level title"
        ]
      },
      {
        "title": "Head of Security",
        "department": "Security",
        "level": "head_of",
        "firstInFunction": true,
        "reasons": [
          "\"Head of\" title",
          "only 1 open role in Security (first-in-function)"
        ]
      },
      {
        "title": "Founding Marketing Manager, EMEA",
        "department": "Marketing",
        "level": "founding",
        "firstInFunction": true,
        "reasons": [
          "founding / first-hire role"
        ]
      },
      "..."
    ]
  },
  "sources": [
    {
      "url": "https://acme-widgets.example/",
      "fetchedAt": "2026-10-06T12:00:00.000Z"
    },
    {
      "url": "https://www.sec.gov/files/company_tickers.json",
      "fetchedAt": "2026-10-06T12:00:00.000Z"
    },
    {
      "...": "7 more"
    }
  ]
}
```

Seniority is classified from titles (`C-level`, `VP`, `Head of`, `Director`, `Founding/First …`); a senior role in a department with at most two open roles is flagged `firstInFunction`. Dates: Lever/Ashby/Workable/SmartRecruiters give a publish date; Greenhouse gives `first_published` when available, otherwise `updated_at` — then `window.basis` is `"updated"` and signals say so.

#### `filings` — $0.03

Reads EDGAR `submissions` JSON with the SEC-required User-Agent (contact from `SEC_CONTACT_EMAIL`) and a request throttle well under SEC's 10 requests/second.

```json
{
  "domain": "acme-widgets.example",
  "mode": "filings",
  "outcome": "found",
  "summary": "Acme Widgets (acme-widgets.example): 5 signals (1 exec change filing, 1 financing filing, 1 periodic report, 1 earnings filing, 1 private financing filing). Latest: 8-K filed 2026-10-02: Executive or board change (5.02, 9.01) [2026-10-02].",
  "checkedAt": "2026-10-06T12:00:00.000Z",
  "windows": {
    "filings": "2026-07-08T12:00:00.000Z"
  },
  "entity": {
    "name": "Acme Widgets",
    "legalName": "Acme Widgets, Inc.",
    "confidence": 0.99,
    "lowConfidence": false,
    "evidence": [
      {
        "type": "jsonld_name",
        "value": "Acme Widgets",
        "weight": 0.7
      },
      {
        "type": "jsonld_legal_name",
        "value": "Acme Widgets, Inc.",
        "weight": 0.6
      },
      {
        "type": "og_site_name",
        "value": "Acme Widgets",
        "weight": 0.55
      },
      {
        "type": "sec_name_match",
        "value": "Acme Widgets, Inc.",
        "weight": 0.5
      },
      "..."
    ],
    "sec": {
      "cik": 1234567,
      "ticker": "ACMW",
      "title": "Acme Widgets, Inc.",
      "matchType": "name_exact"
    }
  },
  "score": {
    "value": 52,
    "label": "warm"
  },
  "signals": [
    {
      "id": "filing-0001234567-26-000041",
      "kind": "exec_change_filing",
      "title": "8-K filed 2026-10-02: Executive or board change (5.02, 9.01)",
      "date": "2026-10-02",
      "strength": 80,
      "confidence": 0.95,
      "lowConfidence": false,
      "source": {
        "url": "https://www.sec.gov/Archives/edgar/data/1234567/000123456726000041/acmw-20261001.htm",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "5.02 Director or executive officer departure, election or appointment"
      ]
    },
    {
      "id": "filing-0001234567-26-000038",
      "kind": "financing_filing",
      "title": "8-K filed 2026-09-18: Financing (1.01, 3.02, 9.01)",
      "date": "2026-09-18",
      "strength": 80,
      "confidence": 0.95,
      "lowConfidence": false,
      "source": {
        "url": "https://www.sec.gov/Archives/edgar/data/1234567/000123456726000038/acmw-20260917.htm",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "1.01 Entered into a material definitive agreement",
        "3.02 Unregistered sale of equity securities (private financing)"
      ]
    },
    "..."
  ],
  "filings": {
    "status": "ok",
    "company": {
      "cik": 1234567,
      "name": "Acme Widgets, Inc.",
      "tickers": [
        "ACMW"
      ],
      "matchType": "name_exact"
    },
    "countsByForm": {
      "8-K": 3,
      "10-Q": 1,
      "D": 1
    },
    "filings": [
      {
        "form": "8-K",
        "filedAt": "2026-10-02",
        "items": [
          {
            "code": "5.02",
            "label": "Director or executive officer departure, election or appointment",
            "category": "exec_change"
          },
          {
            "code": "9.01",
            "label": "Financial statements and exhibits",
            "category": "other"
          }
        ],
        "events": [
          "exec_change"
        ],
        "url": "https://www.sec.gov/Archives/edgar/data/1234567/000123456726000041/acmw-20261001.htm"
      },
      {
        "form": "8-K",
        "filedAt": "2026-09-18",
        "items": [
          {
            "code": "1.01",
            "label": "Entered into a material definitive agreement",
            "category": "material_agreement"
          },
          {
            "code": "3.02",
            "label": "Unregistered sale of equity securities (private financing)",
            "category": "financing"
          },
          {
            "code": "9.01",
            "label": "Financial statements and exhibits",
            "category": "other"
          }
        ],
        "events": [
          "material_agreement",
          "financing"
        ],
        "url": "https://www.sec.gov/Archives/edgar/data/1234567/000123456726000038/acmw-20260917.htm"
      },
      "..."
    ]
  },
  "sources": [
    {
      "url": "https://acme-widgets.example/",
      "fetchedAt": "2026-10-06T12:00:00.000Z"
    },
    {
      "url": "https://www.sec.gov/files/company_tickers.json",
      "fetchedAt": "2026-10-06T12:00:00.000Z"
    },
    {
      "...": "1 more"
    }
  ]
}
```

8-K item codes are translated (e.g. 5.02 → executive/board change, 2.01 → M\&A, 1.01/3.02 → agreement/private financing, 2.05 → restructuring, 1.05 → cybersecurity incident). 8-Ks that only carry exhibits (9.01) or Reg FD text are not turned into signals.

#### `news` — $0.03

GDELT DOC 2.0, queried for the company name and domain. Articles that mention the company neither in the headline nor in the URL/publisher are dropped as noise; headlines are classified by keyword rules; syndicated copies (same headline after stripping publisher suffixes and money formats, or ≥ 80 % token overlap) are merged into the earliest article with `alsoReportedBy`.

```json
{
  "domain": "acme-widgets.example",
  "mode": "news",
  "outcome": "found",
  "summary": "Acme Widgets (acme-widgets.example): 5 signals (1 funding, 1 leadership change, 1 product launch, 1 expansion, 1 m and a). Latest: Acme Widgets raises $80 million Series C led by Northwind Capital [2026-09-29].",
  "checkedAt": "2026-10-06T12:00:00.000Z",
  "windows": {
    "news": "2026-09-06T12:00:00.000Z"
  },
  "entity": {
    "name": "Acme Widgets",
    "legalName": "Acme Widgets, Inc.",
    "confidence": 0.99,
    "lowConfidence": false,
    "evidence": [
      {
        "type": "jsonld_name",
        "value": "Acme Widgets",
        "weight": 0.7
      },
      {
        "type": "jsonld_legal_name",
        "value": "Acme Widgets, Inc.",
        "weight": 0.6
      },
      {
        "type": "og_site_name",
        "value": "Acme Widgets",
        "weight": 0.55
      },
      {
        "type": "sec_name_match",
        "value": "Acme Widgets, Inc.",
        "weight": 0.5
      },
      "..."
    ],
    "sec": {
      "cik": 1234567,
      "ticker": "ACMW",
      "title": "Acme Widgets, Inc.",
      "matchType": "name_exact"
    }
  },
  "score": {
    "value": 47,
    "label": "warm"
  },
  "signals": [
    {
      "id": "news-funding-2026-09-29-0",
      "kind": "funding",
      "title": "Acme Widgets raises $80 million Series C led by Northwind Capital",
      "date": "2026-09-29T14:30:00Z",
      "strength": 80,
      "confidence": 0.88,
      "lowConfidence": false,
      "source": {
        "url": "https://techcrunch.example/acme-widgets-series-c",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "category: funding",
        "publisher: techcrunch.example",
        "syndicated by reuters.example, siliconnews.example"
      ]
    },
    {
      "id": "news-leadership_change-2026-09-26-1",
      "kind": "leadership_change",
      "title": "Acme Widgets appoints Jane Roe as Chief Financial Officer",
      "date": "2026-09-26T12:00:00Z",
      "strength": 75,
      "confidence": 0.7,
      "lowConfidence": false,
      "source": {
        "url": "https://businesswire.example/acme-cfo",
        "fetchedAt": "2026-10-06T12:00:00.000Z"
      },
      "evidence": [
        "category: leadership_change",
        "publisher: businesswire.example"
      ]
    },
    "..."
  ],
  "news": {
    "query": "(\"Acme Widgets\" OR \"acme-widgets.example\") sourcelang:english",
    "totals": {
      "articles": 12,
      "relevant": 10,
      "classified": 9,
      "afterDedupe": 7,
      "unclassified": 1
    },
    "byCategory": {
      "funding": 1,
      "leadership_change": 1,
      "product_launch": 1,
      "expansion": 1,
      "m_and_a": 1,
      "legal": 1,
      "layoffs": 1
    },
    "events": [
      {
        "category": "funding",
        "title": "Acme Widgets raises $80 million Series C led by Northwind Capital",
        "publisher": "techcrunch.example",
        "date": "2026-09-29T14:30:00Z",
        "confidence": 0.88,
        "alsoReportedBy": [
          "reuters.example",
          "siliconnews.example"
        ],
        "copies": 2
      },
      {
        "category": "leadership_change",
        "title": "Acme Widgets appoints Jane Roe as Chief Financial Officer",
        "publisher": "businesswire.example",
        "date": "2026-09-26T12:00:00Z",
        "confidence": 0.7,
        "alsoReportedBy": [],
        "copies": 0
      },
      {
        "category": "product_launch",
        "title": "Acme Widgets launches Widget Pro 2 for enterprise teams",
        "publisher": "acme-widgets.example",
        "date": "2026-09-20T09:00:00Z",
        "confidence": 0.7,
        "alsoReportedBy": [],
        "copies": 0
      },
      "..."
    ]
  },
  "sources": [
    {
      "url": "https://acme-widgets.example/",
      "fetchedAt": "2026-10-06T12:00:00.000Z"
    },
    {
      "...": "2 more"
    }
  ]
}
```

### Pricing

Pay-per-event, per company. You pay only when an item has `outcome: "found"`: at least one **confident** signal. No data, low-confidence-only results, unreachable sources, errors and invalid input cost $0.

| Mode | Event | Price per company |
| --- | --- | --- |
| `hiring` | `hiring-signals` | $0.03 |
| `filings` | `filing-signals` | $0.03 |
| `news` | `news-signals` | $0.03 |
| `why_now_pack` | `why-now-pack` | $0.10 |

`why_now_pack` is charged once ($0.10, not the sum of three modes) when at least one of its signals is confident.

**Spending limits.** The Actor respects your run's *maximum cost*. When it is reached the run stops cleanly: the item that would exceed it is not delivered or charged, remaining companies are returned as `outcome: "unavailable"` with `stoppedReason: "max_total_charge_reached"`, and the run summary says so.

### Input

| Field | Default | Max | Notes |
| --- | --- | --- | --- |
| `mode` | `why_now_pack` | | see above |
| `domain` | | | company domain, e.g. `stripe.com` |
| `companyName` | | | optional, improves entity resolution |
| `ticker` | | | optional US ticker |
| `companies` | | 25 items | bulk: strings or `{domain, companyName, ticker}` |
| `since` | | 365 days back | return only newer signals (YYYY-MM-DD / ISO). Default windows: 30 d hiring and news, 90 d filings. News looks back at most ~90 days |
| `maxCompanies` | 10 | 25 | |
| `maxNewsArticles` | 100 | 250 | |
| `maxFilings` | 30 | 100 | |
| `maxJobs` | 1000 | 3000 | |
| `maxConcurrency` | 3 | 5 | |
| `requestTimeoutSecs` | 12 | 30 | every request has a timeout and is retried with backoff |

Empty input runs a fast demo on `example.com`.

**Environment variables** (set as secret environment variables in Actor settings; none is a key, none is required): `SEC_CONTACT_EMAIL` — the contact address sent in the SEC User-Agent (SEC asks for one; defaults to a placeholder, which SEC may throttle).

### Data sources and etiquette

The company's public pages (robots.txt honoured; SSRF-guarded), public job-board APIs of Greenhouse, Lever, Ashby, Workable and SmartRecruiters, [SEC EDGAR](https://www.sec.gov/edgar) (`company_tickers.json`, `submissions`, company search for Form D filers), and [GDELT DOC 2.0](https://blog.gdeltproject.org/gdelt-doc-2-0-api-debuts/). No login, no paywalled sources, no scraping of job-board HTML. Descriptive `User-Agent` (`CompanyWhyNowBot/…`); SEC requests use the SEC-required form `CompanyWhyNowSignals/0.1 (<contact>)`.

### Limitations

- **Coverage:** hiring needs a supported public ATS (many companies use others, e.g. Workday, iCIMS, custom pages — those return `no_match`). SEC filings cover US registrants (and Form D filers found by exact name); foreign private issuers (6-K/20-F) are not covered.
- **Entity resolution is heuristic.** Common names, rebrands and holding structures can resolve wrongly; check `entity.confidence` and `entity.evidence`, and pass `companyName`/`ticker` for anything below 0.9 that matters.
- **News is keyword-classified from headlines only** (no article text, no LLM). Expect misses and occasional false positives; `confidence` reflects keyword strength, not truth. GDELT is a global aggregator with uneven coverage and a ~90-day lookback, and is occasionally slow or rate-limited (reported as `unavailable`, not charged).
- **Dates:** Greenhouse boards without `first_published` expose only last-updated times; roles can look "new" because they were edited.
- Senior/first-in-function detection is title-based. The ranking weights and keyword rules are fixed and documented here, not tuned per customer.
- No contact details, no people data, no private-company financials.

### Related Actors

- [Google Trends Scraper: Bulk Compare 100+ Keywords](https://apify.com/s3nafps/google-trends-bulk-compare): see whether search interest in the companies you track is rising, with up to 500 names on one Google Trends scale.
- [YouTube Transcripts for AI](https://apify.com/s3nafps/youtube-transcripts-for-ai): bulk YouTube transcripts from videos, channels and search as text, Markdown and RAG chunks.

### Feedback

Something not working, or a feature you need? Open an issue in the **Issues** tab with your input and I'll take a look. If the Actor saves you time, a short review on its Store page helps other people find it.

### Local development

```bash
npm ci
npm run build && npm run lint && npm test     # offline unit tests with fixtures
SEC_CONTACT_EMAIL=you@yourdomain.com npm run smoke   # live: every mode against 3 real companies
apify run                                      # default input = example.com demo
```

# Actor input Schema

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

Pick one. why_now_pack ($0.10): hiring + filings + news and a ranked top-3 'why reach out now' list with evidence, date, source, confidence (best default for outreach/sales agents). hiring ($0.03): open roles by department/location, new roles since a date, senior and first-in-function hires. filings ($0.03): SEC 8-K, 10-K/10-Q, S-1, Form D with item codes in plain English. news ($0.03): GDELT news classified into funding, layoffs, leadership change, M\&A, product launch, expansion, legal. A mode is charged only when it returns at least one signal; signals that depend on an uncertain company match (confidence below 0.6) are labelled low_confidence and never charged.

## `domain` (type: `string`):

The company's website domain, e.g. stripe.com or https://www.stripe.com. This is the primary key: the Actor reads the homepage title, og:site_name and JSON-LD Organization to resolve the company name, then matches it against SEC company_tickers.json.

## `companyName` (type: `string`):

Optional legal or trade name. Improves entity resolution when the website does not state it clearly. If it conflicts with the name found on the site, the match is flagged and may fall below 0.6 confidence (then filings/news signals are labelled low_confidence and not charged).

## `ticker` (type: `string`):

Optional US-listed ticker, e.g. AAPL. An exact ticker match in SEC company_tickers.json is strong evidence for the entity and enables SEC filings.

## `companies` (type: `array`):

Optional list for scheduled monitoring: strings (domains) or objects like {"domain": "stripe.com", "companyName": "Stripe", "ticker": ""}. One dataset item per company, each charged separately when it has signals. At most 25.

## `since` (type: `string`):

Return only signals newer than this date (YYYY-MM-DD or ISO 8601), for scheduled monitoring: pass the date of your last run. If empty, the windows are 30 days for hiring and news and 90 days for SEC filings. News lookback is limited to about 90 days by the source; the date is clamped to 365 days.

## `maxCompanies` (type: `integer`):

Safety cap on how many companies from the list are processed (max 25).

## `maxNewsArticles` (type: `integer`):

How many GDELT articles to request per company before classification and de-duplication (max 250).

## `maxFilings` (type: `integer`):

Maximum SEC filings returned per company (max 100).

## `maxJobs` (type: `integer`):

Maximum job postings read from a company's job board (max 3000).

## `maxConcurrency` (type: `integer`):

How many companies are processed in parallel (max 5). SEC requests are throttled separately.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each network request; every request is retried with backoff (max 30).

## Actor input object example

```json
{
  "mode": "why_now_pack",
  "domain": "example.com",
  "maxCompanies": 10,
  "maxNewsArticles": 100,
  "maxFilings": 30,
  "maxJobs": 1000,
  "maxConcurrency": 3,
  "requestTimeoutSecs": 12
}
```

# Actor output Schema

## `companies` (type: `string`):

One compact JSON item per company: outcome (found | no_match | unavailable | error), entity with confidence, signals with date/source/confidence, ranked top signals (why_now_pack) and actions.

## `runSummary` (type: `string`):

Counts of processed, charged and free items, and whether the max-charge limit stopped the run.

# 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 = {
    "domain": "example.com"
};

// Run the Actor and wait for it to finish
const run = await client.actor("s3nafps/company-why-now-signals").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 = { "domain": "example.com" }

# Run the Actor and wait for it to finish
run = client.actor("s3nafps/company-why-now-signals").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 '{
  "domain": "example.com"
}' |
apify call s3nafps/company-why-now-signals --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s3nafps/company-why-now-signals"
        }
    }
}
```

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/eArxsWCMaXmXDL1Gc/builds/3dnh9lmJK7mvgYUxT/openapi.json
