Skip to Content
New: meet Clu, and send email, LinkedIn and call steps with Sequences. Watch the videos →
API Reference (v2)Company Search API

Company Search API

CluGTM’s Company Search API finds B2B accounts by industry, headcount and location, and charges 0 credits to run. POST /api/v2/search/companies returns matched companies with domain, industry and employee count, plus a task_id for enrichment. A companion endpoint, POST /search/companies/similar, returns lookalikes for a seed company. Search is free; you spend 1 credit per company only when you enrich one.

🔌

Audience: developers. API keys need a Pro or Enterprise plan (legacy Pro and Scale plans included) or an AppSumo Tier 5, 6 or 7 license, and they never work during a trial. Calls also need the companies:read scope. To search from Claude instead, use the CluGTM MCP.

The three company search endpoints are live on /api/v2 but are not in the served OpenAPI spec (/openapi-public-v2.json). Call them over HTTP as shown here.

How do I call the CluGTM Company Search API?

POST https://api.cleanlist.ai/api/v2/search/companies with a clapi_ Bearer token and the companies:read scope. The body takes filters (or the criteria form), limit (1 to 500, default 25) and an optional cursor.

curl -X POST https://api.cleanlist.ai/api/v2/search/companies \ -H "Authorization: Bearer clapi_your_key" \ -H "Content-Type: application/json" \ -d '{ "filters": { "industries": ["Software Development"], "employee_count_ranges": ["51-200", "201-500"], "locations": ["San Francisco"] }, "limit": 25 }'

Which company filters does the API accept?

These flat keys are the complete list. Each row’s aliases mean the same thing, so you can pipe company_* keys from a people search straight in.

Key (aliases)ExampleNotes
industries (industry, linkedin_industries)["Financial Services"]LinkedIn industry names
employee_count_ranges (employee_count_range, company_headcount, headcount_range, headcount)["51-200", "201-500"]Headcount bands
locations (company_locations, company_hq, hq_location)["San Francisco"]HQ location
hq_country["Canada"]HQ country
funding_stages (funding_stage, last_funding_round_type)["Series B"]Last funding round. Matched verbatim against the stored label; see below
names (company_names, company_name)["Shopify"]Company display name
domains (company_domains, company_website_domain)["shopify.com"]Company web domain; the reliable identifier
year_founded[2019]Founding year
company_type["Privately Held"]LinkedIn company type
⚠️

Any other key is rejected. revenue_ranges, technologies and typos such as industrys return 400 validation_error with “Unknown company filter key” and the list of accepted keys. Nothing is dropped silently. Sending no filters at all also returns 400.

Get suggested values for industries, employee_count_ranges, locations and funding_stages from GET /search/companies/filters?field=<field>&query=<text> (free).

Advanced callers can send the raw company filter shape ({"op": "and", "conditions": [...]}) in filters; it passes through without key checks.

Why does funding_stages return zero results?

Because the flat key matches the stored last-round label exactly, and a friendly label doesn’t always match it. In our August 2026 test, {"industries": ["Software Development"], "employee_count_ranges": ["51-200"], "funding_stages": ["Series B"]} returned total: 0, while the same filters without funding_stages returned thousands. An empty result is HTTP 200 with total: 0, not an error.

If you need funding or revenue filtering, use the criteria form where it’s enabled: fundingRoundTypes translates labels like “Series B” into the stored values, and revenueMin / revenueMax filter on estimated annual revenue. Otherwise, use headcount as a proxy: the 51-200 and 201-500 bands are mostly post-Series-A and pre-enterprise.

{ "filters": { "industries": ["Software Development", "Financial Services"], "employee_count_ranges": ["51-200", "201-500"], "locations": ["San Francisco", "New York", "Toronto"] }, "limit": 200 }

Because search costs 0 credits, you can run several variations and compare total counts before committing to one.

Why is industries: ["Finance"] returning nothing useful?

