Python SDK for Canonical company search — find companies using natural language
Project description
canonical-search
Typed Python SDK for Canonical company search — find and enrich companies using natural language or structured filters. A thin, sync + async client over the public REST API.
Install
pip install canonical-search
Requires Python 3.11+.
Quick Start
from canonical_search import CanonicalClient
client = CanonicalClient(api_key="sk_your_key")
# Natural-language search
results = client.search("AI healthcare startups")
for company in results.results:
print(f"{company.name} — {company.domain}")
# Async twin
results = await client.asearch("B2B fashion tech companies")
Environment-based config
export CANONICAL_API_KEY=sk_your_key
export CANONICAL_API_BASE_URL=https://trycanonical.ai # optional
export CANONICAL_TIMEOUT=30.0 # optional
from canonical_search.config import client_from_env
client = client_from_env()
results = client.search("fintech companies in Europe")
Methods
Every method has an async twin (a-prefixed, e.g. asearch, alookup_companies).
| Method | Purpose | Credits |
|---|---|---|
search(query, top_k=25) |
Natural-language search | 1 per strong result |
search_structured(description=None, *, filters=None, intent=None, top_k=25, include_partials=False) |
Search by typed filters | 1 per strong result |
find_similar_companies(company_domain, top_k=25, intent=None) |
Look-alikes for a seed domain | 1 per strong result |
lookup_companies(names, k=5, disambiguation_mode="auto_when_confident") |
Resolve names → candidate domains | 1 per call when ≥1 candidate |
get_company_details(company_domain) |
Full profile + people + relationships | 1 when found (404 free) |
get_account_status() |
Credit balance, plan, rate limits | free |
top_k is 1–1000. Partial matches (verdict == "partial") are never billed. domain is the public
handle — internal numeric ids are never exposed.
Structured search
from canonical_search import CanonicalClient, StructuredFilters, StructuredLocation
client = CanonicalClient(api_key="sk_your_key")
results = client.search_structured(
description="AI diagnostic platforms for hospitals", # optional semantic core
filters=StructuredFilters(
location=StructuredLocation(countries=["United States"]),
employee_count_min=50,
funding_series=["series_a", "series_b"],
founding_year_min=2018,
),
intent="sales_prospecting",
top_k=25,
)
funding_series: pre_seed, seed, series_a…series_g_plus, growth, late, bridge, venture,
angel, other. intent: sales_prospecting, sales_timing, sales_expansion, competitive_tracking,
emerging_competitor_scan, talent_source, recruiter_employer_vet, jobseeker_stability,
jobseeker_growth. founder_prior_categories: faang, big_tech, unicorn, top_startup, mbb.
Company details, lookup, account status
details = client.get_company_details("stripe.com")
print(details.company.name, details.company.employee_count)
for person in details.people:
print(person.name, "—", person.role)
resp = client.lookup_companies(["stripe", "adyen"])
for name, result in resp.results.items():
if result.auto_resolve_recommended:
print(name, "→", result.primary_candidate_domain)
status = client.get_account_status()
print(status.plan, status.credits.total, "credits left")
Error handling
from canonical_search import (
CanonicalClient,
AuthenticationError,
InsufficientCreditsError,
NotFoundError,
InvalidRequestError,
RateLimitError,
APIError,
)
client = CanonicalClient(api_key="sk_your_key")
try:
results = client.search("fintech")
except InsufficientCreditsError:
print("Out of credits — top up at /billing")
except RateLimitError as e:
print(f"Rate limited — retry after {e.retry_after}s")
All exceptions subclass CanonicalError and carry .status_code and .detail:
AuthenticationError (401), InsufficientCreditsError (402), NotFoundError (404),
InvalidRequestError (400/422), RateLimitError (429, with .retry_after), APIError (5xx).
Response schema
SearchResponse:
results: list[Company]
count: int
query: str
credits_used: int
credits_remaining: int | None
Company:
name: str
website: str
domain: str # public handle
description: str
headquarters: str | None
employee_count: int | None
founding_year: int | None
dimensions: dict | None
funding: FundingSummary | None
verdict: str | None
verdict_reason: str | None
Framework integration
The SDK returns Pydantic models (.model_dump_json() / .model_dump()), so it drops into any
framework that accepts Python functions.
LangChain
from langchain_core.tools import tool
from canonical_search import CanonicalClient
client = CanonicalClient(api_key="sk_your_key")
@tool
def search_companies(query: str, top_k: int = 25) -> str:
"""Search for companies using natural language."""
return client.search(query, top_k).model_dump_json()
AutoGen (classic / AG2)
# pip install "ag2[openai]" — register_function is the v0.2/AG2 API
from autogen import register_function
from canonical_search import CanonicalClient
client = CanonicalClient(api_key="sk_your_key")
def search_companies(query: str, top_k: int = 25) -> str:
"""Search for companies using natural language."""
return client.search(query, top_k).model_dump_json()
register_function(search_companies, caller=assistant, executor=executor,
description="Search for companies using natural language")
CrewAI
from crewai.tools import tool
from canonical_search import CanonicalClient
client = CanonicalClient(api_key="sk_your_key")
@tool("Company Search")
def search_companies(query: str, top_k: int = 25) -> str:
"""Search for companies using natural language."""
return client.search(query, top_k).model_dump_json()
Agno
from agno.tools import tool
from canonical_search import CanonicalClient
client = CanonicalClient(api_key="sk_your_key")
@tool
def search_companies(query: str, top_k: int = 25) -> str:
"""Search for companies using natural language."""
return client.search(query, top_k).model_dump_json()
MCP server
Canonical also offers a hosted, OAuth-authenticated remote MCP server at
https://trycanonical.ai/mcp/ (add it as a connector in Claude, Cursor, VS Code, etc.). It is a
separate hosted service — it is not part of this pip package, and there is no [mcp] extra.
See the MCP docs for connection details.
Get an API key
- Sign up at trycanonical.ai
- Go to Settings → API Keys
- Create a new key (starts with
sk_)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file canonical_search-0.2.0.tar.gz.
File metadata
- Download URL: canonical_search-0.2.0.tar.gz
- Upload date:
- Size: 10.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.13.3 Darwin/23.6.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b976f3fa04425011d6250124c70cfaa415f283fc4879e1b792c7e913a3f020b6
|
|
| MD5 |
c36e53f0c9aef13ef02cbde8c9c7f148
|
|
| BLAKE2b-256 |
78d82471c1f8413a6928efe760321b47cb0e590e4daada96ed79634e5c86e89f
|
File details
Details for the file canonical_search-0.2.0-py3-none-any.whl.
File metadata
- Download URL: canonical_search-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.13.3 Darwin/23.6.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c28fa66ad9cb1d5b786c0365c02ab9ee42827d8ca65591fd0e02b853b7f56df
|
|
| MD5 |
0c5e6864daaa6e75321f21e75d7f9732
|
|
| BLAKE2b-256 |
6076764b12593fb8cd153740e634ff0031ba74d3bd69d8f998a53dfc4ba5451b
|