# Public Company Earnings Dates and Reporting Window Finder (`mambalabs/public-company-reporting-window-finder`) Actor

Finds when a public company reports. Give it a domain, ticker, ISIN, LEI or CIK and get back fiscal year end, reporting cadence, next reporting date, days to event, and the open and close of the outreach window, as one flat row per company built for Clay. Timing rows cover US companies only.

- **URL**: https://apify.com/mambalabs/public-company-reporting-window-finder.md
- **Developed by:** [Mamba Labs](https://apify.com/mambalabs) (community)
- **Categories:** Lead generation, Automation, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.10 / 1,000 company resolveds

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

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### 🧭 What can Public Company Earnings Dates and Reporting Window Finder do?

Give it a **domain, ticker, ISIN, LEI or CIK** and it tells you **when that public company
reports**, and when to reach out around it. One flat row per company, built to drop into a Clay
column.

Most tools tell you a company is public. This one tells you the **fiscal year end**, the
**reporting cadence**, the **next reporting date**, **how many days away it is**, and the **open
and close of an outreach window** you define yourself.

| 📦 What you get | ⚙️ Features and integrations |
|---|---|
| 🏢 **44 identity fields** in `resolve`, 47 in `qualify`, 46 in `universe`<br>📅 **75 fields** in `timing` mode<br>🎯 **`outreach_window_open` and `outreach_window_close`**, your lead and lag<br>🧾 **`null` never missing**, every field always present | 🔑 **Five identifier types**: domain, ticker, ISIN, LEI, CIK<br>🇺🇸 **Timing from SEC filing history**, US companies<br>🧊 **24 hour identity cache**, timing never cached<br>⬇️ **Export** to JSON, CSV, Excel, HTML or XML |

Bought by outbound teams timing their sequences around earnings, by investor relations and
finance researchers, and by anyone who needs a reporting calendar keyed to identifiers they
already have.

> 🇺🇸 **Timing rows cover US companies only.** Identity, venue and classification resolve
> worldwide, across 10,646 publishable companies. The reporting dates come from US SEC filing
> history and exist for US companies alone. If you send a European or UK company to `timing`
> mode, you get its identity and a stated reason, never a guessed date.

### 💡 Why use this actor?

| If you want | Read these fields |
|---|---|
| The next reporting date | `next_event_date`, `next_event_type`, `next_event_period` |
| To time outreach around it | `outreach_window_open`, `outreach_window_close`, `window_status`, `days_to_event` |
| To know how much to trust the date | `confidence_band`, `confidence_effective`, `next_event_source_rung` |
| The reporting rhythm | `derived_cadence`, `cadence_confidence`, `cadence_observation_count` |
| The fiscal calendar | `fiscal_year_end_mmdd`, `fiscal_year_end_month`, `is_non_calendar_fiscal_year` |
| Company identity | `legal_name`, `primary_ticker`, `isin`, `lei`, `cik`, `domain` |
| Venue and classification | `primary_exchange_code`, `country_code`, `sector`, `security_type` |
| To tell empty from broken | `match_method`, `timing_unavailable_reason`, `domain_absent_reason` |

#### 📏 A predicted date is labeled as one

`next_event_is_estimate` and `next_event_is_announced` sit on every timing row. A date derived
from filing history is an **estimate**, and the actor says so on the row rather than in the
documentation. `confidence_band` and `confidence_effective` tell you how much history sat behind
it.

**The bands sit at 0.80 and 0.50.** At or above 0.80 is `strong`, 0.50 to 0.80 is `moderate`,
below 0.50 is `weak`. Confidence is computed on the **weakest link in the chain**: a date is only
as good as the cadence it was derived from, so `confidence_effective` is the minimum of the event
and cadence confidences, never an average. Because of that minimum, **the 0.75 to 0.80 band is
empty by construction**. A gap in the distribution is arithmetic, not missing data.

### 📋 What data does it extract?

**Field counts are per mode**, measured against live runs: `resolve` **44**, `qualify` **47** with
its three verdict fields, `universe` **46**, `timing` **75**, and `season` **19**, which are
aggregate rows rather than company rows. Within a mode every field is always present. A field with
nothing behind it is `null`, never absent, so a Clay column never shifts.

Identity and venue: `company_id`, `legal_name`, `normalized_name`, `primary_ticker`, `isin`,
`lei`, `cik`, `domain`, `primary_exchange_code`, `country_code`, `currency`, `market_segment`,
`listing_count`, `all_exchange_codes`, `is_cross_listed`, `sector`, `security_type`,
`is_operating_company`, `is_foreign_private_issuer`, `is_us_registrant`, `is_blank_check`,
`is_depositary_receipt`, `public_float_usd`, `public_float_band`, `shares_outstanding`.

Timing: `fiscal_year_end_mmdd`, `derived_cadence`, `next_event_date`, `next_event_type`,
`next_event_period`, `next_event_is_estimate`, `next_event_is_announced`, `days_to_event`,
`outreach_window_open`, `outreach_window_close`, `window_status`, `constrained_period_open`,
`constrained_period_close`, `is_in_constrained_period`, `confidence_band`,
`timing_unavailable_reason`.

Provenance on every row: `data_as_of`, `snapshot_built_at`, `contract_version`,
`provenance_source`, `provenance_confidence`, `attribution`, `license`, `source_surface`.

### 🛠️ How to find a company's next reporting date

1. Pick a **mode**. `resolve` for identity, `timing` for reporting dates and windows, `universe`
   to list companies matching a filter, `season` for aggregate reporting volume by week or month,
   `qualify` to test companies against filters.
2. Give it identifiers: `company_domains`, `tickers`, `isins`, `leis`, `ciks` or `company_names`.
   Mix types freely in one run, up to 1,000 per run.
3. For `timing`, set `window_lead_days` and `window_lag_days`. They default to 70 and 42, which
   opens the window ten weeks before the reporting date and closes it six weeks after.
4. Run it. Every input gets exactly one row back, in the same shape, whether it matched or not.

### 💵 How much does it cost?

Pay per event. You are charged for **rows returned**, not for rows you filtered out.

| Event | Price |
|---|---|
| Company resolved | $0.006 per row |
| Timing row returned | $0.012 per row |
| Reporting season aggregate | $0.05 per row |
| Actor start | $0.00005 per run |

Volume discounts of 5, 10 and 15 percent apply on the Apify Bronze, Silver and Gold plans.

**A row that resolves nothing is still billed.** An identifier that matches no public company
comes back with `match_method` set to `no_match` and every other field `null`. That is a real
answer, the actor made a real request to produce it, and a documented null is worth more than a
silent gap. If you do not want to pay for misses, filter your input before you send it.

**Timing rows are billed per row and exist for US companies only.** A non US company sent to
`timing` mode returns its identity and a `timing_unavailable_reason`, and is billed as a timing
row because the work was done.

**Not charged**: rows dropped by a filter you set, and every row in a run that fails input
validation. A rejected input emits no rows and charges no row event. The platform's own
`apify-actor-start` event still applies, at one per run, because it is levied before the actor
validates anything.

**The truncation notice is a row you are not charged for.** When `universe` or `season` matches
more than your `limit`, one extra row comes back carrying `total_matched` and no company, so the
shortfall is visible rather than silent. It is not billed: a `limit` of 5 against a larger match
returns 6 rows and charges 5.

### ⌨️ Input

| Field | Type | Notes |
|---|---|---|
| `mode` | string | `resolve`, `qualify`, `timing`, `universe`, `season` |
| `company_domains`, `tickers`, `isins`, `leis`, `ciks`, `company_names` | array | Up to 1,000 identifiers per run |
| `window_lead_days`, `window_lag_days` | string | Outreach window, defaults 70 and 42 |
| `country_codes`, `exchange_codes`, `sectors`, `security_types` | array | Universe and qualify filters |
| `cadences`, `fiscal_year_end_months` | array | Reporting rhythm filters |
| `season_from`, `season_to`, `season_group_by`, `season_split_by` | string | Season mode window and grouping |
| `min_provenance_confidence` | string | `any` or `high` |
| `limit` | string | Rows to return, default 1,000 |

### 📤 Output

One flat row per input, one JSON object per row, all fields always present.

```json
{
  "matched_on": "ticker",
  "matched_value": "TXG",
  "legal_name": "10x Genomics, Inc.",
  "primary_ticker": "TXG",
  "cik": "0001770787",
  "primary_exchange_code": "XNAS",
  "country_code": "US",
  "derived_cadence": "quarterly",
  "next_event_type": "quarterly_results",
  "next_event_date": "2026-11-03",
  "next_event_is_estimate": true,
  "days_to_event": 77,
  "outreach_window_open": "2026-08-25",
  "outreach_window_close": "2026-09-22",
  "window_status": "not_yet",
  "confidence_band": "strong",
  "data_as_of": "2026-08-17"
}
```

### 💡 Tips

**Read `window_status` before `next_event_date`.** It is `open`, `not_yet`, `closed_passed` or
`no_event` against today, and it is the field you filter a Clay table on. `no_event` is the
state a company lands in when there is no reporting event to build a window from, which is
every non US company.

**Set the window to your sales cycle.** `window_lead_days` and `window_lag_days` are yours. A
long enterprise cycle wants a wider lead than the default 70 days.

**Use `universe` mode to build the list, then `timing` to time it.** `universe` returns every
company matching a filter, paging through the whole match rather than stopping at the first page.

### ⚠️ Known limits

**Timing is US only.** Reporting events come from SEC filing history. Non US companies resolve
fully for identity, venue and classification and return a stated
`timing_unavailable_reason` in `timing` mode. No date is invented for them.

**Unknown cadence is refused, not guessed.** 922 companies in the universe have no derivable
reporting cadence, because their filing history is too short or too irregular to support one. The
actor returns `derived_cadence` null with a reason instead of inventing a date. A wrong date that
looks right is worse than no date.

**864 companies have no publishable representation** and cannot be returned at all. They exist in
the market and not in the redistributable surface this actor reads.

**Dates are predicted, not announced.** `next_event_is_estimate` is true for a predicted date and
`next_event_is_announced` is true only when the event is a confirmed one. Treat an estimate as an
estimate.

**Identity is cached for 24 hours, timing never is.** `days_to_event`, `window_status` and
`is_in_constrained_period` change every day by construction, so a cached window would be a wrong
window. There is no flag to turn timing caching on.

**Attribution ships only where the result set requires it.** The `attribution` and `license`
fields carry the acknowledgment a row's source requires, and the run level attribution list holds
only the strings the rows you actually received need. A result set with no rows from a given
source does not claim that source's acknowledgment.

### ❓ FAQ

**Which identifier should I send?** Whichever you already have. Ticker and CIK are the most
precise, domain is the most common in a GTM table, and name matching is the loosest. `matched_on`
tells you which one produced the row.

**Can I send 5,000 companies?** Send up to 1,000 identifiers per run. `universe` mode pages
through matches larger than that and returns the whole set.

**What is the constrained period?** The stretch before a reporting date when a company's investor
relations team is least available. `constrained_period_open`, `constrained_period_close` and
`is_in_constrained_period` mark it so you can avoid it or target it deliberately.

**Why did a company I know is public come back `no_match`?** Either the identifier does not
appear on the publishable surface, or the company is one of the 864 with no publishable
representation. `match_method` and `domain_absent_reason` say which.

**How fresh is the data?** `data_as_of` and `snapshot_built_at` ship on every row. Read them
rather than assuming.

### 🧩 Want other GTM data?

| | |
|---|---|
| 🏢 [Company Firmographic Enricher](https://apify.com/mambalabs/company-firmographic-enricher) | 🔎 [Company Identity Resolver](https://apify.com/mambalabs/company-identity-resolver) |
| 💰 [Funding and Press Signal Scanner](https://apify.com/mambalabs/funding-press-signal-scanner) | 📊 [Company Discovery List Builder](https://apify.com/mambalabs/company-discovery-list-builder) |
| 🧑‍💼 [Hiring Signal Scraper](https://apify.com/mambalabs/gtm-hiring-signal-scraper) | 👤 [People Finder and Email Verifier](https://apify.com/mambalabs/people-finder) |
| 🚀 [Prospect Engine](https://apify.com/mambalabs/b2b-prospect-engine) | 🤖 [AI Tooling Detector](https://apify.com/mambalabs/ai-tooling-detector) |
| 📮 [Outbound Stack Detector](https://apify.com/mambalabs/outbound-infrastructure-fingerprint) | ⚖️ [Legal Entity Resolver](https://apify.com/mambalabs/legal-entity-resolver) |

> Every actor in the suite takes a domain or a company and returns one flat row,
> so they stack in the same Clay table without reshaping anything.

> 🛠️ **Need something custom built for you or your team?** Tell us what you are
> trying to find and we will build it. [Talk to Mamba Labs](https://mambabuilt.com/contact).

### 🆘 Support

A company timed wrongly, or an identifier that should have matched? Open an issue on the
**Issues** tab with the input and the rows, and we will look at it.

> ℹ️ **Sourcing and legal.** Company identity, venue and classification come from openly
> published reference sources, and reporting events from US SEC filing history. Every row carries
> its `provenance_source`, `provenance_confidence` and, where the source requires one, its
> `attribution` string and `license`. The actor emits company identity, venue, classification and
> reporting dates. It holds no personal data and returns none. You are responsible for how you
> use the output.

Built by [Mamba Labs](https://apify.com/mambalabs).

# Actor input Schema

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

resolve returns identity and venue. qualify adds a listed status verdict. timing returns fiscal year end, reporting cadence, the next obligated event and your outreach window. universe builds a company list from filters. season returns reporting load per week or month.

## `company_domain` (type: `string`):

A single bare domain, e.g. stripe.com. The Clay column shape. Used by resolve, qualify and timing.

## `company_domains` (type: `array`):

Many domains at once. Used by resolve, qualify and timing.

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

Exchange tickers, e.g. NWLG. Matched against the primary ticker and every venue listing.

## `isins` (type: `array`):

12 character ISINs.

## `leis` (type: `array`):

20 character Legal Entity Identifiers.

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

SEC Central Index Keys, with or without leading zeros.

## `company_names` (type: `array`):

Legal or trading names. Matched on a normalized name. Former names are not available: the alias table carries tickers and ISINs only.

## `operating_companies_only` (type: `string`):

Drop funds, trusts and other non operating entities. Sent as a string for Clay compatibility.

## `exclude_blank_checks` (type: `string`):

Drop pre deal SPACs. Separate from the operating company filter: a blank check shell is flagged as an operating company and passes every ordinary firmographic filter.

## `listed_only` (type: `string`):

qualify mode. Keep only rows proven to be publicly listed.

## `suppress_listed` (type: `string`):

qualify mode. Remove companies proven to be publicly listed, for anyone selling only into private companies. It removes what we can prove is listed; it does not warrant that the remainder is private.

## `assume_unmatched_is_private` (type: `string`):

qualify mode. By default an unmatched company returns is\_listed null, because a non match may mean the company is private OR that we do not hold its domain. Set true to opt into reading a non match as private, which sets is\_listed false.

## `foreign_private_issuer` (type: `string`):

Filter on foreign private issuer status.

## `us_registrant_only` (type: `string`):

Keep only companies carrying an SEC CIK.

## `exchange_codes` (type: `array`):

ISO 10383 MICs. 18 venues are covered.

## `country_codes` (type: `array`):

ISO 3166-1 alpha-2, e.g. US, GB, FR.

## `regions` (type: `array`):

Shorthand for a set of venues and countries: us, uk, eu. Widens an explicit exchange or country filter rather than replacing it.

## `sectors` (type: `array`):

SEC SIC descriptions, e.g. Pharmaceutical Preparations. Populated on roughly 65 percent of the publishable universe.

## `security_types` (type: `array`):

ordinary\_shares, depositary\_receipt, preferred\_shares.

## `public_float_bands` (type: `array`):

micro, small, mid, large, mega, unknown. Size runs on public float because market capitalization is not populated anywhere in this dataset.

## `fiscal_year_end_months` (type: `array`):

Integers 1 to 12. Fiscal year end is effectively a United States field in this dataset.

## `exclude_december_fiscal_year_end` (type: `string`):

Keep only companies whose fiscal year ends in a month other than December, the accounts whose budget cycle is out of phase with a calendar quarter.

## `cadences` (type: `array`):

quarterly, semiannual, annual, unknown.

## `min_cadence_confidence` (type: `string`):

0 to 1. Rows whose cadence confidence falls below this return a null timing block with a stated reason rather than a guess. Quarterly cadence averages 0.94, annual 0.40, semiannual 0.21.

## `event_types` (type: `array`):

full\_year\_results, half\_year\_results, quarterly\_results, trading\_update, annual\_report\_publication, sustainability\_report\_publication, agm, proxy\_filing, capital\_markets\_day.

## `window_lead_days` (type: `string`):

How many days before the event the outreach window opens. Default 70.

## `window_lag_days` (type: `string`):

How many days before the event the outreach window closes. Default 42. Must be less than the lead.

## `window_statuses` (type: `array`):

Keep only rows in these window states: open, not\_yet, closed\_passed, no\_event.

## `max_days_to_event` (type: `string`):

Drop rows whose next event is further away than this. A cost control.

## `include_constrained_period` (type: `string`):

Emit the period in which a listed company is constrained in what it can announce, derived from the same window numbers. Useful for campaign and announcement timing.

## `season_group_by` (type: `string`):

season mode. Bucket size.

## `season_split_by` (type: `string`):

season mode. Optional second dimension.

## `season_from` (type: `string`):

season mode. ISO date. Defaults to today.

## `season_to` (type: `string`):

season mode. ISO date. Defaults to 180 days from today.

## `min_provenance_confidence` (type: `string`):

Set to high to exclude rows whose source terms were never read.

## `exclude_name_only_matches` (type: `string`):

Drop rows whose identity link rests on a name and country agreeing rather than on an identifier. Use this wherever a wrong identity link matters.

## `exclude_share_alike` (type: `string`):

Drop rows derived from CC BY-SA sources, whose share alike condition may not suit a closed product.

## `limit` (type: `string`):

Maximum rows for universe and season. Truncation is always reported, never silent.

## `source_tag` (type: `string`):

Internal attribution tag set by Mamba Labs on published task examples. Not required, and nothing depends on it. Leave it empty.

## Actor input object example

```json
{
  "mode": "resolve",
  "company_domain": "10xgenomics.com",
  "operating_companies_only": "false",
  "exclude_blank_checks": "false",
  "listed_only": "false",
  "suppress_listed": "false",
  "assume_unmatched_is_private": "false",
  "foreign_private_issuer": "any",
  "us_registrant_only": "false",
  "exclude_december_fiscal_year_end": "false",
  "min_cadence_confidence": "0",
  "window_lead_days": "70",
  "window_lag_days": "42",
  "include_constrained_period": "true",
  "season_group_by": "week",
  "season_split_by": "none",
  "min_provenance_confidence": "any",
  "exclude_name_only_matches": "false",
  "exclude_share_alike": "false",
  "limit": "1000"
}
```

# Actor output Schema

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

Dataset containing one flat row per company: identity, venue, qualification and, in timing mode, fiscal year end, reporting cadence, the next obligated reporting event and the outreach window. Every forward date is a prediction and carries a confidence band.

# 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 = {
    "company_domain": "10xgenomics.com"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mambalabs/public-company-reporting-window-finder").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 = { "company_domain": "10xgenomics.com" }

# Run the Actor and wait for it to finish
run = client.actor("mambalabs/public-company-reporting-window-finder").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 '{
  "company_domain": "10xgenomics.com"
}' |
apify call mambalabs/public-company-reporting-window-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mambalabs/public-company-reporting-window-finder"
        }
    }
}

```

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/uINxR7a1IW8qUTRUX/builds/jMwU7aGFFOb3B5sB8/openapi.json
