Docs

Lookalike

Nearest accounts, deals, and themes by conversation similarity - centroid cosine over your own corpus, honest about coverage

POST /lookalike answers "more like this one" over your own conversation corpus. lookalike.find takes a seed company or deal and returns the entities most similar to it, ranked by centroid cosine similarity; lookalike.similar_themes takes any free-text description and returns the customer-conversation ML themes closest to it. Both are honest about coverage: when the similarity data is not materialized for your workspace yet, they say so (available: false) instead of guessing.

Every "lookalike audience" tool ranks companies by firmographics. Amdahl ranks by conversation: each company / deal / theme gets a centroid vector built from its utterances in your corpus, and similarity is distance between centroids. The account whose buying committee raises the same concerns, in the same words, as your last three wins is a better expansion bet than the one that merely shares an industry code.

OperationRESTMCP (lookalike tool)Scope
Nearest entities to a seedlookalike.findPOST /lookalikeaction finddata:read
Nearest themes to a descriptionlookalike.similar_themesPOST /lookalike/themesaction themesdata:read

find — nearest entities to a seed

FieldTypeDefaultNotes
entity_typecompany | deal— (required)Which centroid family to search.
entity_idstringThe seed's id, as your pipeline emits it — preferred.
domainstringCompany seeds only: tried as the entity id (see below).
limitint10Max neighbours, cap 50.
bash
curl -X POST "https://app.amdahl.co/api/platform/v1/lookalike" \
  -H "X-API-Key: $AMDAHL_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "entity_type": "company", "entity_id": "1852…", "limit": 10 }'

Over MCP, the lookalike tool's find action:

json
{ "action": "find", "entity_type": "company", "entity_id": "1852…", "limit": 10 }

What comes back — the seed's centroid facts plus its ranked neighbours (the seed itself is excluded):

json
{
  "success": true,
  "available": true,
  "seed": { "entity_type": "company", "entity_id": "1852…", "member_count": 214, "computed_at": "2026-07-19T03:40:11Z" },
  "matches": [
    { "entity_id": "9b03…", "score": 0.91, "member_count": 88 },
    { "entity_id": "77aa…", "score": 0.87, "member_count": 45 }
  ]
}

member_count is how many corpus utterances back each centroid — treat a match built on 6 utterances more skeptically than one built on 200. score is cosine similarity: use it to rank within a response, not as a calibrated probability.

On domain: company seeds also accept a domain, which is tried as the entity id (company centroid ids are the pipeline's company ids). If the domain is not that id for your workspace, you get the honest available: false below rather than a guessed match — when you have a company id (from a routed-search row, for example), prefer it.

Handling available: false — coverage, not failure

Centroids are materialized by a background pipeline sweep on its own cadence. A new workspace, a just-connected data source, or a seed with no corpus presence yet all land here:

json
{ "success": true, "available": false, "reason": "centroids_not_materialized", "matches": [] }

Two reason values, two different reactions:

  • centroids_not_materialized — the similarity data is not there (yet) for this seed or workspace. Not retryable-right-now, not an error. Fall back to the themes action (which degrades gracefully on its own), ask the question as semantic search, or simply re-check after the pipeline's next materialization pass.
  • error — the read itself failed. Transient; retry later.

The HTTP status is 200 either way — branch on available and reason, not on status codes.

themes — nearest themes to a description

The theme-level sibling: describe an idea, an angle, or a complaint in free text and get the ML conversation themes it lands on.

bash
curl -X POST "https://app.amdahl.co/api/platform/v1/lookalike/themes" \
  -H "X-API-Key: $AMDAHL_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "query": "frustration with slow security reviews blocking procurement", "limit": 5 }'
json
{ "action": "themes", "query": "frustration with slow security reviews blocking procurement", "limit": 5 }
json
{
  "success": true,
  "results": [
    { "cluster_id": "c_0412", "label": "Security review as deal blocker", "score": 0.88, "member_count": 96 },
    { "cluster_id": "c_0197", "label": "Procurement timeline friction", "score": 0.81, "member_count": 143 }
  ],
  "freshness": { "source": "pgvector", "synced_at": "2026-07-21T04:12:09Z" }
}

Unlike find, themes never returns available: false — when the fast centroid mirror is off or unsynced it transparently falls back to the warehouse theme index, and freshness.source tells you which one answered (pgvector with a synced_at stamp, or bigquery for the fallback).

A prompt to hand an agent

code
Similarity read over our own corpus — use the lookalike tool.

Seed: {company id or domain of a top closed-won account | deal id}.
Find the {10} most similar {companies | deals}, with scores and member counts.

If it comes back available: false with centroids_not_materialized, don't
improvise a list — tell me, then run the themes action instead with a
description of what made the seed a great account, and give me the nearest
themes with their labels and member counts.

For every match, note the member_count so I know how much conversation
evidence backs the similarity.

Variations

  • Deal-shaped seeds: entity_type: "deal" + the deal id — "which past deals did this one talk like?" for triage and postmortems.
  • Campaign-to-theme mapping: run themes on a draft campaign angle before you write it — if it maps onto a big, well-labeled theme you have grounding; if nothing scores well, your corpus does not talk about it yet.
  • Chain it: seed from your best closed-won, then enrich and interrogate each match — the full play is the expansion motion.

Tips

  • Prefer entity_id over domain. Centroid ids are pipeline company ids; a routed-search row gives you the real id for free, and an unmapped domain resolves to available: false by design.
  • Weight matches by member_count. Similarity over a thin corpus slice is noisy; the score ranks, the member count tells you how much to trust the rank.
  • available: false is a state, not a bug. Centroids materialize on the pipeline's cadence — build the fallback (themes / semantic search / re-check) into any automation instead of treating it as an error path.
  • Lookalike expansion mines your corpus, not the open market. Matches are entities you have already talked to — dormant accounts, stalled deals, early conversations that resemble your winners.

See also

  • Searchsimilar_themes is the theme-level sibling of the semantic lane; the filter lane is where seeds come from.
  • Enrich — what to run on each match once you have the list.
  • Endpoints overview — the whole surface, prerequisites, and the expansion motion.