Official Python SDK and CLI for the DiscoLike API
The search engine for the business web — find your ideal target accounts from Python or your terminal.
Website · API Docs · Get an API key · Sign up · Book a demo · Blog
DiscoLike indexes 80M+ business websites worldwide, analyzed in 50 languages — roughly 3x the coverage of LinkedIn-dependent databases. This repo gives you that index from Python or your terminal, as two packages: discover lookalike companies, size segments, enrich domain lists, match messy company names to domains, and find the right contacts.
If you're a coding agent: the fastest integration is the hosted MCP server —
https://api.discolike.com/v1/mcp(streamable-http, OAuth; 48 tools). For scripting and pipelines usepip install discolikeas a library; for the terminal usepip install discolike-clioruvx --from discolike-cli discolike, auth viaDISCOLIKE_API_KEY. Machine-readable API index:https://docs.discolike.com/llms.txt.
This repo ships two packages: discolike (the SDK) and discolike-cli (the discolike command, depends on the SDK).
pip install discolike # SDK only, for use as a library
pip install discolike-cli # CLI — installs discolike as a dependency
pip install "discolike[cli]" # same thing, extras spellingOr with uv:
uv add discolike # as a library
uv tool install discolike-cli # CLI onlyOr run the CLI without installing:
uvx --from discolike-cli discolike --helpRequires Python 3.10+.
Create an API key at app.discolike.com/account/management/keys, then use any of:
export DISCOLIKE_API_KEY="dl_..." # environment variable
discolike auth login # or store it via the CLIclient = Discolike(api_key="dl_...") # or pass it explicitlyfrom discolike import Discolike
client = Discolike()
companies = client.discover(
icp_text="Cybersecurity for SMBs, managed IT services, endpoint protection",
country=["US"],
max_records=25,
)
for company in companies:
print(company.domain, company.name, company.similarity)Run DiscoGen research over a set of domains and wait for the result:
job = client.discogen.process(
query="Recent funding rounds and headcount growth",
domains=["stripe.com", "adyen.com"],
web_search=True,
)
result = job.wait()
print(result.results)Size a segment before pulling it:
total = client.count(phrase_match=["book a demo"], country=["US"])
print(total.count)Pull a full company profile:
profile = client.companies.data(domain="stripe.com")The client is a context manager if you want deterministic cleanup:
with Discolike() as client:
...Every resource has an async twin on AsyncDiscolike:
import asyncio
from discolike import AsyncDiscolike
async def main() -> None:
async with AsyncDiscolike() as client:
companies = await client.discover(icp_text="B2B SaaS for logistics", max_records=10)
print([c.domain for c in companies])
asyncio.run(main())The examples/ folder has runnable scripts for common workflows — matching a CRM contact export to DiscoLike persona IDs (with checkpointing and resume), bulk-finding work emails from a CSV, and discovering companies by ICP then enriching them with DiscoGen. Each is stdlib-plus-SDK only:
export DISCOLIKE_API_KEY="dl_..."
python examples/match_crm_contacts.py --helpThe same API from your terminal, with --help on every command:
discolike auth login
discolike discover --icp-prompt "managed IT services for SMBs" --country US --max-records 25
discolike match "Stripe Inc" --city "San Francisco"
discolike match --file companies.csv --name-column company_name --wait
discolike count --phrase-match "book a demo" --country US
discolike company data stripe.com
discolike extract https://stripe.com/enterpriseTop-level commands: discover, count, match, extract, validate-icp, append, segment — plus auth, company, contacts, discogen, queries, account, search-providers, and llm-providers command groups.
- Results print as JSON to stdout; errors print as JSON (
error,message,status_code) to stderr. - Pass
--format tablefor a human-readable table — used automatically when stdout is a TTY. - Async endpoints (
match --file,discogen run,discogen run-personas,segment,validate-icp) take--waitto block until the job finishes. Without it, you get atask_idback to poll withdiscolike discogen status <task_id> --family <family>.appendis synchronous — it returns enriched rows directly (or writes CSV bytes to--output).
| Exit code | Meaning |
|---|---|
| 0 | Success |
| 1 | Server error or unexpected failure |
| 2 | Validation error |
| 3 | Authentication or plan-access error |
| 4 | Rate limited |
| 5 | Network error |
| 6 | Not found |
| Surface | What it does |
|---|---|
client.discover() / client.count() |
Find lookalike companies by ICP text, phrases, tech stack, geo, and 40+ other filters |
client.companies |
Company profiles: firmographics, scores, growth, redirects, vendors, subsidiaries |
client.contacts |
Search, look up, match, and discover contacts at target companies |
client.match |
Match company names (plus phone/city/state) to domains — single or bulk CSV |
client.append() |
Enrich a CSV of domains with DiscoLike datasets |
client.segment() |
Auto-segment a list of domains |
client.validate_icp() |
Validate a domain list against an ICP definition |
client.queries |
Saved inclusion/exclusion lists for reusable targeting |
client.search_providers / client.llm_providers |
Manage BYOK search and LLM provider integrations for DiscoGen |
client.account |
Usage and quota |
All responses are typed Pydantic models.
Bulk operations (match.bulk, segment, validate_icp, contacts.bulk_match) return a Job handle instead of blocking:
job = client.segment(domains=["stripe.com", "adyen.com", "checkout.com"])
result = job.wait()Job.status() polls without blocking, Job.cancel() aborts, and wait() raises JobFailedError / JobTimeoutError on failure.
JobTimeoutError is a client-side wait limit only — the task keeps running server-side (large DiscoGen runs can take hours), so call wait() again to resume or fetch status() later. Cancelled tasks still return results for every item that finished before cancellation. Send one job per list (up to 10,000 domains) rather than splitting into parallel jobs — concurrent DiscoGen jobs share your LLM provider key and slow each other down.
All errors inherit from DiscolikeError:
from discolike import Discolike, RateLimitError, ValidationError
try:
companies = Discolike().discover(icp_text="fintech infrastructure")
except RateLimitError as err:
...
except ValidationError as err:
...AuthenticationError, PlanAccessError, NotFoundError, ServerError, and APIConnectionError cover the rest. Transient failures are retried automatically (3 attempts by default).
| Option | Default | |
|---|---|---|
api_key |
DISCOLIKE_API_KEY env var, then CLI config file |
|
base_url |
https://api.discolike.com/v1 |
|
timeout |
60.0 seconds |
|
max_retries |
3 |
|
http_client |
— | Bring your own httpx2.Client / httpx2.AsyncClient |
A provided http_client is mutated in place (the auth header is stamped on it, and base_url is set if it's unset) — use a client dedicated to DiscoLike, not one shared across other services.
This is a uv workspace with two members: packages/discolike (the SDK) and packages/discolike-cli (the CLI).
uv sync --all-packages
uv run pytest packages/discolike/tests
uv run pytest packages/discolike-cli/tests
uv run ruff check .- API documentation: docs.discolike.com
- Sign up: auth.discolike.com/en/signup
- Book a demo: calendly.com/discolike/introductory-call
- LinkedIn: linkedin.com/company/discolike
- Issues with this SDK: GitHub issues