---
title: "Find companies similar to a list of seed companies"
method: POST
path: "/v1/accounts/lookalikes"
tags: ["Accounts"]
---

# Find companies similar to a list of seed companies

`POST /v1/accounts/lookalikes`

## Request

- Base URL: `https://api.trayo.ai`
- URL: `https://api.trayo.ai/v1/accounts/lookalikes`
- Auth: HTTP bearer

**Required permissions:** `accounts:read`.

Send 1–50 companies by companyId, linkedinUrl, website or name, and a limit (default 100, maximum 500). companyId is an exact company dataset ID (number or numeric string), not a workspace account UUID. When supplied, it takes precedence; a missing ID is reported without trying other fields. Otherwise each company resolves by LinkedIn first, then its marketing website including redirects, then its name. Duplicate matched identities contribute once. No saved accounts are required. Optional hard filters minEmployees, maxEmployees, countries (ISO-2 codes or country names), regions and industries drop candidates outside them, including those with an unknown value for a filtered field unless includeUnknown is set; an employee bound replaces the seed size range.

Returns candidates sorted by similarity to the closest seed, with preliminary high/medium/low bands. Matched seeds and candidates include companyId for reuse in later searches. Check seeds for each matched identity and whether it contributed. Unmatched or unindexed seeds are reported and skipped. If none can contribute, companies is empty. A search failure returns 503. The seed companies themselves are excluded; other existing workspace accounts may appear.

Synchronous, read-only and unmetered. Allow more than 120 seconds for the client timeout. Returns up to limit candidates in one response, with no pagination. Import selected results using POST /v1/accounts/batch.

## Request body

- LookalikeSearchBodyDto
  - `companies` object[], required: Seed companies. Use companyId as an exact reference when supplied. Otherwise, try LinkedIn first, then its marketing website (including redirects), then its name. Stop at the first match.
    - `companyId` union: Exact company dataset ID, as a number or numeric string. Reuse companyId from a lookalike result or id from a known company find result. This is not a workspace account UUID. When supplied, it takes precedence; a missing ID is reported as not_found without trying other fields.
      - integer
      - string
    - `linkedinUrl` string: The company's LinkedIn page — the `linkedinUrl` a find result or a person row carries, copied through (`https://www.linkedin.com/company/zapier`); the bare handle (`zapier`) is accepted too. Tried first when present, and the most precise key there is. Showcase pages are not company pages: send the company's own. Copy the handle from a Trayo result or the company's own site rather than guessing it from the name — a slug that belongs to a different company resolves to that company.
    - `website` string: The company's own website, as a URL or a domain (`https://zapier.com`, `zapier.com`). The strongest key after the LinkedIn page: it is matched against our data, then, on a miss, followed through a cross-domain redirect, so a legacy or vanity domain that forwards to the current site still resolves. Sent on its own as the bare site (no path or subdomain), a data or social platform's domain names the platform itself (`zoominfo.com` is ZoomInfo); a page on such a site (`linkedin.com/company/acme`) is not a company website. When our data files the company under a different website, a website sent on its own is also tried as the LinkedIn page it spells (`gong.io` as `gong-io`), accepted only for an established company whose name matches the domain. An alias that does not forward to the company's current site is a miss: send the current website, the LinkedIn page or the name. Does not have to be in your workspace.
    - `name` string: The company name. Tried last and the weakest key, since a common name can match the wrong company — send the website when you have it. A name-only lookup finds only companies Trayo holds under that name; an employer that a Trayo person row names with `companyId: null` has no company record, and its name will usually miss.
  - `limit` integer: Maximum number of candidates to return. Fewer may be available; there is no pagination.
  - `matchSize` boolean: Keep results within the employee range of the seeds. On by default: when the seeds are your accounts or target accounts, size is part of a good match. Set false to find companies that do what the seeds do at any size, for example when the seeds are competitors in one niche.
  - `useWorkspaceAccounts` boolean: Rank results partly by where people at your workspace's accounts used to work: among companies similar to the seeds, the ones your accounts hire from rank higher. On by default. Set false to rank on the seeds alone.
  - `minEmployees` integer: Hard filter: keep only companies with at least this many employees. A company with an unknown employee count is left out unless includeUnknown is set. Either employee bound replaces the seed size range.
  - `maxEmployees` integer: Hard filter: keep only companies with at most this many employees. A company with an unknown employee count is left out unless includeUnknown is set. Either employee bound replaces the seed size range.
  - `countries` string[]: Hard filter: the headquarters country, as ISO-2 codes (`["US", "DE"]`) or country names (`["United States", "Germany"]`), any case. A name is read as its ISO-2 code. A company with an unknown country is left out unless includeUnknown is set. Merged with regions.
  - `regions` string[]: Hard filter: shorthand for a block of countries (north_america, europe, asia_pacific, latin_america, middle_east, africa). Merged with countries.
  - `industries` string[]: Hard filter: exact industry values, the same taxonomy as find (list them with trayo_list_industries or GET /v1/find/industries), case-insensitive. Several values are a union. An unrecognised value is a 400 that names it.
  - `includeUnknown` boolean: Keep companies whose value for a filtered field is unknown instead of leaving them out. About 9.5% of companies have no known headquarters country and 3.5% no industry; employee counts are nearly always known. Kept rows show the unknown field as null.

