Matching a List of Companies

You have a spreadsheet of companies — customers, suppliers, prospects, a portfolio — and you want the registered entity behind each row. This guide covers what to send per row, what to do when a row comes back empty, and how to tell "we do not have this company" apart from "the query did not describe it".

Match on the right field

Each row usually carries more than a name. Pick the most specific thing you have, because they do not search the same field:

What you haveParameterNotes
Registration numbernationalIdThe strongest match. Combine with countryCode.
Website or email domainwebsiteMatches with or without www. and with or without a scheme.
A CompanyData ID from an earlier callIDExact, and free of ambiguity.
Only a namesearchCombine with countryCode when you are confident of the country.

A value in the wrong parameter does not fail — it just looks for the wrong thing. A domain in search looks for a company whose name is that domain, which is why search=aselsan.com finds nothing while website=aselsan.com finds ASELSAN. If a search value is unmistakably a domain or a registration number and no company carries it as a name, the API retries it against the right field for you and says so in meta.warnings; sending it in the right parameter to begin with is one request instead of two.

How name matching behaves

search matches from the start of the stored company name. A leading word or two is enough — Heineken finds Heineken N.V. — but everything you do send has to match:

  • Word order matters. QA Wolf does not find Wolf Qa Inc.
  • Inserted words matter. Lurica Argentina does not find LURICA CORP ARGENTINA S.A.
  • Accents matter. Telefonica does not find Telefónica.
  • Legal forms are interchangeable for common cases (BV / B.V., GmbH, Ltd / Limited), but an unusual suffix is treated as part of the name: Younited SA does not find YOUNITED.
  • Names are stored in the Latin alphabet. A search in Greek or Cyrillic will not match.

When the exact search finds nothing, the API retries on its own before answering, in this order, and tells you which step produced the rows:

  1. All the words, in any order — QA Wolf → Wolf Qa Inc.
  2. The name without its legal form — Randstad France SASU → RANDSTAD FRANCE.
  3. (API keys only) The closest spelling — Telefonica Germany → Telefónica Germany.
  4. (API keys only) The same name in another country — Thamesis Consulting + IT → THAMESIS CONSULTING LIMITED in GB.

Each step is only accepted while its result set is small, so a common word cannot pass for a match, and steps 3 and 4 are skipped for names too short to be distinctive. The rows are real, but a relaxed match is a candidate, not a confirmation — check it (see below) before you use it.

What to do per row

For each row, stop at the first step that returns something:

  1. nationalId + countryCode, if you have a registration number.
  2. website, if you have a domain.
  3. search with the name + countryCode. The API's own retries cover word order, legal forms, spelling and — for API keys — other countries.
  4. If it is still empty, search with the first two or three distinctive words, then the same without countryCode. A UK subsidiary is often registered as a branch of its foreign parent: Hoist Finance UK Limited is on the register as Hoist Finance AB (publ) with a UK address.

Anything that arrived with a SEARCH_MATCHED_* warning, or from step 4, widened the search, so check it before you accept it. Location Type and the headquarter fields tell you whether you have the entity itself, its parent, or a branch — see Corporate Structure.

Read meta.warnings

A successful response can carry a meta.warnings array. It never means the request failed; the rows in data.records are always real results. It means something about the request is worth knowing:

{
  "meta": {
    "totalCount": 1,
    "currentPage": 1,
    "totalPages": 1,
    "pageSize": 25,
    "warnings": [
      {
        "code": "SEARCH_LOOKS_LIKE_DOMAIN",
        "parameter": "search",
        "message": "No company is named \"aselsan.com\", so the website field was searched for \"aselsan.com\" instead.",
        "hint": "Use website=aselsan.com to search websites directly."
      }
    ]
  },
  "data": { "records": [ { "Company Name": "ASELSAN ELEKTRONIK SANAYI VE TICARET A S" } ] }
}

Worth acting on when you see them across many rows:

CodeWhat it means
COUNTRY_CODE_NORMALISEDYou sent a country name or a lowercase code; it was read as the ISO code.
COUNTRY_CODE_UNRECOGNISEDThe value is not a country code, so nothing can match it. The filter is kept rather than dropped, so the count stays honest.
NATIONAL_ID_NORMALISEDSeparators were stripped to match the stored form.
SEARCH_LOOKS_LIKE_DOMAINNo company has that name; website was searched instead.
SEARCH_LOOKS_LIKE_REGISTRATION_NUMBERNo company has that name; nationalId was searched instead.
SEARCH_NON_LATIN_SCRIPTNames are stored in the Latin alphabet.
SEARCH_MATCHED_ANY_ORDERExact search found nothing; these rows contain all the words in some order.
SEARCH_MATCHED_CORE_NAMEExact search found nothing; these rows match the name with the legal form left off.
SEARCH_MATCHED_FUZZYExact search found nothing; these are the closest spellings. Verify before use.
SEARCH_MATCHED_OTHER_COUNTRYNothing matched in the country you gave; these rows are registered elsewhere.
PARAMETER_NOT_APPLIEDThe parameter is accepted but does not filter anything on this index.

Check your parameter names once

A parameter name this endpoint does not have is refused with 400, rather than ignored, because a dropped filter returns the whole database as an apparently valid answer:

{
  "error": "Unknown parameter",
  "message": "This endpoint does not have the parameter(s): query.",
  "unknownParameters": ["query"],
  "didYouMean": { "query": "search" },
  "documentation": "https://companydata.com/api-docs/search"
}

Run one request by hand before you start a batch. The name of the company field is search, not query or companyName; employee ranges are employeesTotalMin / employeesTotalMax; the country filter is countryCode and takes ISO 3166-1 alpha-2 codes.

Reading a zero honestly

After the ladder above, an empty result is a real answer: we do not have that company. That happens most often with very small or very new businesses outside Western Europe, and with entities registered abroad under a different name. It is worth separating those rows out rather than retrying them — and if a whole segment of your list comes back empty, tell us which segment, because that is coverage feedback we can act on.

Was this page helpful?