Skip to main content
Match Users
Ranks other users against an asker’s interests, using activity-derived interest facets — clusters of what each user has actually engaged with over time, not a static profile. The endpoint returns a structured match breakdown (who, how strongly, and on which facets), optionally with sample content that illustrates each overlap. Matching runs in two modes:
  • passive — match against the asker’s own interest facets. Answers “who is like me?” No free-text; the asker’s top facets are the query.
  • directed — match against a free-text query topic. Answers “who is into biotech?” The query is embedded and ranked against candidate facets.
Requires a paid plan, the ai-search bundle, the interest-matching bundle, and interestMatching.enabled set on the project. See the Interest Matching guide for setup.

Authentication

The endpoint requires an authenticated user. A missing token is rejected with a bare 401 before the controller runs; an invalid or expired token is rejected with 403 (refresh and retry). Both modes act on behalf of that user:
  • passive ranks candidates against the asker’s own facets — the authenticated user is the query.
  • directed ranks candidates against a free-text query, still on behalf of the authenticated user.
A master or service key passes the auth layer without binding to a specific user; when acting that way the controller still needs an identified user and returns 401 auth/user-required if none is resolved.

Body Parameters

string
required
"passive" or "directed".
string
The free-text topic to match against. Required in directed mode; rejected in passive mode.
number
default:"20"
Maximum number of matched users to return. Maximum 50.
string
Restrict candidates to users active in this space.
boolean
default:"false"
Only applies with spaceId. When true, candidates active anywhere in the space’s subtree are eligible. Ignored without spaceId.
boolean
default:"false"
Gate 2 of the two-gate sample exposure. When true and the project setting interestMatching.exposeSampleContent is on, each matched facet includes a few illustrative content snippets from the candidate. Requesting samples while the project setting is off returns 403 match/sample-content-disabled.
boolean
default:"true"
Exclude the asker from the results.

Response

Returns the { results: [...] } envelope (a deliberate divergence from search/*, which return bare arrays). Results are ordered by descending score.
Breakdown fields
  • score — the aggregate match score. In passive mode this is additive over the top matched facet-pairs (two moderate overlaps can outrank one very strong overlap); in directed mode it is the single best facet’s similarity · weight(hotness).
  • matchedFacets[].similarity — cosine similarity of the facet pair.
  • matchedFacets[].askerFacet — the asker’s side of the pair. Present in passive mode; omitted in directed mode (there is no asker facet — the query is the anchor) and for the cold-start bio fallback.
  • matchedFacets[].candidateFacet — the candidate’s facet: its id and lazily-decayed hotness.
  • matchedFacets[].sampleContent — present only when both sample gates are satisfied. Never contains moderation-removed, soft-deleted, or private-DM content.
The always-returned breakdown (users, scores, facet ids, similarities, hotness) carries no readable content — raw content appears only behind the two gates.

Cold-start fallback

In passive mode, if the asker has no facet above the significance threshold, the endpoint falls back to the asker’s bio embedding (from UserEmbeddings) as a single pseudo-facet, so a brand-new user can still get matches. Cold-start matches omit askerFacet on the breakdown.

Candidate exclusions

Candidates are excluded when they are: the asker (unless excludeSelf: false), users with an active suspension (a future-dated suspension does not count as active), and — for a space-scoped match — users banned in that space.

Error Responses

The interest-matching bundle is not installed.