OpenCorporates

Document information
FieldValue
Canonical URL/docs/11_partner_services/40_opencorporates
Version (published date)2026-08-14
Tagspartners, opencorporates, kyc, legal-entities, reference-data, restapi-generic

Summary

OpenCorporates is a read-only REST API over a multi-jurisdiction legal-entity database: company names and numbers, statuses, registered addresses, officers, filings, and related statements. Default responses are JSON (XML is optional). Tealfabric has exercised the v0.4 GET interface against restapi-generic-1.1.0 (operation: receive, method: GET).

An API token is required on every call. Open-data / public-benefit projects can use the data under share-alike attribution; commercial products need a paid API account. Tealfabric does not issue tokens or resell the dataset.

For Finnish Trade Register facts only, prefer PRH BIS (free, no token). Use OpenCorporates when you need many countries, officers, or a single search surface across jurisdictions.

Why use it with Tealfabric

Tealfabric stores your customers and entities. It does not maintain the world’s company registers. Use OpenCorporates when a workflow must resolve a legal name to a register identifier outside (or in addition to) Finland:

  • Match an onboarding name to jurisdiction_code + company_number
  • Enrich an entity with status, incorporation date, and registered address
  • Look up officers for KYC
  • Feed a resolved legal entity into OpenSanctions /match

Typical pattern: keep the entity in Tealfabric; receive OpenCorporates from a process step; persist jurisdiction_code, company_number, opencorporates_url, and current_status in DataPool or entity-information. Attribute OpenCorporates (and the underlying register) as their licence requires.

What the API provides

Use HTTPS and pin the version in the path (vendor default can change):

https://api.opencorporates.com/v0.4

Calls without a token return an error (often HTTP 503). Send the token as header X-API-TOKEN or query api_token. Prefer the header so the token is not copied into URL logs.

Useful GET routes:

NeedHow
Search by nameGET /v0.4/companies/search?q=… (loose word match; order=score for relevance; q=Name* for prefix)
Restrict jurisdictionjurisdiction_code=gb or fi; US states are us_de, us_mi, …
One companyGET /v0.4/companies/{jurisdiction_code}/{company_number} (sparse=true skips filings and extra data)
OfficersGET /v0.4/officers/search?q=… and GET /v0.4/officers/{id}
Jurisdiction list / matchGET /v0.4/jurisdictions and GET /v0.4/jurisdictions/match?q=Finland
QuotaGET /v0.4/account_status

Search and list calls are paginated: default 30 rows, per_page up to 100, page up to 100. Date filters use YYYY-MM-DD or ranges 2013-12-03:2014-05-22. Term filters can AND with commas or OR with pipes.

JSON envelope:

{ "api_version": "0.4", "results": { } }

Search puts companies under results.companies[], each item wrapping { "company": { … } }. A single-company call puts the record at results.company. restapi-generic-1.1.0 receive wraps that JSON as a one-element data array — unwrap in step code.

Each object includes opencorporates_url. Prefixing that URL with api. is the corresponding API URL. Provenance (source / provenance) says which register the row came from and when it was retrieved.

Statements (control, gazette, trademarks, registrations) are replacing the older data / datum model. Prefer statement endpoints for new work.

Reference: API Reference v0.4.8, authentication.

Platform compatibility

We have run OpenCorporates v0.4 GET through Tealfabric’s generic REST connector.

Integration settingValue
Connectorrestapi-generic-1.1.0
urlhttps://api.opencorporates.com
path/v0.4
methodGET
auth_header_nameX-API-TOKEN
api_keyyour OpenCorporates token (no Bearer / ApiKey prefix)
acceptapplication/json
Process step operationreceive

Keep this integration GET / receive only. Do not set method to POST. Paging and filters belong in query. Do not request format=xml unless you change accept and parse XML yourself.

Alternative to the header: set api_key_query_param to api_token and leave auth_header_name empty. Do not send the token from the browser.

Leave executable_by_ai_agents off until you accept quota spend. Put https://api.opencorporates.com/documentation/API-Reference in the integration description.

Connector details: Generic REST API connector.

Connect from a process step

Replace YOUR_INTEGRATION_ID. The examples search in one jurisdiction, then fetch the first hit sparsely.

const integrationId = "YOUR_INTEGRATION_ID";
const q = String(process_input.q ?? "").trim();
const jurisdiction = String(process_input.jurisdiction_code ?? "fi").trim();

if (!q) {
  throw new Error("q is required");
}

function failMessage(result: Record<string, unknown>, fallback: string): string {
  const err = result.error;
  if (typeof err === "string") return err;
  if (err && typeof err === "object") {
    return String((err as Record<string, unknown>).message ?? fallback);
  }
  return fallback;
}

