Skip to main content

CompanyEnrich Python SDK

PyPI

The official Python client for the CompanyEnrich API: company and people enrichment, filter, semantic and lookalike search, work emails, and bulk jobs.

It includes sync and async clients, with types generated from the OpenAPI spec. It requires Python 3.10 or newer.

Install

pip install companyenrich

Quick start

Create an API key in your dashboard and keep it secret.

from companyenrich import CompanyEnrich

# Reads COMPANYENRICH_API_KEY from the environment, or pass CompanyEnrich("your-api-key").
client = CompanyEnrich()

company = client.companies.enrich("stripe.com")
print(company.get("name"), company.get("employees"))

Responses are plain dictionaries with the API's field names, so they pass straight to json.dumps or pandas.DataFrame. Optional fields can be absent or None, so read them with .get(). Editors and type checkers know every field through companyenrich.types.

Method arguments are in snake_case. Dictionaries you pass, such as filter, use the API's own field names.

Companies

# Add paid data to a lookup. Each expansion costs extra credits.
detailed = client.companies.enrich("stripe.com", expand=["technologies", "workforce"])

# Up to 50 domains at once. Check each item's status.
batch = client.companies.enrich_batch(["stripe.com", "adyen.com"])
for item in batch["items"]:
    found = item.get("company")
    if found:
        print(item["domain"], found.get("name"))

# Filter search
page = client.companies.search(
    filter={"country": "US", "employees": ["51-200", "201-500"], "categories": "saas"},
    page_size=25,
)
print(len(page["items"]), page.get("nextCursor"))

# Natural-language search
client.companies.search(semantic={"query": "AI tools for hospitals"})

# Lookalike search
client.companies.search(lookalike={"domains": ["stripe.com", "adyen.com"]})

# Free count of the same query
total = client.companies.count(filter={"country": "US"})
print(total["count"])

People

results = client.people.search(
    filter={"domain": "stripe.com", "seniority": ["c-suite", "founder"]},
    page_size=10,
)

person = client.people.enrich("jane@stripe.com")

lookup = client.people.find_email(person["id"], domain="stripe.com")
if lookup["status"] == "found":
    print(lookup.get("email"), lookup.get("certainty"))

Pagination

search() returns one page. The *_all methods return an iterator that requests pages as you consume them.

for company in client.companies.search_all(filter={"country": "TR"}, page_size=100):
    print(company["domain"])

These are available as companies.search_all, people.search_all, batches.list_all, and geo.search_countries_all, geo.search_states_all and geo.search_cities_all.

Search credits are charged for every result on a fetched page, even if you stop iterating partway through it. Set page_size close to the number of results you plan to use.

Bulk jobs

Bulk enrichment and search exports run in the background.

job = client.companies.bulk_enrichment.create(["stripe.com", "adyen.com"])

client.batches.wait_for_completion(
    job["id"],
    on_progress=lambda batch: print(batch["progress"]["succeeded"], batch["progress"]["total"]),
)

for record in client.companies.bulk_enrichment.stream(job["id"]):
    enriched = record.get("company")
    if enriched:
        print(record["domain"], enriched.get("name"))

companies.bulk_enrichment, companies.search_export and people.search_export share the same methods:

Method Returns
create(...) The new batch's status
stream(id) An iterator of records, best for large jobs
results(id) One JSON document with every record
csv(id) The CSV as text
iter_csv(id) The CSV as raw bytes, for writing to a file

Async

AsyncCompanyEnrich has the same methods. Await calls that return a result, and use async for with the iterators.

import asyncio

from companyenrich import AsyncCompanyEnrich


async def main() -> None:
    async with AsyncCompanyEnrich() as client:
        company = await client.companies.enrich("stripe.com")
        print(company.get("name"))

        async for person in client.people.search_all(filter={"domain": "stripe.com"}, page_size=25):
            print(person.get("name"))


asyncio.run(main())

Both clients can be used as context managers, or closed with close(), to release network connections.

Errors

Failed requests raise a subclass of APIError, which carries status, title, detail, errors (field-level validation messages) and trace_id (include it when contacting support).

from companyenrich import APIError, NotFoundError, PaymentRequiredError

try:
    client.companies.enrich("example.invalid")
except NotFoundError:
    print("No company found")
except PaymentRequiredError:
    print("Out of credits, or not included in this plan")
except APIError as error:
    print(error.status, error.detail, error.trace_id)
Status Class
400 BadRequestError
401 AuthenticationError
402 PaymentRequiredError
403 PermissionDeniedError
404 NotFoundError
422 ValidationError
429 RateLimitError
5xx ServerError
Other APIError