Industries use the LinkedIn industry taxonomy, which uses specific labels. "Finance" is not a taxonomy value; "Financial Services" is. Likewise "Software" is not a value and "Software Development" is. Use GET /search/companies/filters?field=industries&query=fin to find the right label.

For locations, send a bare city name like ["San Francisco"] rather than the full "San Francisco, California, United States" literal. Records are stored in different forms (“Toronto, ON”, “North York”), and the long literal misses many of them.

The structured criteria form

Instead of filters, you can send criteria: the company filter form from the Find People page (Companies tab), compiled on the server the same way. Send exactly one of filters or criteria. It reaches fields flat filters can’t, such as revenueMin and revenueMax, fundingRoundTypes, growthMin, headcountLatestMin, hqCountriesIso3, investorsInclude and descriptionKeyword. The full list is the CompanySearchCriteria schema in the OpenAPI spec.

{ "criteria": { "industriesInclude": ["Software Development"], "headcountRanges": ["51-200"], "fundingRoundTypes": ["Series B"] }, "limit": 25 }

criteria can also leave companies out: excludeCompanyDomains (domains you name), excludeInCleanlist and excludeInCleanlistListIds (companies already on your lists), and crmFilterSections (accounts in your connected CRM). A crmFilterSections clause needs the crm:read scope, or you get 403 insufficient_scope; a CRM that isn’t connected returns 400 crm_not_connected; and if the CRM set can’t be read completely the search refuses to run (400 invalid_criteria) rather than return the companies you asked to leave out. When exclusions apply, the response adds exclusion_summary. Look up accepted values with GET /search/values?entity=company.

The criteria form isn’t available to AppSumo-only workspaces, which get a 403 instead. Criteria that compile to no filter return 400 empty_criteria.

How do I find companies similar to my best customers?

POST /api/v2/search/companies/similar with a seed company. Send company_domain or company_id (the numeric id from a company search row; anything else returns 400 validation_error), and an optional limit (1 to 100, default 25).

curl -X POST https://api.cleanlist.ai/api/v2/search/companies/similar \ -H "Authorization: Bearer clapi_your_key" \ -H "Content-Type: application/json" \ -d '{"company_domain": "shopify.com", "limit": 25}'
{ "reference_company": "Shopify", "results": [ { "company_id": "...", "name": "Example Commerce", "domain": "example.com", "similarity_score": 0.75 } ] }

Candidates share the seed’s LinkedIn industries and headcount band. They are ranked by similarity_score (0 to 1), a weighted share of the seed’s facets the candidate also has: shared industries count most (up to 3 points), then the same last funding round (1), then headcount band and a shared category (0.5 each). It is a deterministic shared-facet count, not a trained lookalike model, so use it to widen a segment from accounts you know convert. If the seed can’t be resolved, or has no industry or headcount to match on, results is empty.

The route deducts no credits. (POST /credits/estimate with tool: "find_similar_companies" returns 1, but you don’t need a quote to call it.)

What does a Company Search response look like?

{ "task_id": "cl-task_...", "entity_kind": "company", "results": [ { "company_id": "...", "name": "Example Corp", "domain": "example.com", "industry": "Software Development", "employee_count": 180, "revenue_range": null, "hq_location": "San Francisco, California, United States", "funding_stage": null } ], "total": 1432, "cursor": "H4sIA...", "credits_charged": 0, "truncation_warning": null }

total is the full match count regardless of limit, so one free call tells you how big a market is. Search is free on every standard plan; a workspace whose contract sets a per-row search price is charged it for the rows each call asks for, shown in credits_charged (a short balance returns 402 insufficient_credits).

Pass columns (up to 12) to add more fields to each row. Accepted values: Revenue, Funding, Last funding, Founded, LinkedIn, Total funding, Last round amount, Investors, Growth 12m, Followers, Company Phone, Company Email, Time Zone, Open Jobs, Review Rating and Reviews. Rows then carry fields such as founded_year, linkedin_url, employee_count_range, last_funding_date, revenue_min_usd and revenue_max_usd, total_funding_usd, investors, headcount_growth_12m_percent, company_phone and open_job_count. The response can also carry a presentation block of display-ready rows and a search_handoff.url that opens the search in the app.