function unwrapResults(result: Record<string, unknown>): Record<string, unknown> {
  const envelope = (result.data ?? {}) as Record<string, unknown>;
  let root: unknown = envelope.data ?? envelope;
  if (Array.isArray(root) && root.length === 1) {
    root = root[0];
  }
  const obj =
    root && typeof root === "object" && !Array.isArray(root)
      ? (root as Record<string, unknown>)
      : {};
  const results = obj.results;
  return results && typeof results === "object" && !Array.isArray(results)
    ? (results as Record<string, unknown>)
    : obj;
}

const search = (await integration.executeSync(integrationId, {
  operation: "receive",
  path: "companies/search",
  query: {
    q,
    jurisdiction_code: jurisdiction,
    inactive: "false",
    order: "score",
    per_page: "10",
    page: "1",
  },
})) as Record<string, unknown>;

if (!search?.success) {
  throw new Error(failMessage(search, "OpenCorporates search failed"));
}

const searchResults = unwrapResults(search);
const wrapped = Array.isArray(searchResults.companies) ? searchResults.companies : [];
const companies = wrapped.map((row) => {
  const rec = row && typeof row === "object" ? (row as Record<string, unknown>) : {};
  return rec.company ?? rec;
});

const first = companies[0] as Record<string, unknown> | undefined;
let detail: unknown = null;
if (first?.jurisdiction_code && first?.company_number) {
  const get = (await integration.executeSync(integrationId, {
    operation: "receive",
    path: `companies/${String(first.jurisdiction_code)}/${String(first.company_number)}`,
    query: { sparse: "true" },
  })) as Record<string, unknown>;
  if (get?.success) {
    detail = unwrapResults(get).company ?? unwrapResults(get);
  }
}

return {
  success: true,
  data: {
    companies,
    company_count: companies.length,
    detail,
  },
};

Direct lookup when you already have the register pair:

const result = await integration.executeSync(integrationId, {
  operation: "receive",
  path: "companies/gb/00102498",
  query: { sparse: "true" },
});

Check remaining quota before a batch:

await integration.executeSync(integrationId, {
  operation: "receive",
  path: "account_status",
});

Daily counters reset at midnight UTC; monthly at midnight UTC on the last day of the month.

Example use cases with Tealfabric

Resolve a legal name at onboarding. A WebApp collects company name and country. Map country to jurisdiction_code (jurisdictions/match or your own ISO table). Search with inactive=false and order=score, then store company_number and opencorporates_url on the entity.

Finland vs everyone else. If country_id is FI, call PRH BIS with the Y-tunnus. Otherwise call OpenCorporates. Same process, two integrations.

Enrich after PRH. You already have a Finnish Business ID. Search OpenCorporates with jurisdiction_code=fi and fields=company_number (or name) to attach opencorporates_url and cross-jurisdiction identifiers.

Officers for KYC. officers/search by person name and jurisdiction, then write officer records into DataPool. Do not treat a name search as identity proof.

Sanctions after resolution. Once you have a legal name and company number, send OpenSanctions /match with schema: "Company".

Investigator WebApp. Bind a search box to companies/search. Show name, company_number, jurisdiction_code, current_status. Link opencorporates_url for attribution. Cache results; each search costs quota.

Quota watchdog. A scheduled step calls account_status and notifies when calls_remaining.today is low.

Pricing and accounts

Get a token from OpenCorporates (API accounts, pricing).

UseCost model
Open-data / public-benefit project (share-alike attribution to OpenCorporates)Free or at-scale access; still needs a token. See their licence page.
Commercial product (no share-alike on OpenCorporates’ database rights)Paid self-serve API plan, billed annually with daily and monthly call caps
High volume / selected jurisdictions / SFTP dumpsEnterprise bulk delivery — talk to OpenCorporates

Self-serve commercial tiers on the pricing page (orientation only; confirm there) currently scale from hundreds of calls per month (Essentials) to a few thousand (Starter / Basic), with Enterprise above that. The API reference also describes a small default cap (tens of calls per day / hundreds per month) when you are not on a paid plan.

Quota and invoices stay with OpenCorporates. In Tealfabric you only store the token on the integration (or inject it from ProcessFlow Keystore).

Limits to keep in mind

  • GET / receive only. Version v0.4 in the path.
  • Token required. Header X-API-TOKEN or query api_token.
  • page max 100, per_page max 100. Do not crawl the world through search.
  • HTTP 403 when you exceed the plan; 404 when the company is missing; 503 for some redactions and for missing tokens.
  • Name search is loose. Confirm company_number with a human or a second identifier before treating it as the same legal entity.
  • Do not send the token to the browser.
  • Attribute OpenCorporates (and the source register) per their licence.

See also