APIConnectionError and APITimeoutError cover requests that never received a response. Everything above extends CompanyEnrichError.

Retries and timeouts

Failed requests are retried up to twice with exponential backoff.

Failure GET and free POST endpoints Other POST endpoints
429 rate limit Retried Retried
408, 5xx, connection error, timeout Retried Not retried

POST requests that consume credits or start a job are not repeated after an ambiguous failure, because the first attempt may already have been charged or created a batch.

Configuration

configured = CompanyEnrich("your-api-key", timeout=30.0, max_retries=4)

# Every method accepts per-request options.
configured.me(options={"timeout": 5.0, "max_retries": 0})
Option Default Description
api_key COMPANYENRICH_API_KEY Your API key
base_url https://api.companyenrich.com API origin, for proxies
timeout 120.0 Timeout in seconds. None disables it
max_retries 2 Retries after the first attempt
default_headers none Headers added to every request
http_client new client A custom httpx.Client or httpx.AsyncClient

API reference

SDK method Endpoint
companies.get(id) GET /v2/companies/{companyId}
companies.enrich(domain) GET /v2/companies/enrich
companies.enrich_by_properties(...) POST /v2/companies/enrich
companies.enrich_batch(domains) POST /v2/companies/enrich/batch
companies.autocomplete(query) GET /v2/companies/autocomplete
companies.workforce(...) GET /v2/companies/workforce
companies.search(...) POST /v2/companies/search
companies.count(...) POST /v2/companies/search/count
companies.preview(...) POST /v2/companies/search/preview
companies.bulk_enrichment.* /v2/companies/enrich/bulk
companies.search_export.* /v2/companies/search/export
people.get(id) GET /v2/people/{personId}
people.enrich(email) POST /v2/people/enrich
people.find_email(id) GET /v2/people/{personId}/email
people.search(...) POST /v2/people/search
people.count(...) POST /v2/people/search/count
people.preview(...) POST /v2/people/search/preview
people.search_export.* /v2/people/search/export
batches.list(...) GET /v2/batches
batches.get(id) GET /v2/batches/{id}
batches.cancel(id) POST /v2/batches/{id}/cancel
batches.raw_results(id) GET /v2/batches/{id}/results
batches.wait_for_completion(id) Polls GET /v2/batches/{id}
geo.regions() GET /v2/geo/regions
geo.country(code) GET /v2/geo/countries/{countryCode}
geo.search_countries(...) POST /v2/geo/countries
geo.search_states(...) POST /v2/geo/states
geo.search_cities(...) POST /v2/geo/cities
industries.list() GET /v2/industries
keywords.autocomplete(query) GET /v2/keywords/autocomplete
technologies.autocomplete(query) GET /v2/technologies/autocomplete
positions.autocomplete(query) GET /v2/positions/autocomplete
me() GET /v2/me

See the API documentation for parameters and credit costs.

Development

uv sync
uv run pytest
uv run python scripts/unasync.py                 # Regenerates the sync client after editing _async
uv run python scripts/generate_types.py --fetch  # Downloads the latest spec and regenerates types

To release, bump version in pyproject.toml and push to main. The publish workflow runs the checks and publishes that version to PyPI if it is new.

License

MIT

Metadata

Release files for companyenrich 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for companyenrich 1.0.0
File Size Uploaded Provenance Actions
companyenrich-1.0.0.tar.gz 32.4 kB Without provenance Details for companyenrich-1.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for companyenrich 1.0.0
File Interpreter ABI Platform Actions
companyenrich-1.0.0-py3-none-any.whl Python 3 none any Details for companyenrich-1.0.0-py3-none-any.whl

Total release size: 76.3 kB

Release files / companyenrich-1.0.0.tar.gz

Download URL companyenrich-1.0.0.tar.gz
Size 32.4 kB
Tags Source
SHA-256 checksum
How to use checksums
43286f48efa7866daa345a109ef9a1a3b946538d81f576b39c5deb15dade3529
BLAKE2b-256 checksum
How to use checksums
c8dea0cd0b79cfa3fcafafb3441c37ef1326e197712cf4d425451c5827dfddb5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / companyenrich-1.0.0-py3-none-any.whl

Download URL companyenrich-1.0.0-py3-none-any.whl
Size 43.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
509a4d815615d9731ee956edff611344187e1e5be814004112d72cae99e0ee67
BLAKE2b-256 checksum
How to use checksums
784f639143e50ff87cd00b37f6e39d9deb1ee39e55e83ee648bdb95ddefb26e5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for companyenrich 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page