How do I get the people at those companies?

Company search returns accounts. To get contacts, take the domains and feed them into the People Finder API:

{ "filters": { "company_domains": ["example.com", "acme.com"], "management_levels": ["VP", "Director"], "departments": ["Sales", "Marketing"] }, "limit": 25 }

A plain people search returns 25 rows per call, so page with its cursor. For a larger company set described by a filter, use POST /people/find-at-companies. Both are free; you pay only when you enrich a person for an email or a phone number, at 1 and 10 credits respectively.

What does company enrichment cost?

OperationCredits
Company search0
Similar companies0 (no credits deducted)
Company enrichment1 per company
Person enrichment, verified email1
Person enrichment, direct-dial phone10
Person enrichment, email and phone11

Company enrichment is synchronous. Person enrichment is asynchronous and returns a workflow_id you poll. See Enrichment and Polling & Async.

How do I paginate through company results?

Pass the cursor from the previous response back on the next request, with the same filters. Cursors are opaque; don’t construct them. cursor: null means you have reached the end. There is no offset or page-number pagination.

60 requests per minute per organization (30 for AppSumo licenses without a paid plan) and 30 per minute per API key.

Company search is not subject to the 60-searches-per-UTC-day cap or the hourly paging cap; those apply only to POST /people/find. A company search returns up to limit rows per call. If you are building an account-based workflow, do the company work first and pull people in fewer, larger People Finder calls.

On Pro and Enterprise, searches are unlimited within these rate limits. On AppSumo, each company search and similar-companies call draws from the workspace’s monthly search allowance (200 a month, shared with people search); when it runs out you get 403 search_quota_exhausted.

Can an AI agent call the Company Search API?

Yes, and that is the intended pattern. Because search costs nothing and every paid operation needs a signed quote from POST /credits/estimate, an agent can explore accounts freely and still can’t spend credits without pricing the job first. The quote is HMAC-signed with a 5-minute TTL and checked on the server against the actual cohort.

The CluGTM MCP gives Claude the same search_companies and find_similar_companies tools directly, so Claude connects with your CluGTM sign-in and no API key.

What error does a bad company search return?

Errors from the endpoint use the public envelope, wrapped in an error object:

{ "error": { "code": "validation_error", "problem": "Unknown company filter key: 'revenue_ranges'", "fix": "Use one of the documented public flat-filter keys: [...]. For raw CompanyDB column access, pass the advanced {op, conditions} shape directly.", "retryable": false, "docs_url": "https://docs.cleanlist.ai/errors/validation-error", "request_id": "req_01J..." } }

An empty result set is not an error: a search that matches nothing returns HTTP 200 with total: 0. Check total rather than the status code. Full table in Errors & Rate Limits.

FAQ

Is the CluGTM Company Search API free?

The search call is free and returns credits_charged: 0. API keys need a Pro or Enterprise plan (or legacy Pro or Scale) or an AppSumo Tier 5 to 9 license. Company enrichment costs 1 credit per company and is billed only when data is returned.

Does CluGTM have technographic or intent data?

No. There is no technographic filtering and no intent data. The technologies filter key is rejected with a 400 error.

How large can a company search be?

limit accepts 1 to 500 and defaults to 25. Use cursor pagination for larger cohorts. total reports the full match count either way.

What is the difference between names and domains?

names matches the company’s display name and is ambiguous across companies that share one. domains matches the company’s web domain and is the reliable identifier. Prefer domains whenever you have them.

Where does company data come from?

CluGTM is an orchestration layer over external providers rather than a data vendor with an owned database. Company search and company enrichment are served by a search provider; contact enrichment runs a multi-provider waterfall with verification before results are returned.

Last updated: November 10, 2026. Accepted and rejected filter keys, the similar-companies body and the error shapes on this page were checked against the API code on that date. The funding_stages result was observed in a live test in August 2026.