Corporate Decision Intelligence: KYC, Compliance, Supplier Risk avatar

Corporate Decision Intelligence: KYC, Compliance, Supplier Risk

Pricing

from $1.00 / 1,000 company fetcheds

Go to Apify Store
Corporate Decision Intelligence: KYC, Compliance, Supplier Risk

Corporate Decision Intelligence: KYC, Compliance, Supplier Risk

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.

Pricing

from $1.00 / 1,000 company fetcheds

Rating

0.0

(0)

Developer

Ryan Clinton

Ryan Clinton

Maintained by Community

Actor stats

2

Bookmarked

102

Total users

23

Monthly active users

12 days ago

Last modified

Share

Corporate Decision Intelligence: resolve, score and monitor company risk at scale

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.

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.

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:

{
"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:

{
"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 for the full input shape.

Real-world output

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

{
"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

How this differs

CapabilityRegistry APIsRegistry scrapersThis actor
Company search
Entity resolution (stable ID)
Confidence scoring
Risk signals with evidencePartial
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 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).
  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

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

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

ParameterTypeRequiredDefaultDescription
queryStringYes--Company name, keyword, or registration number to search for (e.g., "Google", "Tesla Motors", "C3259768")
jurisdictionCodeStringNo--Two-letter jurisdiction code (e.g., us_ca for California, gb for UK, de for Germany). Leave empty to search all jurisdictions
countryCodeStringNo--Two-letter country code for broader geographic filtering (e.g., us, gb, de)
statusStringNoAllFilter by company status: Active, Inactive, or Dissolved
lookupTypeStringNoautoauto (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
apiKeyStringNo--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
fallbackModeStringNoautoauto (default) uses the free chain when no key is provided. free forces the free chain. paid requires an OpenCorporates API key
outputProfileStringNostandardPayload 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
includeOfficersBooleanNofalseAlso search for officers/directors matching the query
maxResultsIntegerNo25Maximum number of results to return (1--100)
watchlistNameStringNo--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
companiesArrayNo--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

{
"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.

{
"_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:

{
"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:

{
"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:

{
"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

Company result example

{
"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.

{
"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)

{
"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

FieldTypeDescription
companyNameStringOfficial registered name of the company
companyNumberStringRegistration number assigned by the official registry
jurisdictionCodeStringJurisdiction code in OpenCorporates format (e.g., us_ca, gb)
jurisdictionStringHuman-readable jurisdiction label (e.g., "US - CA", "GB")
incorporationDateString/nullDate the company was incorporated (YYYY-MM-DD)
dissolutionDateString/nullDate the company was dissolved, if applicable
companyTypeString/nullLegal entity type (e.g., "Domestic Stock", "Limited Company")
registryUrlString/nullURL of the official government registry page
statusString/nullCurrent company status (e.g., "Active", "Dissolved")
registeredAddressString/nullFormatted registered address combining street, locality, region, postal code, and country
sourceString/nullName of the official registry publisher (e.g., "California Secretary of State")
opencorporatesUrlString/nullDirect URL to the company's OpenCorporates profile page. Always null in free mode -- the actor never fetches opencorporates.com pages without an API key.
officersArray/nullOfficer 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.
entityTypeStringNormalised 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).
_metaObjectProvenance + 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[].
resultTypeStringPresent only on officer results -- always set to "officer"
recordTypeStringDiscriminator 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.
schemaVersionStringOutput-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.
actorGraphObjectPer-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.
failureTypeStringPresent 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.

FieldTypeDescription
decisionObjectThe 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.
coveragePredictionObjectPredicts 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.
resolutionObjectEntity-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).
riskObjectDeterministic 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.
consensusObjectCross-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.
dataQualityObjectField-completeness: score (0-100), presentFields[], missingFields[] over the core registry fields.
healthSignalsObjectAutomation-friendly booleans: active, officersPresent, registeredAddressPresent, ownershipKnown, sanctionsClear.
freshnessObjectsource (live-registry/snapshot), snapshotDate, daysOld, tier (live/high/medium/low). Snapshot enrichment sources carry a date; live registry lookups report live.
ownershipReadinessObjectBeneficial-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.
nextActionsArrayDeterministic 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.
monitoringObjectPresent 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.
riskTrendObjectPresent 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?".
historyObjectPresent 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.
queryStringPortfolio 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

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

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

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

  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

fallbackModeapiKey providedBehaviour
auto (default)yesPaid path (OpenCorporates API)
auto (default)noFree path (multi-source chain)
freeanyFree path (forces free chain even if a key is provided)
paidyesPaid path
paidnoHard 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

MetricValue
Memory allocation256 MB
Timeout3,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 pages1.5 seconds (paid path only)
Max retries on rate limit3 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 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 classCoverageNotes
United KingdomStrongCompanies House full register
FranceStrongINSEE SIRENE full register
Global listed companiesMediumGLEIF covers regulated entities with an LEI
Offshore (BVI/Cayman/Panama/Bahamas/Bermuda/etc.)PartialICIJ Leaks + OpenSanctions overlap only
US private companies / LLCsWeakPass an OpenCorporates API key for full US coverage
Most of EU outside FRWeakPass an OpenCorporates API key
Asia (CN/JP/KR/IN/etc.)WeakPass 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. 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.

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 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 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):
{
"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.


ActorDescriptionLink
UK Companies HouseSearch UK Companies House for detailed company data, filings, and officer informationapify.com/ryanclinton/uk-companies-house
EU VAT ValidatorValidate European Union VAT numbers via the official VIES serviceapify.com/ryanclinton/eu-vat-validator
GLEIF LEI LookupLook up Legal Entity Identifiers (LEIs) to verify company identity in financial transactionsapify.com/ryanclinton/gleif-lei-lookup
OpenSanctions SearchSearch global sanctions and politically exposed persons (PEP) listsapify.com/ryanclinton/opensanctions-search
OFAC Sanctions SearchSearch the US Treasury OFAC sanctions list for designated individuals and entitiesapify.com/ryanclinton/ofac-sanctions-search
SEC Insider TradingTrack SEC Form 4 insider trading filings for public companiesapify.com/ryanclinton/sec-insider-trading