## Response `200`

- LookalikeSearchResponseDto
  - `seeds` object[], required: One entry per input, in the same order. Check the matched identity, especially for a name-only input.
    - `input` object, required
      - `companyId` union: Exact company dataset ID, as a number or numeric string. Reuse companyId from a lookalike result or id from a known company find result. This is not a workspace account UUID. When supplied, it takes precedence; a missing ID is reported as not_found without trying other fields.
        - integer
        - string
      - `linkedinUrl` string: The company's LinkedIn page — the `linkedinUrl` a find result or a person row carries, copied through (`https://www.linkedin.com/company/zapier`); the bare handle (`zapier`) is accepted too. Tried first when present, and the most precise key there is. Showcase pages are not company pages: send the company's own. Copy the handle from a Trayo result or the company's own site rather than guessing it from the name — a slug that belongs to a different company resolves to that company.
      - `website` string: The company's own website, as a URL or a domain (`https://zapier.com`, `zapier.com`). The strongest key after the LinkedIn page: it is matched against our data, then, on a miss, followed through a cross-domain redirect, so a legacy or vanity domain that forwards to the current site still resolves. Sent on its own as the bare site (no path or subdomain), a data or social platform's domain names the platform itself (`zoominfo.com` is ZoomInfo); a page on such a site (`linkedin.com/company/acme`) is not a company website. When our data files the company under a different website, a website sent on its own is also tried as the LinkedIn page it spells (`gong.io` as `gong-io`), accepted only for an established company whose name matches the domain. An alias that does not forward to the company's current site is a miss: send the current website, the LinkedIn page or the name. Does not have to be in your workspace.
      - `name` string: The company name. Tried last and the weakest key, since a common name can match the wrong company — send the website when you have it. A name-only lookup finds only companies Trayo holds under that name; an employer that a Trayo person row names with `companyId: null` has no company record, and its name will usually miss.
    - `company` object, nullable, required
      - `companyId` integer, required: Company dataset ID. Reuse as companyId in a subsequent search.
      - `name` string, required: The company as Trayo records it.
      - `website` string, nullable, required: The company's website domain as Trayo files it.
      - `linkedinUrl` string, nullable, required: The company's LinkedIn page, when Trayo has it.
      - `resolvedBy` 'account_match' | 'company_id' | 'linkedin' | 'website' | 'redirect' | 'name', required: Which supplied key identified this company. company_id is an exact lookup.
      - `nameMatch` 'exact' | 'approximate', nullable, required: Set only when `resolvedBy` is `name`, null otherwise. `exact`: the company's name equals the name looked up once legal suffixes (Inc, GmbH, Ltd) are dropped. `approximate`: the closest name Trayo holds, which can be a different company ("CR Management Consulting" answered with "m3 management consulting"). Check an `approximate` match against what you know of the company before using it, and leave it out when it does not fit.
    - `status` 'resolved' | 'not_found' | 'not_indexed', required: resolved: contributed to the search. not_found: no company matched the input. not_indexed: the company matched but similarity data is unavailable for it.
  - `companies` object[], required: Candidates ranked best match first: a company close to several seeds ranks above one close to a single seed. Seed companies, their subsidiaries and sister brands, and repeat listings of one company are left out; see filtered. Other companies already in your workspace may appear. Nothing is saved.
    - `companyId` integer, required: Company dataset ID. Reuse as companyId in a subsequent search.
    - `name` string, nullable, required
    - `website` string, nullable, required
    - `linkedinUrl` string, nullable, required
    - `industry` string, nullable, required
    - `sizeRange` string, nullable, required
    - `sizeEmployees` number, nullable, required
    - `country` string, nullable, required
    - `city` string, nullable, required
    - `similarity` 'high' | 'medium' | 'low', required: Heuristic bands: high >= 0.85, medium >= 0.7, low below that. These are preliminary similarity bands, not probabilities.
    - `similarityScore` number, required: Similarity to the closest seed, from 0 to 1. Higher is closer.
    - `closestSeedIndex` integer, required: Zero-based index into seeds for the closest contributing input. Duplicate identities use the first input.
    - `seedsMatched` integer, required: Number of distinct seed companies that retrieved this candidate.
  - `filtered` object, required: What was left out so that only strong matches remain.
    - `seedAffiliates` integer, required: Candidates left out as a subsidiary, sister brand or another listing of a seed company.
    - `duplicates` integer, required: Candidates left out as another listing of a company already in the results.
    - `outsideSeedSize` integer, required: Candidates left out because their employee count is outside seedSizeRange.
    - `outsideFilters` integer, required: Candidates retrieved and then left out by minEmployees, maxEmployees, countries, regions or industries. Most filtering happens inside the search, and companies it never retrieved are not counted, so this is usually 0 and is not the number of companies the filters excluded.
    - `seedSizeRange` object, nullable, required: The employee range results were kept within. Null when matchSize is false or fewer than three seeds have a known employee count.
      - `minEmployees` integer, required
      - `maxEmployees` integer, required
  - `rankedByYourAccounts` object, nullable, required: Null when useWorkspaceAccounts is false, your workspace has no matched accounts, or this ranking is unavailable for the request.
    - `companies` integer, required: How many of your workspace's account companies were used to rank the results.
    - `boosted` integer, required: Results ranked higher because at least two people at those companies used to work there.

