# Corporate Decision Intelligence: KYC, Compliance, Supplier Risk (`ryanclinton/opencorporates-search`) Actor

Resolve, score, and monitor companies across 140+ jurisdictions. Each record carries a stable entity ID, a deterministic risk score with evidence, confidence, data quality, and freshness. Free multi-source mode or full OpenCorporates coverage with an API key.

- **URL**: https://apify.com/ryanclinton/opencorporates-search.md
- **Developed by:** [Ryan Clinton](https://apify.com/ryanclinton) (community)
- **Categories:** Lead generation, Developer tools
- **Features:** Limited permissions
- **Stats:** 179 total users, 11 monthly users, 100.0% runs succeeded, 3 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.24 / 1,000 company fetcheds

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

## Corporate Decision Intelligence: KYC, Compliance, Supplier Risk

![Corporate Decision Intelligence: resolve, score and monitor company risk at scale](https://apifyforge.com/readme-assets/ryanclinton-opencorporates-search/hero.png)

**Most company-search tools tell you what a company is. This actor tells you what to do about it.**

Most compliance and procurement teams don't have a data problem. They have a prioritisation problem. This actor is designed to surface the 20 entities that matter, not the 5,000 that don't. Most company-search tools return companies; this actor returns priorities. Deterministic, explainable, no LLM.

### Ready-to-run examples

Don't want to build an input from scratch? Each of these is a published, one-click example ([see all](https://apify.com/ryanclinton/opencorporates-search/examples)) — open it, see real output, run it:

- **[Company Registry Search](https://apify.com/ryanclinton/opencorporates-search/examples/company-registry-search)** — search official company registries by name: registration number, jurisdiction, status, type, incorporation date and registered address
- **[Company Registration Number Lookup](https://apify.com/ryanclinton/opencorporates-search/examples/company-number-lookup)** — look a company up directly by its registration number, with officers and directors
- **[KYC Company Check](https://apify.com/ryanclinton/opencorporates-search/examples/kyc-company-check)** — a due-diligence view: officers, ownership and sanctions health signals plus a risk and resolution score per entity

### In one run you get

- A stable company identity that survives across runs
- A risk decision (`clear` / `review` / `escalate`) with the evidence behind it
- Change detection and risk drift since the last run
- Portfolio-level risk analysis across an entire supplier book
- Recommended, cost-ranked next investigation steps

Search is how the actor works. Decision intelligence is what it produces. Global registry search runs underneath all of it: full OpenCorporates coverage with a key, or free multi-source mode (Companies House, INSEE SIRENE, GLEIF, OpenSanctions, ICIJ Offshore Leaks, OpenOwnership) without one.

### What is Corporate Decision Intelligence?

Traditional company-search tools answer "what is this company?". Corporate Decision Intelligence answers "what should I do about this company?": it resolves the entity, assesses risk, explains the decision, prioritises the investigation, and monitors change over time. Search is infrastructure; the decision is the product.

```text
Company  →  Resolve  →  Assess risk  →  Prioritise  →  Monitor  →  Investigate
```

### What problems does this solve?

- Which of these 5,000 suppliers should I investigate first?
- Which companies became riskier since last week?
- Which counterparties should be escalated to compliance?
- Which company is the correct match among 20 similar names?
- Which enrichment actor should I run next, and is it worth the spend?
- What changed, and does it matter?

### Most tools return records. This returns decisions.

A registry wrapper returns `{ "status": "active" }`. This actor returns:

```json
{
  "companyName": "Example Holdings Ltd",
  "decision": { "status": "escalate", "priority": "high", "confidence": "high" },
  "risk": { "score": 82, "factors": ["appears_in_leaks", "offshore_jurisdiction"] },
  "resolution": { "entityId": "ent_8f7aa1d4e2c9", "identityTier": "verified" },
  "nextActions": ["resolve_ownership", "check_sanctions"]
}
```

Most tools tell you the company exists. This actor tells you what to do next: identity confidence, risk signals with evidence, an escalation decision, change detection, portfolio analytics, and a cost-aware investigation plan. The raw registry data is still there in every record. You just don't have to build these layers on top of it yourself.

### Analyse 50 companies as easily as one

Nobody wakes up wanting to "search a company." They want to analyse their suppliers, counterparties, vendors, or customer book. Pass a list:

```json
{
  "companies": ["Supplier A", "Supplier B", "Supplier C"]
}
```

and one run returns a ranked list of *problems*, not a list of companies:

- Highest-risk entities, each with a relative-risk percentile
- Portfolio outliers (the anomalies worth a second look)
- Offshore / sanctions / inactive concentration
- Jurisdiction exposure across the book
- Shared-officer and shared-address networks
- An investigation priority queue
- Run-over-run risk drift (watchlist mode)

See [Portfolio mode](#portfolio-mode-companies) for the full input shape.

#### Real-world output

A portfolio run returns a triaged book, not a pile of lookups:

```json
{
  "portfolio": { "total": 500, "highRisk": 23, "review": 61, "clear": 416 },
  "priorityQueue": [
    { "companyName": "Example Holdings", "riskPercentile": 98, "status": "escalate" }
  ]
}
```

500 suppliers analysed. 23 need escalation. Start with the top 20 in the priority queue.

### Corporate Memory

Most company-search tools forget everything between runs. This actor remembers. Set a `watchlistName` and it tracks each entity across runs:

- First seen and last seen
- Risk trajectory (rising / falling / stable)
- Change history, and how many runs moved a tracked field
- Risk increases since the last run
- Entity volatility over time

So you can ask "which suppliers became riskier?" instead of "what does this company look like today?". By run 10 you hold a per-entity track record a fresh competitor run cannot backfill.

### Questions you can answer

**Can answer:**

- Which suppliers should I investigate first?
- Which companies became riskier since the last run?
- Which entities require escalation?
- Which companies look unusual in my book?
- Which jurisdictions dominate my portfolio?
- Which entities share officers or addresses?
- Which enrichment is worth running next?

**Cannot answer (chain a specialist actor instead):**

- Beneficial-ownership chains and ultimate-beneficial-owner determination
- Cross-registry ownership graphs

For ownership depth, follow the LEI / ownership siblings named in each record's `actorGraph.next[]`.

![What you also get: decision per record, stable entity IDs, portfolio triage and corporate memory](https://apifyforge.com/readme-assets/ryanclinton-opencorporates-search/feature-callouts.png)

### How this differs

| Capability | Registry APIs | Registry scrapers | This actor |
|------------|:-:|:-:|:-:|
| Company search | ✓ | ✓ | ✓ |
| Entity resolution (stable ID) | ✗ | ✗ | ✓ |
| Confidence scoring | ✗ | ✗ | ✓ |
| Risk signals with evidence | ✗ | Partial | ✓ |
| Escalation decisions | ✗ | ✗ | ✓ |
| Change detection over time | ✗ | ✗ | ✓ |
| Portfolio analysis | ✗ | ✗ | ✓ |
| Investigation prioritisation | ✗ | ✗ | ✓ |
| Next-step recommendations | ✗ | ✗ | ✓ |

### Why teams switch from registry APIs

- Registry APIs return records. **This actor returns decisions.**
- Registry APIs forget previous runs. **This actor tracks risk over time.**
- Registry APIs make you invent your own scoring. **This actor provides an escalation decision with the evidence attached.**
- Registry APIs leave enrichment planning to you. **This actor predicts which enrichment is worth running next.**

The raw registry data is still in every record. You just stop building these layers yourself.

### Before and after

**Before:** search a company → get 50 records → manually inspect each → guess which one matters → repeat for the next company.

**After:** search a company → get one verified entity → receive a risk decision → see the evidence behind it → know exactly what to investigate next. Feed a list of 50 companies and get the whole book triaged at once.

### Built for

- **Compliance teams** — escalate only the entities that matter, with the evidence attached for audit.
- **Procurement teams** — prioritise supplier risk across an entire vendor book in one run.
- **Investigators** — resolve ambiguous entities and follow evidence-backed risk signals.
- **AI workflows** — branch on deterministic decisions (`decision.status`) instead of parsing text.
- **Data teams** — join on stable `entityId` across runs and enrichment pipelines.

### Built for automation

Most systems force you to invent thresholds: `if risk.score > 62`. This actor already makes the routing decision for you: `if decision.status == "escalate"`. Every result is a routing primitive you can branch on directly in:

- Dify, n8n, Make, Zapier
- MCP / agent tool calls
- Internal compliance workflows and case-management queues

No prose parsing, no threshold-guessing. The decision, its priority, its reason codes, and its confidence are all stable enum values.

### Why deterministic beats AI-generated risk scores

Many compliance tools produce opaque, AI-generated risk scores you cannot defend in an audit. This actor attaches the receipts to every decision:

- **Why was this escalated?** The `risk.factors` and `decision.reasonCodes`.
- **Which source contributed?** The `risk.evidence[]` carries `{ code, weight, source }`.
- **How confident is the identity match?** The `resolution.identityTier` and `confidenceFactors`.
- **Will it reproduce?** The same input and sources produce the same output, every run.

No LLM, no randomness, no black box. That auditability is what makes the output usable in regulated KYC and compliance workflows.

### Why use this actor?

- **The same company gets the same identity every time.** No duplicate companies, no rematching names, no broken joins. Every resolved company receives a stable identity (`entityId`) that stays constant across runs and sibling actors, so you can dedupe, monitor, and enrich the same entity over time without re-matching strings. (Under the hood it is a deterministic hash of the normalised name, jurisdiction, and number, so it is reproducible, not guessed.)
- **Two paths, one actor.** With an OpenCorporates API key: 200M+ companies across 140+ jurisdictions in a single search. Without a key: free multi-source mode covering UK (Companies House full register), France (INSEE SIRENE full register), and globally-LEI'd entities (GLEIF, ~2.7M legal entities), with sanctions / leak / ownership enrichment.
- **Zero infrastructure required.** The actor runs on Apify's cloud platform with automatic retries, rate-limit handling, and exponential backoff built in. No servers to provision, no API client code to write.
- **Structured, export-ready output.** Results land in a clean Apify dataset you can download as JSON, CSV, Excel, or XML -- or pipe directly into Google Sheets, Zapier, Make, Slack, and thousands of other tools.
- **Schedule and automate.** Use Apify Schedules to run recurring searches on any cron pattern for ongoing corporate monitoring, compliance screening, or market research.
- **Intelligence, not just records.** Every company record is scored, classified, and signalled — entity-resolution confidence, deterministic risk (offshore / sanctions / leak / ownership signals), data-quality completeness, health flags, and freshness — so KYC, due-diligence, and compliance consumers branch on decisions, not raw fields.
- **Deterministic and reproducible.** Every score, tier, decision, risk factor, and prediction is computed by a documented rule from the sources in hand. No LLM, no randomness: the same input and sources produce the same output, run after run, with the evidence attached. That auditability is what makes it usable in compliance and KYC workflows. The AI-agent compatibility (MCP, Dify branching, the `llm` output profile) is a side benefit of that determinism, not the headline.
- **Chain with other actors.** Every record carries `actorGraph.next[]` pointing at sibling actors (UK Companies House, VAT validation, sanctions screening, LEI lookup) so downstream pipelines can branch on it without parsing prose.

***

### Key features

- **Entity-resolution + risk intelligence layer** -- every company record carries a `resolution` block (stable `entityId`, 0-100 confidence, source count), a deterministic `risk` block (0-100 score + level + stable factor codes), a `dataQuality` completeness block, boolean `healthSignals`, and a `freshness` indicator. Computed from the sources already fetched: no extra API calls, no LLM, fully reproducible. Use `outputProfile: "intelligence"` for the flagship decision-first payload.

- **200M+ companies, 140+ jurisdictions** with an OpenCorporates API key -- search across the United States (all 50 states), United Kingdom, Germany, France, Australia, Canada, and dozens more in a single query

- **Free multi-source mode** without a key -- Companies House (GB), INSEE SIRENE (FR), and GLEIF for global LEI entities, enriched with OpenSanctions, ICIJ Offshore Leaks, and OpenOwnership

- **Provenance and confidence metadata** -- every record carries a `_meta` block listing contributing sources, the canonical source, coverage class (registry / sanctions / leak / ownership), normalised entity type, and any alternative field values surfaced by other sources

- **Conservative dedupe** -- jurisdiction-aware canonical-number matching, three-way concordance for non-offshore jurisdictions, additional concordance signal required for offshore jurisdictions to prevent shelf-company false merges

- **Jurisdiction-level filtering** -- narrow results with jurisdiction codes like `us_ca` for California, `gb` for the United Kingdom, or `de` for Germany

- **Country-level filtering** -- use broader two-letter country codes (`us`, `gb`, `de`) when you do not need state or province precision

- **Company status filtering** -- filter by Active, Inactive, or Dissolved to focus on the companies that matter to your use case

- **Officer and director search** -- enable the `includeOfficers` option to retrieve directors and officers matching your query alongside company results

- **Automatic pagination** -- fetches up to 100 results per run with rate-limit handling and exponential backoff retries built in

- **Clean address formatting** -- combines street address, locality, region, postal code, and country into a single human-readable string

***

### How to use

#### Using the Apify Console

1. Navigate to the [OpenCorporates Global Company Search](https://apify.com/ryanclinton/opencorporates-search) actor page on Apify.
2. Click **Start** to open the input form.
3. Enter your **Search Query** -- a company name, keyword, or partial name (e.g., "Tesla", "Acme Corp").
4. Optionally set **Jurisdiction Code**, **Country Code**, or **Company Status** filters.
5. Paste your **OpenCorporates API Key** into the API Key field (get one at [opencorporates.com/api_accounts/new](https://opencorporates.com/api_accounts/new)).
6. Toggle **Include Officers/Directors** if you need officer data.
7. Set **Max Results** (1--100) depending on how many records you need.
8. Click **Start** and view results in the **Dataset** tab when the run completes.

#### Using the Apify API -- JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('ryanclinton/opencorporates-search').call({
    query: 'Tesla',
    countryCode: 'us',
    status: 'Active',
    apiKey: 'YOUR_OPENCORPORATES_API_KEY',
    maxResults: 50,
    includeOfficers: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Using the Apify API -- Python

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_APIFY_TOKEN')

run = client.actor('ryanclinton/opencorporates-search').call(run_input={
    'query': 'Tesla',
    'countryCode': 'us',
    'status': 'Active',
    'apiKey': 'YOUR_OPENCORPORATES_API_KEY',
    'maxResults': 50,
    'includeOfficers': True,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
for item in items:
    print(item)
```

***

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `query` | String | Yes | -- | Company name, keyword, or registration number to search for (e.g., "Google", "Tesla Motors", "C3259768") |
| `jurisdictionCode` | String | No | -- | Two-letter jurisdiction code (e.g., `us_ca` for California, `gb` for UK, `de` for Germany). Leave empty to search all jurisdictions |
| `countryCode` | String | No | -- | Two-letter country code for broader geographic filtering (e.g., `us`, `gb`, `de`) |
| `status` | String | No | All | Filter by company status: `Active`, `Inactive`, or `Dissolved` |
| `lookupType` | String | No | `auto` | `auto` (default) detects a registration-number-shaped query when a jurisdiction is set and looks it up directly; otherwise name search. `number` forces direct by-number lookup (needs a jurisdiction/country code). `name` always searches by name. See "Lookup by registration number" below |
| `apiKey` | String | No | -- | OpenCorporates API key (optional). Without a key the actor runs the free multi-source chain. With a key you get full OpenCorporates coverage including US private entities. Get one at [opencorporates.com](https://opencorporates.com/api_accounts/new) |
| `fallbackMode` | String | No | `auto` | `auto` (default) uses the free chain when no key is provided. `free` forces the free chain. `paid` requires an OpenCorporates API key |
| `outputProfile` | String | No | `standard` | Payload shape. `minimal` (top-level fields only), `standard` (top-level + compact `_meta` + intelligence blocks), `full` (everything), `llm` (standard + per-record `summary` string), `intelligence` (decision-first: leads with the intelligence blocks, drops `_meta` diagnostics) — see below |
| `includeOfficers` | Boolean | No | `false` | Also search for officers/directors matching the query |
| `maxResults` | Integer | No | `25` | Maximum number of results to return (1--100) |
| `watchlistName` | String | No | -- | Optional. Enables cross-run monitoring: stores a per-entity snapshot in a named key-value store and adds `monitoring` + `history` + `riskTrend` blocks reporting what changed since the last run on the same watchlist. See "Monitoring mode" below |
| `companies` | Array | No | -- | Optional. List of company names/numbers to process as a portfolio (overrides `query`). Each is searched in turn; the summary record carries a portfolio rollup + ranked priority queue. Capped at 50. See "Portfolio mode" below |

#### Example input JSON

```json
{
    "query": "Goldman Sachs",
    "countryCode": "us",
    "status": "Active",
    "apiKey": "YOUR_OPENCORPORATES_API_KEY",
    "includeOfficers": true,
    "maxResults": 25
}
```

#### Tips for input configuration

- Use `jurisdictionCode` for state-level precision (e.g., `us_ny` for New York) and `countryCode` for broad country-level filtering. You can use both together.
- Start with a small `maxResults` (10--25) to validate your query before scaling up to 100.
- The `apiKey` field is marked as secret -- it will not appear in run logs or shared configurations.

#### About `outputProfile: "llm"`

When set to `llm`, every company record carries a `summary` field — a single plain-English string AI agents can quote without joining fields. Format:

```
ACME Holdings Limited · (GB) · status: Active · number: 1234567 · incorporated 2014-08-21 · sources: companies-house, gleif
```

The summary is deterministic and includes whichever of `companyName`, `jurisdiction`, `status`, `companyNumber`, `incorporationDate`, and `_meta.sources` are populated. Compact enough to fit inside a tool-call message, parseable by humans, and stable across runs.

#### About `entityType` (filtering hint)

Every company record carries a normalised `entityType` enum: `operating_company / holding_company / issuer / fund / branch / subsidiary / sole_proprietor / nonprofit / government / unknown`. Useful when you only want operating companies and don't want issuance vehicles polluting the result set. For example, a search for "Barclays" can return dozens of GLEIF-registered issuance and treasury subsidiaries; filtering `entityType === "operating_company"` keeps the operating banks and drops the vehicles. Downstream JSONata / Dify / n8n consumers can branch on this without parsing prose.

```json
{
    "_filter_example": "items[?entityType=='operating_company']",
    "_drop_issuers_example": "items[?entityType!='issuer' && entityType!='fund']"
}
```

#### Lookup by registration number

Set `lookupType: "number"` (or leave it on `auto` with a registration-number-shaped `query`) plus a jurisdiction to fetch a specific company directly instead of searching by name:

```json
{
    "query": "C3259768",
    "jurisdictionCode": "us_ca",
    "lookupType": "number",
    "apiKey": "YOUR_OPENCORPORATES_API_KEY"
}
```

Direct by-number lookup works on the paid OpenCorporates path for any jurisdiction (via the `/companies/{jurisdiction}/{number}` endpoint) and on the free path for the UK via Companies House. A jurisdiction/country code is required — a bare number is ambiguous across registries. If the direct lookup finds nothing, the actor falls back to a name search so you still get results.

#### Monitoring mode (`watchlistName`)

Set `watchlistName` to turn a one-off search into a recurring monitor. The actor stores a per-entity snapshot (status, risk score, officer count, address presence) in a named key-value store keyed by the watchlist name, and on the next run adds a `monitoring` block to each company record:

```json
{
    "monitoring": {
        "changeType": "changed",
        "changedFields": ["status", "riskScore"],
        "previousState": { "status": "Active", "riskScore": 20 }
    }
}
```

- `changeType` is `new` (first sight on this watchlist), `unchanged`, or `changed`.
- `changedFields[]` lists which tracked fields moved: `status`, `riskScore`, `officers`, `address`.
- The first run on a new watchlist logs a notice and marks every record `new`; change detection activates from the second run onward.
- Records are keyed on the stable `resolution.entityId`, so the same company is tracked across runs even as other fields shift. The snapshot is bounded (50,000 entities, FIFO). Schedule the actor with the same `watchlistName` on a cron pattern to track companies over time.
- Alongside `monitoring`, each record carries a `history` block in watchlist mode: `firstSeen`, `lastSeen`, `changeCount` (how many runs changed a tracked field), and `runsSeen`. Compliance teams use `history.changeCount` to surface the most volatile entities on a watchlist without diffing runs themselves.
- Each record also carries a `riskTrend` block in watchlist mode (`current`, `previous`, `delta`, `direction`) so you can answer "whose risk went up since last run?" with `WHERE riskTrend.direction = "up"`.

#### Portfolio mode (`companies[]`)

Pass a list of companies to triage a whole supplier / vendor / counterparty book in one run. Each company is searched in turn (its records stream as it finishes), and the summary record carries portfolio-level intelligence:

```json
{
    "companies": ["Acme Holdings", "Globex SA", "Initech Ltd"],
    "countryCode": "gb",
    "watchlistName": "key-suppliers"
}
```

The summary record (and the `SUMMARY` KV key) then carries:

- `portfolio` — `{ total, highRisk, offshore, sanctions, inactive, ownershipUnknown, escalate, review, clear }` counts across the book. Answers "what is the composition of my supplier book?".
- `jurisdictionExposure` — `[{ jurisdiction, count }]` sorted by count. Your geographic concentration (e.g. 320 GB, 22 KY) — compliance teams gate on offshore share.
- `riskClusters` — `[{ factor, count }]` sorted by count. Answers "*what kind* of risk do I have?" (42 offshore, 7 in-leaks) instead of "which companies have risk?".
- `priorityQueue` — the top 20 entities ranked by `decision.priorityScore`, each with `entityId`, `companyName`, `jurisdiction`, `priorityScore`, `status`, `reasonCodes`, and a `riskPercentile` + `riskTier` (relative risk within the run, e.g. "riskier than 92% of this book"). This is the "show me the 20 problems, not the 5,000 companies" view.
- `outliers` — the anomalies in the book (`highest_risk`, `only_offshore_entity`, `only_sanctioned_entity`, `only_entity_in_leaks`, `only_inactive_entity`). Compliance teams care more about what is unusual than what is average. Emitted for portfolios of 3+ companies.
- `network` — officers and registered addresses shared across ≥2 companies in the book (with `riskyConnections` flagging shared groups that contain an escalate-status company).
- `watchlistSummary` (when `watchlistName` is also set) — `{ newCompanies, changesDetected, highRiskEntities, newRisks }`, a run-over-run dashboard.

Each company record carries a `query` field naming which input produced it. The portfolio is capped at 50 companies per run; one company failing does not abort the others (it lands as an error record tagged with its `query`).

***

### Output

![Sample output table: company, jurisdiction, risk score, decision, identity tier and next action per record](https://apifyforge.com/readme-assets/ryanclinton-opencorporates-search/output-table.png)

#### Company result example

```json
{
    "companyName": "TESLA, INC.",
    "companyNumber": "C3259768",
    "jurisdictionCode": "us_ca",
    "jurisdiction": "US - CA",
    "incorporationDate": "2003-07-01",
    "dissolutionDate": null,
    "companyType": "Domestic Stock",
    "registryUrl": "https://bizfileonline.sos.ca.gov/search/business",
    "status": "Active",
    "registeredAddress": "3500 Deer Creek Road, Palo Alto, CA, 94304, US",
    "source": "California Secretary of State",
    "opencorporatesUrl": "https://opencorporates.com/companies/us_ca/C3259768",
    "officers": null
}
```

#### Free-mode example (no API key — multi-source chain)

When the actor runs without an OpenCorporates API key, results come from the free chain and carry a `_meta` block describing provenance. The `companyName`, `companyNumber`, `jurisdictionCode`, `status`, `incorporationDate`, `registeredAddress`, and `officers` top-level fields stay shape-compatible with the paid mode for downstream consumers reading by field name.

```json
{
    "companyName": "Acme Holdings Limited",
    "companyNumber": "1234567",
    "jurisdictionCode": "gb",
    "jurisdiction": "GB",
    "incorporationDate": "2014-08-21",
    "dissolutionDate": null,
    "companyType": "private-limited-company",
    "registryUrl": "https://find-and-update.company-information.service.gov.uk/company/1234567",
    "status": "Active",
    "registeredAddress": "1 Example Street, London, EC1A 1BB, GB",
    "source": "companies-house",
    "opencorporatesUrl": null,
    "officers": null,
    "entityType": "operating_company",
    "_meta": {
        "sources": ["companies-house", "gleif", "opensanctions"],
        "canonicalSource": "companies-house",
        "coverageClass": "registry",
        "coverageClasses": ["registry", "sanctions"],
        "matchedBy": "canonicalNumber",
        "sourcePriority": 0.95,
        "snapshotDate": "2026-05-13",
        "investigativeOnly": false,
        "normalisedName": "acme holdings",
        "softClusterId": null,
        "sourceEntityType": {
            "companies-house": "private-limited-company",
            "gleif": "GENERAL"
        },
        "alternates": {
            "companyName": [
                { "value": "ACME HOLDINGS LTD", "source": "opensanctions" }
            ]
        },
        "candidateMatches": []
    }
}
```

#### Officer result example (when `includeOfficers` is enabled, paid path)

```json
{
    "resultType": "officer",
    "name": "Elon Musk",
    "position": "chief executive officer",
    "startDate": "2008-10-15",
    "endDate": null,
    "companyName": "TESLA, INC.",
    "companyNumber": "C3259768",
    "jurisdictionCode": "us_ca",
    "opencorporatesUrl": "https://opencorporates.com/officers/123456789"
}
```

#### Output fields reference

| Field | Type | Description |
|-------|------|-------------|
| `companyName` | String | Official registered name of the company |
| `companyNumber` | String | Registration number assigned by the official registry |
| `jurisdictionCode` | String | Jurisdiction code in OpenCorporates format (e.g., `us_ca`, `gb`) |
| `jurisdiction` | String | Human-readable jurisdiction label (e.g., "US - CA", "GB") |
| `incorporationDate` | String/null | Date the company was incorporated (YYYY-MM-DD) |
| `dissolutionDate` | String/null | Date the company was dissolved, if applicable |
| `companyType` | String/null | Legal entity type (e.g., "Domestic Stock", "Limited Company") |
| `registryUrl` | String/null | URL of the official government registry page |
| `status` | String/null | Current company status (e.g., "Active", "Dissolved") |
| `registeredAddress` | String/null | Formatted registered address combining street, locality, region, postal code, and country |
| `source` | String/null | Name of the official registry publisher (e.g., "California Secretary of State") |
| `opencorporatesUrl` | String/null | Direct URL to the company's OpenCorporates profile page. Always `null` in free mode -- the actor never fetches opencorporates.com pages without an API key. |
| `officers` | Array/null | Officer data (null for company search results; officers are returned as separate dataset items). In free mode, officer data is only populated when Companies House supplied it for a GB company with `includeOfficers: true`. |
| `entityType` | String | Normalised entity-type enum: `operating_company`, `holding_company`, `issuer`, `fund`, `branch`, `subsidiary`, `sole_proprietor`, `nonprofit`, `government`, `unknown`. Use this to filter (e.g. drop `issuer` records when you only want operating companies). |
| `_meta` | Object | Provenance + merge metadata (free mode). Contains `sources[]`, `canonicalSource`, `coverageClass`, `coverageClasses[]` (all contributing classes when merged), `matchedBy`, `sourcePriority`, `snapshotDate`, `investigativeOnly`, `normalisedName`, `softClusterId`, `sourceEntityType` (each source's raw type), `alternates` (field values that disagreed across sources), and `candidateMatches[]`. |
| `resultType` | String | Present only on officer results -- always set to `"officer"` |
| `recordType` | String | Discriminator on every record: `company` (an entity), `advisory` (a coverage-gap warning record), or `summary` (the run-level summary, one per run, last in the dataset). Filter with `WHERE recordType = "company"` to get only entities. |
| `schemaVersion` | String | Output-shape version (e.g. `1.1.0`), independent of the actor build version. Branch on this to detect additive shape changes without inspecting the build tag. |
| `actorGraph` | Object | Per-`company` next-best-actor pointers: `{ current, next[] }` where each `next[]` entry is `{ actor, reason, expectedYield? }` naming a sibling actor that enriches or verifies this record. **`next[]` is ordered by `expectedYield` (highest first)** — it is the cost-aware investigation plan, so `actorGraph.next[0]` is the enrichment to run first. `expectedYield` (`high`/`medium`/`low`, from `coveragePrediction`) tells you whether each sibling is worth the spend. |
| `failureType` | String | Present only on error records (`error: true`). Classifies the failure: `invalid-input`, `timeout`, or `api-error`. Lets you tell bad input from upstream problems. |

#### Intelligence layer (on every `company` record)

Computed deterministically from the sources already fetched — no extra API calls, no LLM. Included in the `standard`, `full`, `llm`, and `intelligence` output profiles; stripped in `minimal`.

| Field | Type | Description |
|-------|------|-------------|
| `decision` | Object | **The routing primitive + explainability report** — branch on this instead of thresholding raw scores: `status` (`clear` / `review` / `escalate`), `priority` (`high`/`medium`/`low`), `priorityScore` (0-100 sortable investigation-queue score), `reasonCodes[]` (the "because" — the risk factors behind it), `confidence` (`high`/`medium`/`low`, from identity strength + evidence depth). `if decision.status == "escalate"` is cleaner than `if risk.score > 62`. |
| `coveragePrediction` | Object | Predicts whether enrichment would yield data **before you spend on it**: `registry` / `ownership` / `officers`, each `confirmed` / `likely` / `unlikely` / `unknown`. Pairs with `actorGraph.next[].expectedYield` so a workflow can skip enrichment that would return nothing. Deterministic heuristic from current coverage + jurisdiction. |
| `resolution` | Object | Entity-resolution confidence: `entityId` (stable sha256-derived id, joinable across runs and sibling actors), `confidenceScore` (0-100), `resolutionLevel` (`high`/`medium`/`low`), `identityTier` (compliance 5-tier: `verified` / `strong` / `probable` / `weak` / `unresolved`), `matchedSources`, `matchedBy`, and `confidenceFactors[]` (stable codes: `registry_match`, `jurisdiction_match`, `company_number_match`, `multi_source_confirmation`, `canonical_number_merge`). |
| `risk` | Object | Deterministic corporate-risk signal: `score` (0-100), `level` (`high`/`medium`/`low`/`minimal`), `factors[]` (stable codes), and `evidence[]` — the receipts behind each factor: `{ code, weight, source }` (e.g. `{ "code": "appears_in_leaks", "weight": 30, "source": "icij-leaks" }`). Factor codes: `offshore_jurisdiction`, `appears_in_leaks`, `sanctions_association`, `ownership_unverified`, `inactive_registry_status`, `multiple_candidate_matches`. |
| `consensus` | Object | Cross-source agreement (free path): `agreement` (0-100), `sources` (count), `disputedFields[]` (fields where sources disagreed). High agreement across multiple sources is a trust signal; disputed fields flag where to verify. |
| `dataQuality` | Object | Field-completeness: `score` (0-100), `presentFields[]`, `missingFields[]` over the core registry fields. |
| `healthSignals` | Object | Automation-friendly booleans: `active`, `officersPresent`, `registeredAddressPresent`, `ownershipKnown`, `sanctionsClear`. |
| `freshness` | Object | `source` (`live-registry`/`snapshot`), `snapshotDate`, `daysOld`, `tier` (`live`/`high`/`medium`/`low`). Snapshot enrichment sources carry a date; live registry lookups report `live`. |
| `ownershipReadiness` | Object | Beneficial-ownership discovery readiness: `available` (an ownership-class source already contributed), `sourceCount`, `actor` (sibling slug that resolves/extends ownership). Branch on `available === false` to decide whether to run the ownership sibling next. |
| `nextActions` | Array | Deterministic investigation hints — stable verb codes derived from risk / jurisdiction / entity type: `check_sanctions` (risk ≥ 60 or sanctions/leak signal), `verify_vat` (EU jurisdiction), `resolve_ownership` (holding / issuer / fund / offshore), `confirm_registry` (no company number). Distinct from `actorGraph` (which names actor slugs); these are the action intents a workflow branches on. |
| `monitoring` | Object | Present only when `watchlistName` is set. Cross-run change detection: `changeType` (`new`/`unchanged`/`changed`), `changedFields[]` (`status`/`riskScore`/`officers`/`address`), `previousState` (`{status, riskScore}` or null on first sight). See "Monitoring mode" above. |
| `riskTrend` | Object | Present only when `watchlistName` is set. Risk drift vs the prior run: `current`, `previous` (null on first sight), `delta`, `direction` (`up`/`down`/`flat`/`new`). Answers "what changed?" not "what exists?". |
| `history` | Object | Present only when `watchlistName` is set. Cross-run entity memory: `firstSeen`, `lastSeen`, `changeCount` (runs where a tracked field changed), `runsSeen`, `riskChanges` (runs where the risk score specifically moved), `sourcesSeen` (max distinct sources ever), `riskTrajectory` (`rising`/`falling`/`stable`/`new` over the retained history). Keyed on the stable `resolution.entityId` — the corporate-memory competitors can't backfill. |
| `query` | String | Portfolio mode only. The input company name/number that produced this record. |

#### Summary record

The last record in every run is a `recordType: "summary"` record carrying the run-level `coverage` block (sources attempted / responded / timed out, records returned, coverage classes), a `coverageReport` (jurisdiction / ownership / officer coverage tiers, an `overallCoverage` 0-100 score, plus a `scores` heatmap with per-class numeric coverage — `registry`, `sanctions`, `leak`, `ownership`, `officers` each 0-100 — across the result set), a `portfolio` rollup (`{ total, highRisk, offshore, sanctions, inactive, ownershipUnknown, escalate, review, clear }`), a `priorityQueue` (top 20 entities ranked by `decision.priorityScore`, each with a `riskPercentile` + `riskTier` = relative risk within the run), a `jurisdictionExposure` array (`{ jurisdiction, count }` sorted by count — your supplier-book geography), a `riskClusters` array (`{ factor, count }` sorted — *what kind* of risk you hold, not just which companies), an `outliers` array (`{ entityId, companyName, reason }` — the anomalies: `highest_risk`, `only_offshore_entity`, `only_sanctioned_entity`, etc.; compliance cares about anomalies more than averages), an optional `network` block (officers AND registered addresses shared by ≥2 companies, each with `strength` = company count, plus `riskyConnections` = shared groups containing an escalate-status company), an optional `watchlistSummary` (watchlist mode), `dataGaps[]` (named gaps with a `suggestedFix` and `targetActorSlug`), a run-level `actorGraph`, and `schemaVersion`. The same object is also mirrored to the run's `SUMMARY` key-value-store key so API / Console / MCP consumers can read coverage without scanning the dataset.

***

### Use cases

- **KYC and due diligence** -- verify company existence, registration status, and registered addresses across 140+ jurisdictions as part of Know Your Customer workflows
- **Competitive intelligence** -- track competitor registrations, monitor new incorporations in your industry, and identify corporate structures across multiple countries
- **Compliance screening** -- check whether counterparties are active, dissolved, or inactive before entering business relationships
- **Corporate genealogy research** -- trace company histories, dissolution dates, and officer tenures to understand corporate evolution over time
- **Lead generation and enrichment** -- find companies matching specific criteria and enrich lead databases with official registry data
- **Academic and journalistic research** -- investigate corporate structures, cross-border registrations, and officer networks for research publications
- **M\&A target identification** -- search for companies by type, jurisdiction, and status to identify potential acquisition targets
- **Supply chain verification** -- confirm that suppliers and vendors are properly registered and active in their stated jurisdictions
- **Officer network mapping** -- use the officer search to discover connections between individuals and companies across jurisdictions

***

### API & integration

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient('YOUR_APIFY_TOKEN')
run = client.actor('ryanclinton/opencorporates-search').call(run_input={
    'query': 'Alphabet Inc',
    'countryCode': 'us',
    'maxResults': 10,
    'apiKey': 'YOUR_OPENCORPORATES_API_KEY',
})

for item in client.dataset(run['defaultDatasetId']).list_items().items:
    print(f"{item['companyName']} -- {item['jurisdiction']} -- {item['status']}")
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('ryanclinton/opencorporates-search').call({
    query: 'Alphabet Inc',
    countryCode: 'us',
    maxResults: 10,
    apiKey: 'YOUR_OPENCORPORATES_API_KEY',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.log(`${item.companyName} -- ${item.jurisdiction} -- ${item.status}`);
});
```

#### cURL

```bash
curl "https://api.apify.com/v2/acts/ryanclinton~opencorporates-search/runs" \
    -X POST \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
    -d '{
        "query": "Alphabet Inc",
        "countryCode": "us",
        "maxResults": 10,
        "apiKey": "YOUR_OPENCORPORATES_API_KEY"
    }'
```

#### Platform integrations

This actor works with all standard Apify integrations:

- **Webhooks** -- trigger downstream actions when a run completes
- **Schedules** -- automate recurring searches on any cron pattern
- **Google Sheets** -- export results directly to a spreadsheet
- **Zapier / Make / n8n** -- connect to thousands of apps for automated workflows
- **Slack** -- receive notifications when new results are available

***

### How it works

![Intelligence stack: input through resolution, risk, decision, monitoring and portfolio rollup to a decision output](https://apifyforge.com/readme-assets/ryanclinton-opencorporates-search/intelligence-layers.png)

1. **Input validation** -- the actor reads your input parameters and verifies that a search query is provided.
2. **Path selection** -- the actor branches based on `fallbackMode` and the presence of `apiKey`:
   - `apiKey` present (or `fallbackMode: "paid"`) → query the OpenCorporates API directly.
   - `apiKey` absent (or `fallbackMode: "free"`) → run the free multi-source chain.
3. **Paid path** (OpenCorporates API):
   - Build search parameters from `jurisdictionCode`, `countryCode`, `status`.
   - Query `/companies/search` with pagination, 1.5-second delay between pages.
   - On HTTP 429: exponential backoff (10s, 20s, 30s) and up to 3 retries.
   - Optionally query `/officers/search` when `includeOfficers` is set.
   - Transform results into the output schema and push to the dataset.
4. **Free path** (multi-source chain):
   - Resolve enrichment snapshots from the actor's named Apify KV store (lazy-downloaded with SHA256 verification on cold start).
   - Run registry sources in parallel under per-source deadlines: Companies House (GB), INSEE SIRENE (FR), GLEIF (global LEIs).
   - Run enrichment sources locally against bundled SQLite snapshots: OpenSanctions, ICIJ Offshore Leaks, OpenOwnership.
   - Three-pass dedupe + merge: canonical key (jurisdiction + canonicalised number), three-way concordance (normalised name + jurisdiction + incorporation date), offshore carveout for shell-company jurisdictions.
   - Emission gates: enrichment-only entities require two-source concordance; US-targeted queries with no registry hits get an advisory record; unknown-jurisdiction records are capped at 50 per run.
   - Each output record carries a `_meta` block with provenance, normalised entity type, coverage class, and any alternate field values that disagreed across sources.
5. **Output** -- all results pushed to the Apify dataset. A single structured metrics JSON line is logged at the end of the run for observability.

#### Path selection truth table

| `fallbackMode` | `apiKey` provided | Behaviour |
|----------------|-------------------|-----------|
| `auto` (default) | yes | Paid path (OpenCorporates API) |
| `auto` (default) | no  | Free path (multi-source chain) |
| `free`           | any | Free path (forces free chain even if a key is provided) |
| `paid`           | yes | Paid path |
| `paid`           | no  | Hard fail — actor throws an error and exits |

```
Input Query
    |
    v
[Validate Input + Decide Path]
    |
    +--- apiKey present, mode in {auto, paid} ----> [Paid: OpenCorporates API]
    |                                                     |
    |                                                     v
    |                                              [Search + paginate, 429 backoff]
    |
    +--- key absent, mode in {auto, free} --------> [Free Multi-Source Chain]
                                                          |
                                                          v
                                                  [Registry sources, parallel]
                                                    - Companies House (GB)
                                                    - SIRENE (FR)
                                                    - GLEIF (global LEIs)
                                                          +
                                                  [Enrichment sources, local SQLite]
                                                    - OpenSanctions
                                                    - ICIJ Offshore Leaks
                                                    - OpenOwnership
                                                          |
                                                          v
                                                  [Dedupe + merge with offshore carveout]
                                                          |
                                                          v
                                                  [Emission gates]
                                                          |
                                                          v
                                                  [Push to dataset + structured metrics]
```

***

### Performance & cost

| Metric | Value |
|--------|-------|
| Memory allocation | 256 MB |
| Timeout | 3,600 seconds (1 hour) |
| Typical run time (25 results) | 10--20 seconds |
| Typical run time (100 results with officers) | 30--60 seconds |
| Apify PPE charge (25 results) | ~$0.025 (25 × $0.001 per company-fetched event) |
| Apify PPE charge (100 results) | ~$0.10 |
| Apify compute cost (typical run) | $0.0005 -- $0.002 of platform credits per run |
| Apify Free-plan credits | $5 / month, supports hundreds of runs |
| API delay between pages | 1.5 seconds (paid path only) |
| Max retries on rate limit | 3 attempts with exponential backoff |

**Two costs to be aware of:**

1. **Apify platform cost** — what the actor charges per run. Per-event PPE pricing of $0.001 per company-fetched event, plus modest compute cost (~$0.0005 to $0.002 per run). The advisory and summary records are NOT charged.
2. **OpenCorporates API cost** — only when you pass an `apiKey`. OpenCorporates offers a free tier with low rate limits; commercial / data-licence tiers run from roughly $300 / month to $1000+ / month depending on volume, jurisdictions, and rate limits. Check [opencorporates.com](https://opencorporates.com/api_accounts/new) for current pricing. The free path of this actor (the default) does not call the OpenCorporates API at all -- it uses Companies House, INSEE SIRENE, GLEIF, and the bundled OpenSanctions / ICIJ / OpenOwnership snapshots.

***

### Keyless coverage scorecard

What you get without an API key (the free multi-source path). Pass an OpenCorporates `apiKey` for full global coverage across all 140+ jurisdictions.

| Jurisdiction class | Coverage | Notes |
|---|---|---|
| United Kingdom | **Strong** | Companies House full register |
| France | **Strong** | INSEE SIRENE full register |
| Global listed companies | Medium | GLEIF covers regulated entities with an LEI |
| Offshore (BVI/Cayman/Panama/Bahamas/Bermuda/etc.) | Partial | ICIJ Leaks + OpenSanctions overlap only |
| **US private companies / LLCs** | **Weak** | Pass an OpenCorporates API key for full US coverage |
| Most of EU outside FR | Weak | Pass an OpenCorporates API key |
| Asia (CN/JP/KR/IN/etc.) | Weak | Pass an OpenCorporates API key |

***

### Limitations

- **US private-entity coverage in keyless mode is minimal.** GLEIF only covers regulated US entities with an LEI. For comprehensive US company discovery (state-level Secretary of State data, LLCs, private corporations), pass an OpenCorporates API key.
- **Officer detection in keyless mode is GB-only.** Companies House returns officer data for UK companies; other free sources do not include officer records.
- **Rate limits apply.** When using an OpenCorporates API key, the actor handles rate limits automatically with exponential backoff. The free sources have their own modest rate limits which the actor respects via per-source timeouts.

#### Offshore concordance carveout

In free mode, the actor merges records from different sources using a conservative deterministic dedupe. For most jurisdictions, two records merge when they share both:

1. The same canonical jurisdiction + canonicalised company number, OR
2. The same normalised legal name AND jurisdiction AND incorporation date.

In offshore jurisdictions, criterion #2 alone is insufficient because shell-company formation patterns routinely reuse template names and batch incorporation dates. To prevent false merges, the actor requires one additional concordance signal before merging two offshore records:

- Normalised registered-address overlap, OR
- At least one normalised officer name shared between the two records.

Note that raw legal-name equality is **not** sufficient as a standalone signal in offshore jurisdictions — formation agents commonly issue dozens of distinct entities under the identical template name (e.g. "Asset Holdings Ltd"). Locked-in by regression tests in `test/regression-fixtures.test.ts`.

Offshore jurisdictions covered by this carveout: `vg` (British Virgin Islands), `ky` (Cayman Islands), `pa` (Panama), `sc` (Seychelles), `bs` (Bahamas), `mh` (Marshall Islands), `ai` (Anguilla), `bz` (Belize), `bm` (Bermuda).

When two offshore records satisfy #1 (canonical jurisdiction + number) they still merge; the carveout only applies to the three-way concordance path.

- **Maximum 100 results per run.** The `maxResults` parameter caps at 100. For larger datasets, run multiple queries with different filters or jurisdiction codes.
- **Officer search is single-page.** The officer endpoint fetches only the first page of results (up to the `maxResults` limit) without pagination.
- **Data freshness varies by jurisdiction.** OpenCorporates updates its database from official registries on different schedules. Major jurisdictions are typically updated weekly or monthly, but some smaller registries may lag.
- **By-number lookup needs a jurisdiction.** Direct registration-number lookup (`lookupType: "number"`) requires a jurisdiction/country code, and on the free path is GB-only (Companies House); other jurisdictions need an OpenCorporates API key. A bare number with no jurisdiction falls back to name search.
- **Relationship data is within-run only.** The summary `network` block detects officers shared across companies *in the same result set*. Cross-entity ownership chains and beneficial-owner graphs are out of scope here — chain to the sibling actors named in `actorGraph.next[]` (UK Companies House, GLEIF LEI, OpenOwnership) for those.
- **Address formatting depends on registry data.** Not all registries provide complete address information. Some fields may be null or incomplete depending on the jurisdiction.

***

### Responsible use

- **Respect OpenCorporates terms of service.** Ensure your usage complies with the [OpenCorporates API terms](https://opencorporates.com/info/licence). Commercial use may require a paid API plan.
- **Handle personal data carefully.** Officer names and positions are personal data. Process them in accordance with applicable data protection laws such as GDPR, CCPA, or equivalent regulations in your jurisdiction.
- **Do not use for harassment or discrimination.** Company and officer data should be used for legitimate business purposes such as due diligence, compliance, research, and verification -- never for stalking, harassment, or discriminatory practices.
- **Verify critical information at primary sources.** For formal KYC, AML, or legal proceedings, always cross-reference OpenCorporates data against the original government registry to confirm accuracy and currency.
- **Use reasonable request volumes.** Avoid unnecessarily high-frequency runs that could strain the OpenCorporates API. Use filters and appropriate `maxResults` values to retrieve only the data you need.

***

### FAQ

**Do I need an OpenCorporates API key to use this actor?**
No. The actor runs a free multi-source chain by default. With a key you get full OpenCorporates coverage including US private entities and 140+ jurisdictions. Without a key you get strong coverage for the UK and France, partial coverage for offshore jurisdictions, and weak coverage for US private companies. Sign up for a key at [opencorporates.com/api_accounts/new](https://opencorporates.com/api_accounts/new).

**Which free sources are used in keyless mode?**
Companies House for UK companies (5M+), INSEE SIRENE for French companies (30M+), GLEIF for global regulated entities with an LEI (2.7M+), plus enrichment from OpenSanctions, ICIJ Offshore Leaks, and OpenOwnership.

**Is the OpenCorporates API key free?**
OpenCorporates offers a free tier with low rate limits suitable for prototyping or non-commercial use. Commercial / data-licence plans cost roughly $300 / month at the entry tier and scale to $1000+ / month for higher-volume access. Visit [opencorporates.com](https://opencorporates.com/api_accounts/new) for current pricing and rate limits.

**Is the free (keyless) path actually free?**
You still pay Apify's per-event PPE charge ($0.001 per company-fetched event) plus a small amount of compute. There are no external API costs on the free path — the actor uses Companies House (free key, fleet-held), INSEE SIRENE (no key required), GLEIF (no key required), and bundled snapshots for OpenSanctions / ICIJ Leaks / OpenOwnership. The free path is materially cheaper than paying for an OpenCorporates commercial plan; it trades coverage breadth (especially US private entities) for cost.

**What jurisdictions does OpenCorporates cover?**
Over 140 jurisdictions worldwide, including all 50 US states, the United Kingdom, Germany, France, Canada, Australia, the Netherlands, and many more. Use the `jurisdictionCode` or `countryCode` filters to target specific regions.

**What is the difference between `jurisdictionCode` and `countryCode`?**
`countryCode` is a broad two-letter filter (e.g., `us` returns companies from all US states). `jurisdictionCode` is more specific -- for example, `us_ca` returns only California companies and `us_ny` returns only New York companies.

**How do I search for companies in a specific US state?**
Set `jurisdictionCode` to the state code in the format `us_xx` -- for example, `us_ca` for California, `us_ny` for New York, or `us_de` for Delaware.

**What happens if I hit the OpenCorporates rate limit?**
The actor automatically handles HTTP 429 rate-limit responses. It waits with exponential backoff (10 seconds, then 20, then 30) and retries up to 3 times per request before moving on.

**Can I run this actor on a schedule?**
Yes. Use Apify Schedules to run the actor on any cron pattern -- daily, weekly, or custom intervals. This is ideal for ongoing corporate monitoring or compliance checks.

**How do I get officer data in the results?**
Set `includeOfficers` to `true` in the input. The actor will perform an additional search against the OpenCorporates officers endpoint. Officer results appear in the same dataset with a `resultType: "officer"` field.

**Are company and officer results mixed in the same dataset?**
Yes. Company results have the standard company fields, while officer results include a `resultType: "officer"` field. You can filter by the presence of `resultType` to separate them.

**Can I combine this with other Apify actors?**
Absolutely. Use the Apify API or platform integrations to chain this actor with other actors -- for example, run a company search and then pass the results to a sanctions screening actor or a VAT validation actor.

**What output formats are available?**
Results are stored in an Apify dataset and can be exported as JSON, CSV, Excel (XLSX), XML, or RSS. You can also access them programmatically via the Apify API.

**Is this actor suitable for KYC/AML compliance workflows?**
The data comes from official government registries aggregated by OpenCorporates and can be a useful component of due diligence workflows. However, for formal KYC/AML processes, always verify critical information against primary registry sources.

***

### Use in Dify

Drop this actor into [Dify](https://docs.apify.com/platform/integrations/dify) workflows via the Apify plugin's Run Actor node. Every record is typed, deduped, source-attributed, and scored structured JSON: a `recordType` discriminator (`company` / `advisory` / `summary`), an `entityType` enum, a `risk` block (`level`: `high` / `medium` / `low` / `minimal`), a `resolution` confidence block, and an `actorGraph.next[]` array of ranked next-actor pointers your downstream node consumes verbatim. Point a generic registry scraper at the same sources and you get raw per-source JSON to merge yourself; this returns one merged, typed, risk-scored record per entity plus a run-level coverage report.

- **Actor ID:** `ryanclinton/opencorporates-search`
- **Sample input** (keyless UK search, decision-first intelligence payload):

```json
{
    "query": "Monzo",
    "countryCode": "gb",
    "outputProfile": "intelligence"
}
```

- **Branching example** — a Dify if/else node routes on `recordType`, then on the intelligence enums:
  - `recordType == "summary"` → read `coverage` + `coverageReport` + `dataGaps[]` to decide whether coverage was sufficient or a paid `apiKey` re-run is needed.
  - `recordType == "advisory"` → coverage-gap warning; branch to a fallback source (the advisory record names the gap).
  - `recordType == "company"` → branch on `decision.status`: `escalate` → manual review / sanctions screening; `review` → queue for a human; `clear` → auto-proceed. Branch again on `resolution.identityTier` to gate `weak`/`unresolved` matches. Sort the run with `decision.priorityScore` to work the highest-attention entities first.
- **Chain the next step automatically** — each `company` record's `actorGraph.next[]` carries `{ actor, reason }` sibling-actor slugs (e.g. `ryanclinton/eu-vat-validator`, `ryanclinton/gleif-lei-lookup`). A Dify loop reads `actorGraph.next[0].actor` and runs it with no LLM rewriting. The `resolution.entityId` is a stable join key for deduping across runs.

The `summary` record is also mirrored to the run's `SUMMARY` key-value-store key, so a Dify HTTP node can read the coverage block without scanning the dataset.

***

### Related actors

| Actor | Description | Link |
|-------|-------------|------|
| UK Companies House | Search UK Companies House for detailed company data, filings, and officer information | [apify.com/ryanclinton/uk-companies-house](https://apify.com/ryanclinton/uk-companies-house) |
| EU VAT Validator | Validate European Union VAT numbers via the official VIES service | [apify.com/ryanclinton/eu-vat-validator](https://apify.com/ryanclinton/eu-vat-validator) |
| GLEIF LEI Lookup | Look up Legal Entity Identifiers (LEIs) to verify company identity in financial transactions | [apify.com/ryanclinton/gleif-lei-lookup](https://apify.com/ryanclinton/gleif-lei-lookup) |
| OpenSanctions Search | Search global sanctions and politically exposed persons (PEP) lists | [apify.com/ryanclinton/opensanctions-search](https://apify.com/ryanclinton/opensanctions-search) |
| OFAC Sanctions Search | Search the US Treasury OFAC sanctions list for designated individuals and entities | [apify.com/ryanclinton/ofac-sanctions-search](https://apify.com/ryanclinton/ofac-sanctions-search) |
| SEC Insider Trading | Track SEC Form 4 insider trading filings for public companies | [apify.com/ryanclinton/sec-insider-trading](https://apify.com/ryanclinton/sec-insider-trading) |

# Changelog

This Actor's version history is a separate document: https://apify.com/ryanclinton/opencorporates-search/changelog.md

# Actor input Schema

## `query` (type: `string`):

Company name or keyword to search for

## `jurisdictionCode` (type: `string`):

Two-letter country code or jurisdiction code (e.g., 'us_ca' for California, 'gb' for United Kingdom, 'de' for Germany). Leave empty to search all jurisdictions.

## `countryCode` (type: `string`):

Two-letter country code to filter by country (e.g., 'us', 'gb', 'de'). Broader than jurisdiction code.

## `status` (type: `string`):

Filter by company status

## `lookupType` (type: `string`):

How to interpret the query. 'auto' (default) detects a registration-number-shaped query when a jurisdiction is set and looks it up directly; otherwise searches by name. 'number' forces direct by-number lookup (needs a jurisdiction/country code). 'name' always searches by name. Direct by-number lookup works on the paid OpenCorporates path (any jurisdiction) and the free path for GB via Companies House.

## `apiKey` (type: `string`):

Optional. Without a key the actor runs a free multi-source chain (Companies House for GB, INSEE SIRENE for FR, GLEIF for global, plus OpenSanctions / ICIJ Leaks / OpenOwnership for enrichment). With a key you get full OpenCorporates coverage including US private entities. Get a free or paid key at https://opencorporates.com/api_accounts/new

## `fallbackMode` (type: `string`):

Controls source selection. 'auto' uses the free chain when no key is provided. 'free' forces the free chain even if a key is provided (used by internal shadow-comparison runs). 'paid' requires an OpenCorporates API key.

## `outputProfile` (type: `string`):

Payload-shape control per record. 'minimal' = top-level company fields only (smallest payload, ideal for Zapier / Make / n8n if/then rules). 'standard' (default) = top-level fields + compact \_meta block + the intelligence blocks (resolution, risk, dataQuality, healthSignals, freshness). 'full' = everything including alternates + candidateMatches (for analysts and audit). 'llm' = standard + a per-record `summary` plain-English string AI agents can quote without joining fields. 'intelligence' = leads with the intelligence blocks and drops the \_meta diagnostics (flagship mode for risk / KYC / due-diligence consumers).

## `includeOfficers` (type: `boolean`):

Also search for officers/directors matching the query and include officer data in results

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

Maximum number of company results to return (1-100)

## `watchlistName` (type: `string`):

Optional. Set a name to enable cross-run monitoring: the actor stores a per-entity snapshot in a named key-value store and adds `monitoring` + `history` + `riskTrend` blocks to each record reporting what changed since the last run on the same watchlist. Leave empty for a normal stateless run. Use the same name on a schedule to track companies over time.

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

Optional. Provide a list of company names or registration numbers to process as a portfolio (overrides the single Search Query). Each company is searched in turn, its records stream as it finishes, and the summary record carries a portfolio rollup (high-risk / offshore / sanctions / ownership-unknown counts) plus a ranked priority queue. Use for supplier / vendor / counterparty batches. Capped at 50 companies per run.

## Actor input object example

```json
{
  "query": "Google",
  "status": "",
  "lookupType": "auto",
  "fallbackMode": "auto",
  "outputProfile": "standard",
  "includeOfficers": false,
  "maxResults": 25
}
```

# Actor output Schema

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

No description

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

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "query": "Google"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryanclinton/opencorporates-search").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 = { "query": "Google" }

# Run the Actor and wait for it to finish
run = client.actor("ryanclinton/opencorporates-search").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 '{
  "query": "Google"
}' |
apify call ryanclinton/opencorporates-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ryanclinton/opencorporates-search"
        }
    }
}
```

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/x0a1Q4g0MLc7h15Im/builds/ucRD3JUIclJRjbFXO/openapi.json
