# Company Dossier API — Domain to Full Company Answer (`insight.solutions/company-dossier-api`) Actor

Ask about one company and get one answer: firmographics from its own site, tech stack, company-level contacts, DNS and registrar, the ATS it hires through and its open roles, recent news, SEC filings, US federal awards, product recalls, Y Combinator batch and the apps it publishes. No API key.

- **URL**: https://apify.com/insight.solutions/company-dossier-api.md
- **Developed by:** [Insight Solutions](https://apify.com/insight.solutions) (community)
- **Categories:** Business, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.80 / 1,000 company dossier returneds

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

## Company Dossier API — Domain to Full Company Answer

Ask about **one company** and get **one answer**. Send a domain — or a company name, a ticker, a CIK or
an email address — and get one row carrying twelve sections: who they are, what they run on, how to
write to the company, who hosts and registers them, what they are hiring for, what the press said this
month, what they file with the SEC, what the numbers say, what the US government has paid them, whether
anything of theirs has been recalled, whether they went through Y Combinator, and what they ship in the
app stores.

Every section is read from a **first-party source** — the company's own website, its own DNS, the
public ATS board it recruits through, and the registers that publish the rest — and every section is
stamped with the exact request that produced it. **Read from the company's own website, its own DNS and
the public registers — never from a commercial database.** Anything nobody publishes comes back `null`,
never a guess.

**An empty section is an answer.** "No recalls found, and here is the query that proves it" is the most
valuable cell in a vendor-risk dossier, and it is not the same thing as "we did not look". A section
the company simply has nothing in comes back `status: "none"` with its `apiUrl`; a section the run
could not reach comes back `status: "unavailable"` plus a **free** diagnostic row.

**Company-level only. No names of individuals, in any section.** No CEO, no founders, no directors, no
SEC officer tables, no Y Combinator founder records, no hiring managers. The email filter is a role
allowlist, so `basecamp.com` — which publishes exactly one address, a person's — returns **zero**
emails. There is a test for that.

### At a glance

**Input** — this is the Store prefill; paste it and run:

```json
{ "companies": ["stripe.com", "nike.com", "airbnb.com", "allbirds.com"],
  "sections": ["profile","tech","contacts","domain","jobs","news","filings","awards","recalls","yc","apps"],
  "maxItemsPerSection": 10, "includeSummary": true, "flattenSections": false,
  "maxConcurrency": 3, "maxRunSecs": 300, "proxyConfiguration": { "useApifyProxy": true } }
```

**Output** — one `dossier` row per company with twelve nested sections; the fields you will use most are
`companyName`, `summary`, `sectionsFilled`, `identifiers`, `sections.jobs.openRoles`,
`sections.recalls.recallCount`, `sections.filings.cik` (full list under *Output reference*). A section the
company simply has nothing in comes back `status: "none"` with the query that proves it — not a blank.
Anything that could not be fetched comes back as a free diagnostic row (`ok: false`, `errorType`, `error`)
instead of a charge. **Each company's row is pushed the moment that company finishes**, so a long list
fills the dataset as it goes rather than at the end.

**Price** — $8.00 per 1,000 companies on the FREE tier (+ $0.001 per run); company names that could not be
resolved, sections that could not be reached, every flat child row and every run that returns nothing are
free. Pay-per-event, no API key, no browser, limited permissions — works over the Apify MCP server
(`mcp.apify.com`) and with agentic (x402) payments.

**From code** — `client.actor("insight.solutions/company-dossier-api").call(run_input={…})` with
`apify-client`, or
`POST https://api.apify.com/v2/acts/insight.solutions~company-dossier-api/run-sync-get-dataset-items`.

***

### What you get

One row per company. Abridged, with `nike.com` as the input:

```json
{
  "ok": true,
  "rowType": "dossier",
  "input": "nike.com",
  "domain": "nike.com",
  "resolvedDomain": "nike.com",
  "websiteUrl": "https://www.nike.com/",
  "companyName": "Nike",
  "legalName": "NIKE, Inc.",
  "resolvedFrom": "input-domain",
  "resolutionConfidence": 1,
  "country": "US",

  "identifiers": {
    "domain": "nike.com",
    "cik": "320187",
    "tickers": ["NKE"],
    "sic": "3021",
    "ycSlug": null,
    "ycBatch": null,
    "atsPlatform": "workday",
    "atsBoardSlug": "nike.wd1.myworkdayjobs.com/nike",
    "usaSpendingRecipients": ["NIKE USA, INC."]
  },

  "sectionsFilled": ["profile", "tech", "contacts", "domain", "jobs", "news", "filings", "awards", "recalls"],
  "sectionsEmpty": ["yc", "apps"],
  "sectionsUnavailable": [],
  "sectionCount": 9,
  "itemCount": 49,
  "requestCount": 23,
  "partial": false,
  "billable": true,

  "summary": "NIKE, Inc. is a company in Beaverton, OR. It runs on Akamai and Adobe Analytics. It recruits through Workday. SEC filer, CIK 320187 (NKE). 10 news items in the window.",

  "sections": {
    "profile": {
      "status": "filled",
      "sourceUrl": "https://www.nike.com/",
      "fetchedAt": "2026-09-17T12:00:03.114Z",
      "itemCount": 1,
      "companyName": "Nike",
      "companyNameRule": "jsonld.Organization.name",
      "legalName": "NIKE, Inc.",
      "hqCity": "Beaverton",
      "hqRegion": "OR",
      "hqCountry": "US",
      "foundedYear": 1964
    },

    "jobs": {
      "status": "filled",
      "sourceUrl": "https://nike.wd1.myworkdayjobs.com/nike",
      "itemCount": 0,
      "atsPlatform": "workday",
      "atsPlatformLabel": "Workday",
      "atsBoardUrl": "https://nike.wd1.myworkdayjobs.com/nike",
      "jobsSource": "site-detected",
      "openRoles": null,
      "openRolesNote": "Workday lists postings through a POST with a paged JSON body and a per-tenant site path; the board and its URL are on the row, the open-role count is not."
    },

    "yc": {
      "status": "none",
      "reason": "not-a-yc-company",
      "sourceUrl": "https://www.ycombinator.com/companies?query=Nike",
      "apiUrl": "https://www.ycombinator.com/companies?query=Nike",
      "fetchedAt": "2026-09-17T12:00:03.114Z",
      "itemCount": 0
    }
  }
}
```

That `yc` block is the point of the product. It is not a null. It is *"we asked the Y Combinator
directory for Nike, here is the query, and the answer is no"* — and for the two sections nobody else
sells, `recalls` and `awards`, that answer is what a vendor-risk questionnaire actually needs:

```json
"recalls": {
  "status": "none",
  "reason": "no-results",
  "sourceUrl": "https://www.saferproducts.gov/PublicSearch",
  "apiUrl": "https://www.saferproducts.gov/RestWebServices/Recall?format=json&Manufacturer=Stripe%2C+LLC&RecallDateStart=2016-09-19&RecallDateEnd=2026-09-17",
  "fetchedAt": "2026-09-17T12:00:03.114Z",
  "itemCount": 0,
  "recallCount": 0,
  "byAgency": { "cpsc": 0, "fda": 0 },
  "items": []
}
```

***

### The twelve sections

| # | Section | What it answers | Source | Requests |
|---|---|---|---|---|
| 1 | `profile` | Who are they? | The company's own website | 6 |
| 2 | `tech` | What do they run on? | The pages already fetched, 232 own signatures | **0** |
| 3 | `contacts` | How do I write to the **company**? | The company's own website + `security.txt` | 0 |
| 4 | `domain` | Who hosts, mails and registers them, and since when? | DNS over HTTPS, RDAP, TLS | 5 + 1 socket |
| 5 | `jobs` | What are they hiring for? | The public ATS board they recruit through | 1, up to 4 |
| 6 | `news` | What was said about them this month? | Google News RSS | 1 |
| 7 | `filings` | What do they file, and under what CIK? | SEC EDGAR submissions | 1 |
| 8 | `financials` | What do the numbers say? *(opt-in)* | SEC EDGAR XBRL company facts | 1 |
| 9 | `awards` | Does the US government buy from them? | USAspending | 2 |
| 10 | `recalls` | Has anything of theirs been pulled? | CPSC SaferProducts + openFDA enforcement | 4 |
| 11 | `yc` | Did they go through Y Combinator? | The Y Combinator company directory | 1 |
| 12 | `apps` | What do they ship in the app stores? | iTunes Search + Google Play | 2 |

**Per company: 23 HTTP requests and one TLS socket** at the defaults, and never more than 27. Two more
per *run*, once: the SEC ticker index and the Y Combinator directory's search credentials, both cached.

`tech` and `contacts` cost nothing because they read pages `profile` already fetched. `profile`,
`domain` and the eight off-site sections are what the budget goes on.

Two sections can spend more than their usual cost, and the run log publishes both numbers:

- **`awards` is two POSTs, not one.** USAspending refuses a single query that names both contract and
  grant award-type codes, so contracts and grants are two queries whose results are merged. A third
  POST is allowed once, if the endpoint refuses a field list.
- **`jobs` is one GET when the site's own HTML names a board.** When it does not, the slug-guess
  fallback below tries up to three more.

**Coverage, as numbers.** SEC's ticker index is ≈10,000 US filers. The Y Combinator directory is 6,213
companies. openFDA allows 1,000 requests a day per IP address without a key. USAspending carries awards
from 2007-10-01 onward. Google News RSS returns about 100 items a query. There are 13 ATS platforms in
the detector, 9 of which publish a list endpoint this Actor can count, and 232 technology signatures
across 26 categories — **our own signatures, not a GPL fingerprint database**.

***

### How a company name is resolved

You can send a domain. You can also send `Nike, Inc.`, `NKE`, `320193` or `press@stripe.com`. A name
walks four rungs, cheapest first, and stops at the first one that gives a **verified** answer:

| Rung | Source | Requests | Covers |
|---|---|---|---|
| 0 | The entry is already a domain, a URL or an email address | **0** | every domain input |
| 1 | SEC's `company_tickers.json` | **1 per run**, cached | ≈10,000 US filers, every ticker, every CIK |
| 2 | The Y Combinator directory's search index — its records carry a `website` | 1 per run + 1 search | 6,213 YC companies |
| 3 | `<slug>.com` → `.io` → `.ai` → `.co`, **verified against the page's own identity** | 1–4 | everything whose name maps to its domain |

**Rung 3 accepts a candidate only when the page says who it is.** The page's own name — JSON-LD
`Organization.name`, then `og:site_name`, then the `<title>` split, then the footer copyright — has to
match the name you sent. No identity match, no acceptance: a parked page, a domain squatter or an
unrelated company never becomes an answer. `resolutionConfidence` records which signal matched: `1.0`
you sent the domain, `0.9` an exact SEC or YC match, `0.8` a candidate whose JSON-LD names the company,
`0.6` a candidate confirmed only by `og:site_name` or a footer line.

**Two answers is a question, not an answer.** If two companies answer to the name — three SEC filers
share a prefix, or both `acme.com` and `acme.io` serve a page claiming it — you get a **free**
`ambiguous` diagnostic row listing every candidate with its evidence and its URL. If no rung matches,
you get a **free** `unresolved` row listing every candidate that was tried and why each was refused.
Neither is charged.

#### What the company is *called*

`companyName` is derived from the site with one rule, in this order:

1. JSON-LD `Organization` / `Corporation` `name`, then its `legalName`
2. `og:site_name`
3. the `<title>`, split on `-`, `|`, `—`, `–` and `: `, taking the **shortest** segment that is
   not a generic page word (`Home`, `Welcome`, `Official Site`…)
4. the footer copyright holder
5. and only then the domain label, title-cased — `gusto.com` → `Gusto`

**A meta description is never a name.** The page's `description` and `og:description` are refused
outright, however they reached the field — some content systems copy the SEO title, description and
all, into the structured-data `name`. A `The official website for …` clause is cut off with whatever
separator introduced it. The result is capped at 80 characters, and a candidate that cannot be reduced
to a name is skipped so the next source gets its turn rather than being truncated into one.
`sections.profile.companyNameRule` records which rule produced the name.

**A footer's navigation is never a name either**, and every candidate has to clear three refusals
before it reaches the row:

- **prose** — a sentence boundary inside it, or **more than six words**;
- **navigation vocabulary** anywhere in it: privacy, terms, cookie, accessibility, site map, sitemap,
  careers, contact, login, sign in, all rights reserved, and the rest of a short, published list;
- **a menu shape** — three or more capitalised words of which at least half are page labels.

The footer rung reads only the text immediately after a `©`, `(c)` or `Copyright` mark, up to the first
**comma, period, pipe or line break**. The single exception is a legal form that owns the punctuation:
`Notion Labs, Inc.` and `Apify Technologies s.r.o.` keep theirs, while `SEOMoz, a Ziff Davis company.`
stops at `SEOMoz`. Every `©` on the page is tried in order, so a stray mark above the real line does
not cost you the real line. When every rung fails, the answer is the domain label. The same gate is
applied to `legalName`, which is the field a footer menu actually reached the row on before this rule
existed.

#### How the SEC index is matched

The `filings` section matches the company against SEC's ~10,000-filer ticker index without spending a
request. A ticker or a CIK is used as written. A **name** is matched on a normalised form — lower-case,
punctuation dropped, the legal form (`Inc`, `Corp`, `Ltd`, `PLC`, `LLC`, `Holdings`, `Group`…) dropped,
whitespace collapsed — so `Airbnb` reaches `Airbnb, Inc.`, in three passes: the whole normalised name,
then the domain's own label against the first word of a filer's name, then the first word of the name
the site publishes.

**Every pass requires exactly one filer.** Two filers under one normalised name — `Acme Corp` and
`Acme Holdings Ltd` — makes the section `none` with `reason: "ambiguous"` and the candidates on the
row, because attaching a real company's filings to the wrong dossier is worse than a blank. A prefix is
still not an identity: `Apple Hospitality REIT` never answers for `apple.com`.

**Why Google News cannot do this, and why we say so.** A Google News RSS item's `<source url="…">` is
the *publisher's* domain — `reuters.com`, `bloomberg.com` — never the subject company's. An earlier
draft of this Actor used it as a rung and it resolved `Nike` to `nytimes.com`. It is written down in
the source so the next person does not try it again.

**A name that resolves to a domain you also sent is folded into it and charged once.** `stripe.com`,
`https://www.stripe.com/`, `press@stripe.com` and `Stripe` in one list are one dossier, and the row's
`input` records all four spellings.

***

### Quick start

**One domain.**

```json
{ "companies": ["stripe.com"] }
```

**One company name, for an interview or a first call.**

```json
{ "company": "Allbirds",
  "sections": ["profile", "tech", "jobs", "news", "yc", "apps"],
  "includeSummary": true }
```

**Forty domains, flat, for a spreadsheet.**

```json
{ "companies": ["stripe.com", "nike.com", "…38 more…"],
  "sections": ["profile", "jobs"],
  "flattenSections": true,
  "maxItemsPerSection": 25,
  "maxConcurrency": 5,
  "maxRunSecs": 900 }
```

***

### Input reference

| Field | Type | Default | Notes |
|---|---|---|---|
| `companies` | array of strings | — | Domains, URLs, email addresses, company names, tickers or CIKs — one per line |
| `sections` | array (enum) | eleven of twelve | Which sections to fill. **Turning sections off does not change the price** |
| `maxItemsPerSection` | integer 1–50 | `10` | Jobs, articles, filings, figures, awards, recalls and apps kept per company |
| `includeSummary` | boolean | `true` | A free, deterministic one-paragraph summary. No model, no charge |
| `flattenSections` | boolean | `false` | Also emit one **free** child row per item, for spreadsheets |
| `company` | string | `""` | Single-entry convenience for integrations that cannot send an array |
| `includeFinancials` | boolean | `false` | Adds `financials` — normalised XBRL figures. Off by default: `companyfacts` is megabytes for a large filer |
| `financialsMaxPeriods` | integer 1–40 | `8` | Periods kept when `financials` is on |
| `financialsPeriodKind` | enum | `annual` | `annual` · `quarterly` · `both` |
| `filingForms` | array of strings | `["10-K","10-Q","8-K","20-F","S-1"]` | Empty means every form |
| `newsWindowDays` | integer 1–365 | `90` | How far back the news query reaches |
| `newsSiteScope` | boolean | `false` | Narrow the news query with the company's own domain |
| `awardsWindowDays` | integer 30–7300 | `1825` | USAspending covers 2007-10-01 onward |
| `recallsWindowDays` | integer 30–7300 | `3650` | Ten years, which is the vendor-risk window |
| `maxPagesPerSite` | integer 1–12 | `4` | HTML pages per company site, including the home page |
| `includeAppDetails` | boolean | `false` | Confirms a Play app's publisher website with one extra fetch per app (~2 MB a page) |
| `includePersonalEmails` | boolean | `false` | **Read the Privacy section first.** Person-shaped addresses are dropped unless this is on |
| `secUserAgentContact` | string | `Insight Solutions austinhughhillis@gmail.com` | Used by `filings` and `financials`. SEC asks for `Company Name admin@yourdomain.com` — a name and a reachable address, not an API key. **If you don't set it, the Actor identifies itself** with the default above, so an API or MCP run that sends only `companies` still gets its filings |
| `openFdaApiKey` | string (secret) | `""` | Optional. Raises openFDA's keyless 1,000-a-day-per-IP quota |
| `maxSecsPerCompany` | integer 10–600 | `60` | Hard budget for one company. Sections still running when it expires are marked `timed-out` and the dossier is pushed with what it has |
| `maxConcurrency` | integer 1–10 | `3` | Companies in flight; each gets its own proxy session |
| `sectionConcurrency` | integer 1–8 | `4` | Sections in flight per company |
| `maxRunSecs` | integer 60–3600 | `300` | Wall-clock budget for the run. **No new company is started past 85% of it.** Companies never started are never charged |
| `proxyConfiguration` | object | `{ "useApifyProxy": true }` | Apify **datacenter** proxy. CPSC and SEC are fetched direct first regardless |

***

### Output reference

#### The flat columns

`ok` · `rowType` · `input` · `error` · `errorType` · `scrapedAt` · `source` · `sourceUrl` ·
`domain` · `resolvedDomain` · `redirectedToDifferentDomain` · `websiteUrl` · `companyName` ·
`legalName` · `resolvedFrom` · `resolutionConfidence` · `country` · `identifiers` ·
`sectionsRequested` · `sectionsFilled` · `sectionsEmpty` · `sectionsUnavailable` · `sectionsTimedOut` ·
`sectionsSkipped` · `sectionCount` · `itemCount` · `requestCount` · `partial` · `billable` · `summary` · `sections`

Child rows add `section` · `companyDomain` · `itemType` · `itemId` · `itemTitle` · `itemUrl` ·
`itemDate` · `itemAmount` · `itemCurrency` · `itemParty` · `itemCategory` · `itemStatus` ·
`itemLocation` · `itemDetail`. Diagnostic rows add `candidates` · `triedCandidates` · `apiUrl`.
**Every row type carries every column**, null where it does not apply, so a CSV export is one
rectangle.

#### `identifiers` — the join keys

`domain` · `cik` · `tickers[]` · `exchanges[]` · `sic` · `ycSlug` · `ycBatch` · `atsPlatform` ·
`atsBoardSlug` · `appleDeveloperId` · `googlePlayDeveloper` · `usaSpendingRecipients[]`, in one flat
object so an agent can hand them to another tool. There is **no DUNS** — that is a commercial
identifier we have no licence to — and no professional-network profile URL, which is a decision rather
than an oversight and is stated in *Limitations*.

#### Every section carries the same five stamps

`status` · `reason` · `sourceUrl` (the page a human would read) · `apiUrl` (the exact request) ·
`fetchedAt` · `itemCount`.

| `status` | Means |
|---|---|
| `filled` | The source answered and had content |
| `none` | The source answered and this company has nothing there. **This is an answer**, and `apiUrl` proves it |
| `unavailable` | The source could not be reached. A free diagnostic row names the request |
| `timed-out` | The run stopped waiting for it — at the section's own 45-second deadline or at this company's `maxSecsPerCompany`. A free diagnostic row says so, and the rest of the dossier shipped without it |
| `skipped` | Not requested, or a dependency is missing — a company resolved by name with no domain has no website to read |

`reason` on a `none`: `no-results` · `no-ats-detected` · `not-a-filer` · `ambiguous` (two SEC filers
answer to this name; the candidates are on the section) · `not-a-yc-company` · `no-publisher-match` ·
`name-only-no-domain`.
`reason` on an `unavailable`: `blocked` · `rate-limited` · `timeout` · `upstream-fault` ·
`robots-disallowed` · `budget-stopped`.

#### The child rows

`flattenSections: true` **adds** one row per item on top of the dossier row — never instead of it —
using one canonical twelve-column item shape, so seven different sources land in one table:

| Column | `job` | `news` | `filing` | `award` | `recall` | `app` |
|---|---|---|---|---|---|---|
| `itemId` | posting id | — | accession no. | award id | recall id | app id |
| `itemTitle` | role title | headline | form + document | award description | recall title | app title |
| `itemUrl` | apply URL | Google News link | EDGAR document | usaspending.gov award | agency notice | store listing |
| `itemDate` | posted | published | filed | start date | recall date | released |
| `itemAmount` | — | — | — | award amount | units affected | price |
| `itemCurrency` | — | — | — | `USD` | — | store currency |
| `itemParty` | department | publisher | filer name | awarding agency | recalling firm | developer |
| `itemCategory` | employment type | publisher domain | form family | award type | hazard | store category |
| `itemStatus` | remote / on-site | — | amendment? | active / completed | classification | free / paid |
| `itemLocation` | job location | — | state of incorporation | place of performance | firm country | — |

`financial-period` rows use `itemTitle` = statement + concept, `itemAmount` = value, `itemDate` =
period end. Every child row carries `companyDomain` so it joins back, and `itemDetail` carries the same
object as it appears nested in the dossier row, so nothing is lost by exporting the flat view.

#### Dataset views

`dossiers` (default) · `jobs` · `news` · `filings` · `financials` · `awards` · `recalls` · `apps` ·
`problems`.

#### Row size

A dossier row is kept under a **512 KB soft cap** (Apify's item limit is 9 MB). Free text is clipped at
400 characters; if a row is still over, the longest `items[]` list is truncated first, the section
records `truncated: n`, and a free `row-trimmed` diagnostic says what was cut. The counts and totals on
each section are computed **before** the cut, so `recallCount` is the real number even when `items` is
shorter.

#### How a run is bounded, and when a row reaches you

**A row is pushed the moment its company finishes** — not at the end of the run, not at the end of a
batch. A 25-company run starts filling the dataset within seconds of the first company completing, and
you can read it while the rest are still going.

That only holds if a company always finishes, so there are three nested clocks and each is strictly
shorter than the one above it:

| Clock | Default | What happens when it expires |
|---|---|---|
| One request, retries and backoff included | 30 s | The request fails; the section handles it as any other fault |
| One section | 45 s | The section is `timed-out`, with a free diagnostic row. The other ten carry on |
| One company (`maxSecsPerCompany`) | 60 s | Sections still running are `timed-out`; the dossier is pushed with what it has, and charged on the usual rule — at least one section `filled` |
| The run (`maxRunSecs`) | 300 s | No **new** company is started past 85% of it, so the ones in flight finish and reach the dataset. Companies never started get a free row |

Set `maxRunSecs` at or below the run's platform timeout. A value above it does not buy more time — the
platform aborts first — and the run then ends without the summary it would otherwise write.

Every completed company writes one INFO line to the run log with its domain, how many sections filled,
how many requests it spent and how many milliseconds it took, so a slow source is visible in the log
rather than inferred from a gap in it.

***

### What fills, and what usually does not

**This Actor has not had its first live run yet, so there are no measured fill rates here.** When it
has, this section will publish them per section, as numbers, the way `company-enrichment-api` publishes
`employeeCount` 0 of 6 — and it will publish the skew honestly rather than the average, because the
skew is the honest weakness of a dossier: a US public manufacturer fills eleven sections and a European
private SaaS fills five.

What the offline suite already shows, against the source Actors' own captured fixtures:

- `profile`, `tech`, `contacts` and `domain` fill for every live site tested.
- `filings` fills for a public filer and is `none` / `not-a-filer` for a private one. **Stripe is
  private and its `filings` section says so with the index that proves it.**
- `jobs` fills when the site links to one of the nine boards with a list endpoint, is `filled` with
  `openRoles: null` on Workday and JazzHR, and is `none` / `no-ats-detected` when no board could be
  found or verified.
- `yc` is `none` for most companies, because most companies are not YC companies. That is the answer.
- `apps` is `none` / `no-publisher-match` for a company that publishes no app — the stores returned
  results, none of them belonged to the company, and none was attributed.

`employeeCount`, `foundedYear` and `industry` are the three fields that are empty most often, on every
Actor in this family: most company websites do not state them, and this one does not guess.

***

### What you are never charged for

A `dossier` is charged when **both** hold: the company **resolved**, and **at least one enabled section
is `filled`**. Everything else is free:

- every company name that could not be resolved — with the candidates listed;
- every ambiguous name — with every candidate, its evidence and its URL;
- every free-mail address (`gmail.com`), IP address or non-domain entry;
- every dead domain, bot wall and `robots.txt` refusal;
- every **section** the run could not reach — one free `section-unavailable` row per section, naming the
  request;
- every **section the run stopped waiting for** — one free `section-timed-out` row per section, saying
  which budget expired. The rest of the dossier ships and is charged as any other partial row is;
- every company where **no** section returned anything;
- every flat child row, when `flattenSections` is on — up to sixty per company;
- every company the run never got to, because the time budget or your maximum total charge ran out —
  including every company **not started** past 85% of `maxRunSecs`;
- **and any run that returns no paid row at all**, which finishes FAILED with nothing billed, start fee
  included.

**A dossier where one section filled and ten came back empty IS charged.** "We looked at eleven sources,
here is the one that had something, and here are ten queries that prove the rest are empty" is the
answer the vendor-risk buyer is paying for.

***

### Pricing

| Event | What it is | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|---|
| `actor-start` | Run started | $0.001 | $0.001 | $0.001 | $0.001 |
| **`dossier`** | One company dossier returned | **$0.008** | **$0.008** | **$0.0064** | **$0.0048** |

**$8.00 per 1,000 companies**, and the start fee is charged once per run and only after the first paid
row exists — so a run that returns nothing costs nothing at all.

**One number you can multiply.** There is one paid event. **Turning sections off does not make it cheaper; it makes it faster.** The flat child rows are free, because they contain nothing the dossier row does not already contain.

**One run at $8.00 replaces nine runs that cost $44.10 across nine of our own Actors** — company
enrichment, news, ATS jobs, SEC filings, federal awards, product recalls, domain intelligence, the Y
Combinator directory and app charts, each with its own start fee and its own schema — and it adds four
sections that nothing else in this category sells at any price: recalls, federal awards, Y Combinator
and apps published.

**If you only want a profile, do not run this.** A buyer who wants firmographics, tech stack,
company-level contacts and DNS — sections 1 to 4 — should run
[Company Enrichment API](https://apify.com/insight.solutions/company-enrichment-api) at **$3.50 per
1,000** instead. It is the same code doing the same work for less money, because it makes half the
requests.

***

### FAQ

**Can I send company names instead of domains?** Yes — names, tickers, CIKs, URLs and email addresses
all work. See *How a company name is resolved*. A name that resolves nowhere is free.

**What if two companies share a name?** You get a free `ambiguous` row listing up to five candidates
with their evidence and URLs, and nothing is charged. Send one of their domains and the dossier runs.

**Why is there no CEO name?** Because this Actor returns company-level data only, in every section,
permanently. See *Privacy*.

**Why is there no professional-network profile column?** Because the one everybody means forbids
automated collection in its terms and sits behind an anti-bot wall. See *Limitations*.

**Why is `financials` off by default?** SEC's `companyfacts` document is the only payload in the run
measured in megabytes — several for a large filer. Turn `includeFinancials` on when you want it.

**What does `status: "none"` mean?** That the source answered and this company has nothing there.
`apiUrl` on the section is the query that proves it. It is not the same as `unavailable`, which means
the source could not be reached and which is reported as a free diagnostic row.

**Can I get the rows flat?** Yes — `flattenSections: true` adds one free child row per job, article,
filing, figure, award, recall and app, and the dataset views split them by type.

**Does it work over MCP?** Yes. It is a pay-per-event Actor with limited permissions and no standby
mode, which is what `mcp.apify.com` needs; there is no MCP-specific surface and no per-tool-call
charge.

**Do I need an API key?** No. `secUserAgentContact` is a contact string SEC asks every automated client
for — a name and an address it can reach — not a key: nothing is registered and nothing is issued.
`openFdaApiKey` is optional and only raises a quota.

***

### Limitations

- **Upstream formats change.** Ten sources, ten ways for that to happen. A section whose payload stops
  parsing comes back `unavailable` with a free diagnostic naming the request; one section's bad day
  never costs you the other ten, and never fails the dossier.
- **USAspending matches recipients on text**, so a company with a common name can pull in a namesake.
  `recipientMatched[]` shows the distinct names the endpoint actually returned and
  `recipientMatchQuality` is `exact` or `partial`, so you can see it happen. Its filter takes **one**
  spelling, so the shortest of the names known for the company is the one sent and the rest are used
  only to grade the match; `recipientsSent[]` says which went, `recipientNamesConsidered[]` says what
  was weighed. Contracts and grants are two queries because the endpoint refuses a single one that
  names both, and `awardTypesRead[]` says which of them answered.
- **A board this Actor had to guess at is labelled.** When the site's own HTML names no ATS, `jobs`
  tries `greenhouse:<domain label>`, `lever:<domain label>`, `ashby:<domain label>` and, when it
  differs, Greenhouse for the company name's slug — at most four requests. A guess is accepted only
  when the board answers HTTP 200, parses as a job list with at least one posting, **and** is
  demonstrably that company's: a posting URL on the company's own registrable domain, or a company
  name on the board matching the company's name or domain label. A board that cannot be tied to the
  domain is discarded and `none` stays the answer. `sections.jobs.jobsSource` is `"site-detected"`
  when the marker was in the site's HTML and `"slug-guess"` when it was not, with
  `atsGuessesTried[]` and `atsGuessEvidence` beside it.
- **Workday and JazzHR boards return no open-role count.** Both are detected and named on the row with
  their board URL; Workday needs a POST with a paged JSON body and a per-tenant site path, and JazzHR
  publishes an HTML page rather than a feed. `openRolesNote` says so on the row.
- **Google News links resolve through Google.** Decoding one to the publisher's own URL takes two more
  requests per article, which would double this Actor's whole request count. Items carry the publisher
  name and its domain; for decoded publisher URLs, run
  [Google News Search, Topics & Real Article URLs](https://apify.com/insight.solutions/google-news-api).
- **openFDA allows 1,000 requests a day per IP address without a key.** Three requests a company means
  a very large run on a shared exit can reach it. `openFdaApiKey` is optional and raises the quota.
- **No vehicle recalls and no USDA.** NHTSA is indexed by year, make and model rather than by company,
  and USDA FSIS publishes one 13 MB list. Both are in
  [Product & Vehicle Recalls API](https://apify.com/insight.solutions/product-recalls-api).
- **No hiring velocity.** "How many roles opened and closed this week" needs state across runs, which
  is [New Job Postings Monitor](https://apify.com/insight.solutions/job-postings-monitor).
- **No LinkedIn column, by choice**, and for two stated reasons: their terms of service forbid
  automated collection, and the site is behind an anti-bot wall a keyless, browserless Actor cannot
  pass honestly. A column we could only fill unreliably and impermissibly is a column we do not ship,
  so there is no such URL among the join keys and no such data in any section.
- **No funding rounds, investors, competitor sets or revenue estimates for private companies.** Every
  source for those is a commercial database, and a revenue band derived from a guessed employee count
  is a guess squared. For a **public** company, `financials` returns the real figure from XBRL, sourced
  and dated.
- **No web-search fallback for an unresolvable name in v1.** A search-engine rung would resolve the
  remainder but brings session tokens and a block path into an Actor that already reads ten sources. It
  is a v1.1 question.
- **A company name that reads like a footer link is refused and falls back to the domain label.** The
  name rule rejects any candidate carrying navigation vocabulary — privacy, terms, cookie,
  accessibility, site map, careers, contact, login, sign in, all rights reserved — because a footer
  that renders its menu as bare words after a `©` is otherwise indistinguishable from a copyright line.
  A real `Contact Energy` or `Privacy Dynamics` is therefore reported by its domain label rather than
  by its full name, and `sections.profile.companyNameRule` says `domain.label` when that happened. A
  plain, checkable name is worth more than a menu.
- **A slow source costs you the section, not the dossier.** Every section has a 45-second deadline and
  every company a `maxSecsPerCompany` budget (60 s by default). What is still running when one expires
  is marked `timed-out` with a free row, and the dossier is delivered with what it has. Raise
  `maxSecsPerCompany` when you would rather wait; the sections that do answer are unaffected either way.
- **This Actor has no measured live run yet**, so the fill rates above are unpublished and the launch
  price is modelled rather than measured. Both are fixed before it goes public.

***

### Privacy

**Company-level only. No names of individuals, in any section.** This is a policy, not a default, and
it is enforced at the parser rather than at the row builder — a personal name is never read into memory,
so it cannot leak through a field nobody thought about.

| Section | The people-shaped field upstream | What we do |
|---|---|---|
| `profile` / `contacts` | JSON-LD `Person` nodes, team pages, `firstname.lastname@` | The JSON-LD walker skips `Person` and passes no inheritance; the email filter is a role **allowlist**. `basecamp.com` publishes exactly one address, a person's, and returns **zero** emails |
| `jobs` | `hiringManager`, `recruiter`, `creator`, `user` on several ATS platforms | Not read by any adapter. A test walks every parsed field of every fixture and asserts no personal-name key survives |
| `filings` | SEC submissions carry officer and signatory names in several arrays | Only the company fields are read. The business address is kept because it is a **company** address |
| `financials` | — | XBRL facts are numbers |
| `awards` | `recipient_officers_*` on USAspending's award **detail** endpoint | That endpoint is never called, and the search response carries no officer field |
| `recalls` | CPSC `ConsumerContact` | Kept — it is a company phone number or URL, not a person. Nothing else is read |
| `yc` | `founders[]`, each with a full name, a title and social profile URLs | Those live on a company's YC page, and this Actor never fetches one. The code that would read it is not even vendored |
| `apps` | Apple's `artistName` is usually a company but can be an individual | Kept as `developer`, because it is the publisher of record the store itself shows. An app matching no company signal is not attributed at all |

And, unchanged from the rest of this family: **no email verification of any kind**, no SMTP probe, no
guessed mailbox patterns, no third-party enrichment database. `robots.txt` is honoured on every page and
a refusal is reported rather than worked around. You are the controller of what happens next with
whatever this Actor returns to you.

***

### Use it from an AI agent, or from code

This Actor is pay-per-event with **limited permissions** and no standby mode, which is exactly what the
[Apify MCP server](https://mcp.apify.com) needs, so an agent can call it as a tool with no extra setup
and no per-tool-call surcharge. It is also eligible for agentic (x402) payments.

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("insight.solutions/company-dossier-api").call(run_input={
    "companies": ["stripe.com", "Nike, Inc.", "NKE"],
    "sections": ["profile", "tech", "contacts", "domain", "jobs", "news", "filings", "recalls"],
    "includeSummary": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["rowType"] == "dossier":
        print(row["companyName"], row["sectionsFilled"], row["summary"])
```

**HTTP, one call, rows back in the response**

```bash
curl -X POST "https://api.apify.com/v2/acts/insight.solutions~company-dossier-api/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{"company":"stripe.com","includeSummary":true}'
```

**Every row says where it came from.** `sections.<name>.sourceUrl` is the page a human would read and
`sections.<name>.apiUrl` is the exact request that produced it, so an answer an agent gives from this
data is one a person can check.

### Our other Actors

Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.

**Video, audio & social**

- [YouTube Transcript API](https://apify.com/insight.solutions/youtube-transcript-api) — captions as timed segments, text, SRT or VTT, with language fallback and translation.
- [YouTube Comments API](https://apify.com/insight.solutions/youtube-comments-api) — comments and replies with likes, pinned and hearted flags, newest or top sort.
- [YouTube Channel API](https://apify.com/insight.solutions/youtube-channel-api) — a channel's videos, Shorts and live streams, plus YouTube search.
- [Podcast Search, Episodes & Charts API](https://apify.com/insight.solutions/podcast-api) — Apple Podcasts search, charts and full episode feeds.
- [Bluesky Scraper](https://apify.com/insight.solutions/bluesky-scraper) — profiles, posts, followers and follows from the public AT Protocol API.
- [Telegram Channel Scraper](https://apify.com/insight.solutions/telegram-channel-scraper) — posts, views and channel stats from public Telegram channels.
- [Substack Scraper](https://apify.com/insight.solutions/substack-scraper) — posts with full free text, comments and publication profiles.
- [Hacker News API](https://apify.com/insight.solutions/hacker-news-api) — stories, comments, users, front page and a structured "Who is hiring?" parser from the official HN APIs.

**News, documents & the web**

- [Google News Search, Topics & Real Article URLs](https://apify.com/insight.solutions/google-news-api) — news search and topic feeds with the publisher's real URL decoded.
- [Website to Markdown — Content Extractor for LLMs & RAG](https://apify.com/insight.solutions/website-content-extractor) — any site as clean Markdown, text and heading-aware chunks.
- [Internet Archive API](https://apify.com/insight.solutions/internet-archive-api) — archive.org search, item metadata, files and reviews.
- [Wayback Machine Toolkit](https://apify.com/insight.solutions/wayback-toolkit) — archived URL inventories, snapshots and text diffs between dates.
- [Website Technology Detector](https://apify.com/insight.solutions/website-tech-detector) — the tech stack behind any site, with the evidence for each detection.
- [Domain Intelligence API](https://apify.com/insight.solutions/domain-intelligence-api) — DNS, RDAP registration, TLS certificate and HTTP facts in one row per domain.
- [SEO Page Audit](https://apify.com/insight.solutions/seo-page-audit) — sitemap crawl with on-page checks, structured data and broken-link reports.
- [Keyword Suggestions API](https://apify.com/insight.solutions/keyword-suggestions-api) — Google, YouTube, Bing, Amazon and eBay autocomplete with alphabet and question expansions.
- [Website Contact Extractor](https://apify.com/insight.solutions/website-contact-extractor) — emails, phone numbers and social profiles from any list of websites.
- [Web Search Results API](https://apify.com/insight.solutions/web-search-api) — Bing and DuckDuckGo organic results with snippets, no key, no browser.
- [Company Enrichment API](https://apify.com/insight.solutions/company-enrichment-api) — a domain in, a company profile out: firmographics, contacts, tech stack, DNS and hiring signal.

**Business, finance & jobs**

- [Congress & Insider Trades API](https://apify.com/insight.solutions/congress-insider-trades-api) — STOCK Act periodic transaction reports and SEC Form 4 insider trades in one schema.
- [Federal Contracts, Grants & Lobbying API](https://apify.com/insight.solutions/federal-contracts-grants-api) — SAM.gov opportunities, USAspending awards, Grants.gov notices and Senate lobbying filings in one schema.
- [SEC EDGAR API](https://apify.com/insight.solutions/sec-edgar-api) — filings, XBRL financials and full-text search by ticker or CIK.
- [Clinical Trials & FDA API](https://apify.com/insight.solutions/clinical-trials-fda-api) — ClinicalTrials.gov studies plus openFDA recalls, labels, approvals, 510(k)s and adverse-event reports.
- [Product & Vehicle Recalls API](https://apify.com/insight.solutions/product-recalls-api) — CPSC, NHTSA, FDA and USDA recalls, vehicle complaints and ratings, plus a VIN decoder.
- [Y Combinator Companies, Batches & Founders](https://apify.com/insight.solutions/yc-companies-directory) — the YC directory with founders and social links, filterable by batch, industry and hiring status.
- [Career Site Jobs API](https://apify.com/insight.solutions/ats-jobs-api) — jobs straight from Greenhouse, Lever, Ashby, Workable and 10+ other ATS career sites.
- [New Job Postings Monitor](https://apify.com/insight.solutions/job-postings-monitor) — new, closed and changed postings on the career sites you watch.
- [Remote Jobs API](https://apify.com/insight.solutions/remote-jobs-api) — RemoteOK, Remotive, We Work Remotely, Himalayas, Jobicy and more in one schema, deduplicated.
- [Shopify Products API](https://apify.com/insight.solutions/shopify-products-api) — any Shopify store's catalogue, variants, prices and stock signals.
- [Shopify Store Monitor](https://apify.com/insight.solutions/shopify-store-monitor) — price drops, sales, restocks, sell-outs and new products on any Shopify store, one row per change.

**Apps & games**

- [App Store & Google Play Reviews API](https://apify.com/insight.solutions/app-reviews-api) — reviews from both stores with ratings, versions and developer replies.
- [App Store Top Charts & App Search API](https://apify.com/insight.solutions/app-charts-api) — Apple top charts by country and genre, plus app search and details.
- [App Store Keyword Rank Tracker](https://apify.com/insight.solutions/app-store-keyword-rank-tracker) — where any app ranks for any keyword on the App Store and Google Play, with rank changes and ASO suggestions.
- [Steam Reviews API](https://apify.com/insight.solutions/steam-reviews-api) — Steam reviews with playtime, helpfulness and game details.
- [Steam Game Data API](https://apify.com/insight.solutions/steam-store-stats-api) — prices, tags, review scores, live player counts and top charts.

# Actor input Schema

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

One company per line: a domain (`stripe.com`), a URL, an email address (`press@stripe.com`), a company name (`Nike, Inc.`), a stock ticker (`NKE`) or a CIK. A name is resolved without a search engine — SEC's ticker index, the Y Combinator directory, then candidate domains verified against the page's own JSON-LD or footer. A name that resolves nowhere, or to two companies, gets a free diagnostic row listing what was tried.

## `sections` (type: `array`):

Which of the twelve sections to fill. Each one is read from a first-party source and stamped with the exact request that produced it. Turning sections off does **not** change the price — a dossier is a dossier — it makes the run faster. `financials` is the one section off by default, because SEC's companyfacts payload is measured in megabytes for a large filer.

## `maxItemsPerSection` (type: `integer`):

How many jobs, news articles, filings, financial figures, awards, recalls and apps to keep per company. 10 is a readable dossier; raise it when you want the detail and you are exporting the flat child rows. The counts and totals on each section are computed before this cut, so `recallCount` is the real number even when `items` is shorter.

## `includeSummary` (type: `boolean`):

Adds a free, deterministic paragraph assembled from the row's own fields — no model of any kind, no charge. Every sentence uses a fixed template over a column that is on the row beside it, so you can rebuild it yourself and check it. Turn it off if you only want the structured fields.

## `flattenSections` (type: `boolean`):

Adds one free child row per job, news article, filing, financial figure, award, recall and app, on top of the dossier row — never instead of it. Child rows carry `companyDomain` so you can join them back, and the dataset views split them by type. They cost nothing: they are projections of fields already inside the dossier row you paid for.

## `company` (type: `string`):

One company, for integrations that cannot send an array — a domain, a URL, an email address, a company name, a ticker or a CIK. Merged with anything in `companies`, and deduplicated, so a company named both ways is fetched and charged once.

## `includeFinancials` (type: `boolean`):

Adds the `financials` section: normalised XBRL figures — revenue, income, cash, assets and the rest — from SEC's companyfacts endpoint, for companies that file. Off by default because companyfacts is the only payload in the run measured in megabytes; a large filer's document is several. It fills nothing for a private company.

## `financialsMaxPeriods` (type: `integer`):

How many reporting periods to keep when `financials` is on. Eight annual periods is a decade of history in one row; raise it for a long trend, lower it to keep the row small. Only read when the company is an SEC filer.

## `financialsPeriodKind` (type: `string`):

Annual periods, quarterly periods, or both, when `financials` is on. Annual is the comparable series most analysts want; quarterly is four times the rows and is where a seasonal business shows itself.

## `filingForms` (type: `array`):

Which SEC forms the `filings` section keeps, e.g. `10-K` for the annual report or `8-K` for material events. Leave it empty to keep every form the company filed in the window. Amendments are matched on their base form, so `10-K` also returns `10-K/A`.

## `newsWindowDays` (type: `integer`):

How far back the Google News query reaches. 90 days is a quarter of coverage, which is what an account review wants; 30 is what a pre-call check wants. Articles older than the window are dropped before the cut.

## `newsSiteScope` (type: `boolean`):

Adds the company's own domain to the news query, which helps when the company name is a common word (Apple, Ramp, Stripe) and hurts when the press writes about it without linking to it. Off by default: a quoted company name is the better query for most companies.

## `awardsWindowDays` (type: `integer`):

How far back the USAspending query reaches. 1825 days is five years, which covers a typical contract's full period of performance. USAspending itself carries awards from 2007-10-01 onward, so a window longer than that simply starts there.

## `recallsWindowDays` (type: `integer`):

How far back the CPSC and FDA recall queries reach. 3650 days is ten years, which is the right window for a vendor-risk check — a recall does not stop mattering after a year. Narrow it when you only care about what is current.

## `maxPagesPerSite` (type: `integer`):

HTML pages to read on the company's own site, including the home page. Four buys the home page plus the best three of about/contact/imprint/careers, which is where the firmographics and the company contact live. `robots.txt` is outside this budget and `/.well-known/security.txt` gets one extra allowance.

## `includeAppDetails` (type: `boolean`):

A Google Play search card carries the developer's name and nothing else, so an app is attributed on the name alone. Turning this on fetches each kept app's details page to confirm the publisher's own website against the company's domain. Off by default: a Play details page is about 2 MB, and this costs one per app.

## `includePersonalEmails` (type: `boolean`):

Read the Privacy section of the README before turning this on. By default only role addresses reach the row — info@, sales@, support@, press@, security@ and the rest of the allowlist — and anything shaped like a person's mailbox is dropped at the classifier. With this on, personal data protection is yours to handle: you become the controller of what you do next with it.

## `secUserAgentContact` (type: `string`):

SEC asks every automated client for a User-Agent naming the requester and an address it can reach — `Acme Research data@acme.com` — and answers HTTP 403 without one. It is a contact string, not an API key: nothing is registered and nothing is issued. **If you leave it empty the Actor identifies itself** as `Insight Solutions austinhughhillis@gmail.com`, so `filings` and `financials` work on an API or MCP run that sends no inputs. Set it to put your own name on the request.

## `openFdaApiKey` (type: `string`):

Optional. openFDA answers without a key at 1,000 requests a day per IP address, which a shared datacenter exit can reach on a large run. A free key from open.fda.gov raises that quota. The `recalls` section works without one and nothing else in the Actor uses it.

## `maxSecsPerCompany` (type: `integer`):

Advanced. The hard ceiling on one company. When it runs out, the sections that finished stay on the row, the rest are marked `timed-out` with a free diagnostic each, and the dossier is pushed and charged as any other partial row is. It is what stops one unresponsive website holding a slot for the whole run. Each section also has its own 45-second deadline inside this budget. Raise it for a slow site; lower it to keep a large list moving.

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

How many companies to research at once. Each gets its own proxy session, so one refused site does not burn the exit IP the others are using. Three is the setting the RDAP rate limit and the SEC's per-requester ceiling are both comfortable with; raise it for a long list and watch for rate-limited diagnostics.

## `sectionConcurrency` (type: `integer`):

How many of one company's sections may be on the wire at once. Four keeps the off-site sources running alongside the company's own website, which is the critical path. Lower it if a run at high `maxConcurrency` is pushing memory; the product of the two is how many response bodies can be in flight.

## `maxRunSecs` (type: `integer`):

Wall-clock budget for the whole run, checked before every request. **No new company is started past 85% of it**, so the ones already running finish and reach the dataset; each company's row is pushed the moment that company is done, not at the end of the run. Companies never started get a free row and are never charged for. 300 seconds covers about forty companies at the default concurrency. Keep it at or below the run's platform timeout.

## `proxyConfiguration` (type: `object`):

Apify Proxy settings. The datacenter default answers every source this Actor reads and is far cheaper than residential; switch groups only if a particular company website refuses it. CPSC and SEC are fetched from the machine's own address first whatever this says, because both measurably prefer it.

## Actor input object example

```json
{
  "companies": [
    "stripe.com",
    "nike.com",
    "airbnb.com",
    "allbirds.com"
  ],
  "sections": [
    "profile",
    "tech",
    "contacts",
    "domain",
    "jobs",
    "news",
    "filings",
    "awards",
    "recalls",
    "yc",
    "apps"
  ],
  "maxItemsPerSection": 10,
  "includeSummary": true,
  "flattenSections": false,
  "company": "",
  "includeFinancials": false,
  "financialsMaxPeriods": 8,
  "financialsPeriodKind": "annual",
  "filingForms": [
    "10-K",
    "10-Q",
    "8-K",
    "20-F",
    "S-1"
  ],
  "newsWindowDays": 90,
  "newsSiteScope": false,
  "awardsWindowDays": 1825,
  "recallsWindowDays": 3650,
  "maxPagesPerSite": 4,
  "includeAppDetails": false,
  "includePersonalEmails": false,
  "secUserAgentContact": "Insight Solutions austinhughhillis@gmail.com",
  "maxSecsPerCompany": 60,
  "maxConcurrency": 3,
  "sectionConcurrency": 4,
  "maxRunSecs": 300,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per company with every section nested, plus the free child rows and free diagnostic rows. Delivered as JSON items in the default dataset.

# 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 = {
    "companies": [
        "stripe.com",
        "nike.com",
        "airbnb.com",
        "allbirds.com"
    ],
    "sections": [
        "profile",
        "tech",
        "contacts",
        "domain",
        "jobs",
        "news",
        "filings",
        "awards",
        "recalls",
        "yc",
        "apps"
    ],
    "maxItemsPerSection": 10,
    "includeSummary": true,
    "flattenSections": false,
    "includeFinancials": false,
    "financialsMaxPeriods": 8,
    "financialsPeriodKind": "annual",
    "filingForms": [
        "10-K",
        "10-Q",
        "8-K",
        "20-F",
        "S-1"
    ],
    "newsWindowDays": 90,
    "newsSiteScope": false,
    "awardsWindowDays": 1825,
    "recallsWindowDays": 3650,
    "maxPagesPerSite": 4,
    "includeAppDetails": false,
    "includePersonalEmails": false,
    "secUserAgentContact": "Insight Solutions austinhughhillis@gmail.com",
    "maxSecsPerCompany": 60,
    "maxConcurrency": 3,
    "sectionConcurrency": 4,
    "maxRunSecs": 300,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("insight.solutions/company-dossier-api").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 = {
    "companies": [
        "stripe.com",
        "nike.com",
        "airbnb.com",
        "allbirds.com",
    ],
    "sections": [
        "profile",
        "tech",
        "contacts",
        "domain",
        "jobs",
        "news",
        "filings",
        "awards",
        "recalls",
        "yc",
        "apps",
    ],
    "maxItemsPerSection": 10,
    "includeSummary": True,
    "flattenSections": False,
    "includeFinancials": False,
    "financialsMaxPeriods": 8,
    "financialsPeriodKind": "annual",
    "filingForms": [
        "10-K",
        "10-Q",
        "8-K",
        "20-F",
        "S-1",
    ],
    "newsWindowDays": 90,
    "newsSiteScope": False,
    "awardsWindowDays": 1825,
    "recallsWindowDays": 3650,
    "maxPagesPerSite": 4,
    "includeAppDetails": False,
    "includePersonalEmails": False,
    "secUserAgentContact": "Insight Solutions austinhughhillis@gmail.com",
    "maxSecsPerCompany": 60,
    "maxConcurrency": 3,
    "sectionConcurrency": 4,
    "maxRunSecs": 300,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("insight.solutions/company-dossier-api").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 '{
  "companies": [
    "stripe.com",
    "nike.com",
    "airbnb.com",
    "allbirds.com"
  ],
  "sections": [
    "profile",
    "tech",
    "contacts",
    "domain",
    "jobs",
    "news",
    "filings",
    "awards",
    "recalls",
    "yc",
    "apps"
  ],
  "maxItemsPerSection": 10,
  "includeSummary": true,
  "flattenSections": false,
  "includeFinancials": false,
  "financialsMaxPeriods": 8,
  "financialsPeriodKind": "annual",
  "filingForms": [
    "10-K",
    "10-Q",
    "8-K",
    "20-F",
    "S-1"
  ],
  "newsWindowDays": 90,
  "newsSiteScope": false,
  "awardsWindowDays": 1825,
  "recallsWindowDays": 3650,
  "maxPagesPerSite": 4,
  "includeAppDetails": false,
  "includePersonalEmails": false,
  "secUserAgentContact": "Insight Solutions austinhughhillis@gmail.com",
  "maxSecsPerCompany": 60,
  "maxConcurrency": 3,
  "sectionConcurrency": 4,
  "maxRunSecs": 300,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call insight.solutions/company-dossier-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,insight.solutions/company-dossier-api"
        }
    }
}
```

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/oBlWSZ08wxpDiZhk2/builds/flNj97p6BKyc0BNUt/openapi.json