## Other responses

- `400`: `validation_failed` (`retry: fix_input`) — The request did not pass input validation: a missing or malformed body field, a bad `limit`, a path parameter that is not a UUID, a `signalKey` that already exists or is reserved. `message` lists every failed constraint; `param` names the first offending field when one can be identified.
- `401`: Missing, malformed, or incorrect bearer token. Every way authentication can fail returns the identical body, so do not try to infer which one it was, and do not repeat the call with the same key. `unauthorized` (`retry: do_not_retry`) — Missing, malformed, or incorrect bearer token. Identical body for every cause.
- `403`: The key grant and its owner's current workspace role must both include every scope required by the operation. `insufficient_scope` (`retry: do_not_retry`) — Scope denial details distinguish missing_key_scope (use a key granting every missing scope), owner_permission_limit (the owner needs the missing workspace permissions), and invalid_key_scope (replace the key with supported scopes). Membership and undeclared-route denials remain generic.
- `429`: Every route is rate limited per workspace across REST, MCP, all keys and OAuth users, `GET /v1/whoami` included, so a balance poll competes with the work it is watching. For `rate_limited`, wait `Retry-After` seconds (also `details.retryAfterSeconds`), then send the same request once; do not retry sooner. `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` describe the workspace's bucket, and they come back on successful responses too: read them and slow down BEFORE you are refused. A burst from one network can also be refused before the key is checked; that 429 carries `Retry-After` and no `RateLimit-*` headers. `rate_limited` (`retry: retry_later`) — The workspace or source network exhausted its request budget for one bucket. `details.retryAfterSeconds` (and `Retry-After` on REST) is the wait: wait that long, then retry the same request once. Do not poll or retry sooner; an early retry is refused again. If you cannot wait, stop and tell the user when to retry; do not fill the wait with other calls. `details.limit` and `details.bucket` name the exhausted budget. When present, RateLimit-* headers describe the active budget and reset.
- `500`: Something failed on our side. Nothing about the request needs changing. `internal_error` (`retry: retry_later`) — Something failed on our side. `message` never describes it — quote `requestId` when reporting. Retry with exponential backoff and GIVE UP after a few attempts: `retry_later` here does not mean the failure is known to be transient, only that nothing about your request needs changing. A request that fails this way repeatedly will not start working.
- `503`: `lookalike_search_not_configured` (`retry: do_not_retry`) — Lookalike search is unavailable. Retrying will not help. Contact support. `lookalike_search_failed` (`retry: retry_later`) — Lookalike search failed or exceeded its time budget. Nothing was saved; retry the same request shortly. `company_resolution_timed_out` (`retry: retry_later`) — Resolving the company by name timed out under load before we could answer. This is NOT a "we do not have it" result: nothing was recorded, and the same request sent again shortly will usually resolve. Companies sent by website or LinkedIn page do not take this path.

---

[API](https://skmtc.dev/trayo/apis/trayo-api.md) · [All operations](https://skmtc.dev/trayo/apis/trayo-api/llms.txt) · [OpenAPI document](https://skmtc.dev/trayo/apis/trayo-api/revisions/0af452dce6de?raw)
