---
title: "Search"
method: POST
path: "/api/facade/search"
tags: ["facade"]
---

# Search

`POST /api/facade/search`

## Request

- Base URL: `https://api.vruum.ai`
- URL: `https://api.vruum.ai/api/facade/search`
- Auth: `HTTPBearer` (a scheme the document does not define)

Polymorphic read-only search across your Vruum workspace.

One tool for every list/queue/search read. Pass `type` to pick the entity:
people (your pipeline — keyword `query`, batch dedup array, or list-mode
`filters`), companies (company-domain contact search for decision-makers —
requires filters.domain), directory_people (the shared people directory —
requires filters.query), and directory_companies (the shared company directory —
filters.query?, filters.industry?, or both; industry is the canonical enum,
including Unspecified for missing source data). Directory results contain
contact/company/freshness fields only, never another tenant's CRM state.
Other types are deals, objectives, messages (outreach queue), engagements
(LinkedIn engagement queue), content (LinkedIn content calendar), claims
(the hypothesis ledger: falsifiable beliefs with evidence-backed
confidence — filter by status or scope; render one with fetch
type='claim'), kb
(knowledge-base search), skills (published skills), cta_links, warm_paths
(open targets that have a warm intro path — see find_warm_path for one
target), relationship_attempts (the durable action timeline shared with
the Relationships workspace).

All types except `companies` read internal, tenant-scoped data only.
Pagination (`limit`/`offset`) is supported for people (list mode), deals,
messages, engagements, warm_paths, and relationship_attempts; other types reject it. Results are returned
under `{type, results}` with each entity type's native payload shape.

Objective routing: use `type='objectives'` here to list objectives
(newest-moved first; filters.status). To read one
objective by UUID with its live pins and members count, use `fetch` with
`type='objective'`. To create, update, clone, retire, pause, launch, or
manage objective members, use `manage_outreach`. A paused objective must
pass forecast review and launch approval before it becomes active again.

## Request body

- FacadeSearchRequest: Request body for the polymorphic ``search`` facade tool.
  - `type` 'people' | 'companies' | 'deals' | 'objectives' | 'messages' | 'engagements' | 'content' | 'kb' | 'skills' | 'cta_links' | 'warm_paths' | 'relationship_attempts' | 'directory_people' | 'directory_companies' | 'claims', required: The relationship-aware entity types the ``search`` facade can read.
  - `query` union: Only for type='people'. A keyword string searches the existing pipeline (name/title/company); an array of {name?, company?, linkedin_url?} objects runs a batch dedup lookup (one match record per candidate, in original order; `limit` is ignored). Mutually exclusive with `filters`. For type='kb' or type='deals', use filters.query instead.
    - string
    - FacadeBatchPersonQuery[]
      - `name` string, nullable: Person full name to look up in the existing pipeline.
      - `company` string, nullable: Company name to look up alongside the person name.
      - `linkedin_url` string, nullable: LinkedIn profile URL — strongest dedup signal; exact-matched first when present.
  - `filters` union: Type-specific filters — the object shape is determined by `type` (e.g. {domain} for companies, {stage, outcome, query} for deals, or {query?, industry?} for directory_companies). Unknown keys are rejected with 422.
    - FacadePeopleFilters: List-mode filters for ``type='people'`` (routes to ``get_user_people``). Mutually exclusive with ``query`` — pass one or the other, never both.
      - `stage` string, nullable: Pipeline stage: new, warming, enrolled, contacted, replied, met, opportunity, closed_won, closed_lost.
      - `status` string, nullable: Legacy filter — 'meeting_booked' (stage=met) or 'all' (default).
      - `search` string, nullable: Free-text search across email, first/last name, title, company name.
      - `sort_by` string, nullable: Sort by recent, score, name, or company (default: score — same as the underlying endpoint).
      - `enrollment` string, nullable: Outreach enrollment filter: all, enrolled, paused, not_enrolled.
      - `relationship_type` string, nullable: Relationship filter: outbound_prospect, inbound_buyer, inbound_seller, networking, or all.
      - `objective` string, nullable: Objective UUID, exact name, 'unassigned' for people with no live objective membership, or a comma-separated UUID list to combine several objectives.
      - `score_min` integer, nullable: Minimum match score (0-100, inclusive).
      - `score_max` integer, nullable: Maximum match score (0-100, inclusive).
      - `research_status` string, nullable: 'researched', 'shallow', 'deep', 'stub', or 'all'. When omitted, matches the underlying endpoint's default: 'researched' for browsing, but 'all' when `search` is set (a search must find stubs too).
      - `custom` object, nullable: Custom-attribute filters from CSV-import custom columns; every key=value pair must match (e.g. {'sorted_company_size': 'small'}).
      - `account_list` string, nullable: Comma-separated account list UUIDs. Only people with a known employer in any selected list.
      - `list` string, nullable: Only people in this list — people_lists UUID or exact name (CSV-import list mirroring). Unknown list returns an empty result.
      - `persona` string, nullable: Buying-center role filter: initiator, user, champion, decider, gatekeeper, influencer, executive_buyer, approver, purchaser, unknown, or 'unclassified' (no classification run yet).
    - FacadeCompaniesFilters: Filters for ``type='companies'`` contact search via ``find_people_at_company``.
      - `domain` string, required: Company domain to search (e.g. 'acme.com'). Required.
      - `seniority` string, nullable: Seniority filter: executive (C-level/VP), senior (directors/managers), or junior.
    - FacadeDealsFilters: Filters for ``type='deals'`` (routes to ``get_deals``).
      - `stage` string, nullable: Deal stage filter. Matches the deal's pipeline-stage label LITERALLY (exact, case-sensitive string — not a closed enum). Native pipelines use met, qualified, proposal, negotiation, verbal_yes, closed_won, closed_lost; HubSpot-imported pipelines carry their own custom labels (e.g. 'Hot Leads', 'Prospecting', 'Trial Signup', 'Closed lost'). Pass the literal label exactly as stored. Discover the labels a tenant's pipeline actually uses via inspect_pipeline (groups deals by stage) or by listing deals (with no stage filter) and reading each deal's 'stage'.
      - `outcome` string, nullable: Deal outcome filter: won, lost, stalled.
      - `query` string, nullable: Free-text search for a specific deal — case-insensitive, every whitespace-separated word must match. Spans the deal name, the associated company name, and the primary contact's name/email/title. Combine with stage/outcome to scope further.
    - FacadeObjectivesFilters: Filters for ``type='objectives'`` (routes to ``list_objectives``, filtered client-side — the underlying route has no server-side filter or projection).
      - `status` 'draft' | 'active' | 'paused' | 'completed' | 'retired', nullable: Objective status filter. list_objectives already excludes retired objectives at the source, so status='retired' returns nothing.
    - FacadeMessagesFilters: Filters for ``type='messages'`` (routes to ``get_message_queue``).
      - `status` string, nullable: Message status: needs_draft (unauthored — author via manage_messages edit), draft, approved, rejected, sent (expands to post-send statuses), or all. Omit for default (needs_draft + draft + approved).
      - `channel` string, nullable: Channel filter (email, linkedin_connection, linkedin_message, …).
      - `category` string, nullable: Message category: initial, followup, reply_response.
      - `message_type` 'outreach' | 'inbound' | 'manual' | 'all', nullable: Row family (VRU-832). Omit or 'outreach' for outbound touches (default, unchanged). 'inbound' lists received replies — reply text in content, receive time in created_at, status 'received' (no actionable-status default applies); combine with category='person_reply' to exclude unsolicited inbound. 'manual' lists operator one-off sends — Vruum manual sends and provider-observed external sends (typed directly in LinkedIn/Gmail), status 'sent', no actionable-status default. 'all' returns all three families.
      - `has_reply` boolean, nullable: Only messages that have (true) / have not (false) received a reply.
      - `warm_only` boolean, nullable: true = only WARM follow-ups: linkedin_message rows whose plan has connection_status='connected' (the person ACCEPTED the connection request — highest-EV rows in the queue). Forces channel=linkedin_message. warm_only=true + status='needs_draft' + sort_by='expiring' pulls the warm authoring lane in one call, nearest sweep deadline first.
      - `person_id` string, nullable: Filter by a specific person ID.
      - `search` string, nullable: Search across subject, person email, person name.
      - `sort_by` string, nullable: Sort: recent (default), expiring (created_at asc — nearest sweep deadline first, pair with status='needs_draft'), person_name, subject, priority, or match_score.
      - `sequence_number_min` integer, nullable: Min sequence number, inclusive (T1=1).
      - `sequence_number_max` integer, nullable: Max sequence number, inclusive (T1=1).
      - `score_min` integer, nullable: Minimum match score (0-100).
      - `score_max` integer, nullable: Maximum match score (0-100).
      - `objective_id` string, nullable: Objective UUID, or '__none__' for rows authored outside any objective. Filters the message's AUTHORING objective — not the person's current objective membership.
      - `fields` 'compact', nullable: Set to 'compact' for a lightweight projection WITHOUT message body — keeps message_id, person_name, category, sequence_number, channel, status, match_score (the person's latest fit score) and match_scored_at (the day it was made; score_min/score_max match only scores whose research still holds), touches_completed, objective_id, first_content_touch, channel_rewrite_reason, expires_at, connection_status. first_content_touch=true = the person has never received a content-bearing message (connection requests don't count): treat the item as an OPENER regardless of sequence_number; null = row predates the conversation_state brief (fall back to the sequence_number heuristic). expires_at (needs_draft rows only) = when the nightly sweep auto-rejects the row if still unauthored (regenerate grants a fresh window) — author nearest-deadline-first (sort_by=expiring) to beat it. connection_status = the linked plan's LinkedIn connection state: a linkedin_message row with connection_status='connected' is a WARM follow-up (they accepted the invite) — dispatch these first. Cheap on tokens for triage. An unrecognized value 422s.
      - `view` 'breakdown', nullable: Set to 'breakdown' for a queue-composition summary: grouped counts (by objective × category × sequence × channel × status, plus per-dimension marginals) over the full matching set, alongside a compact items page. Implies fields='compact'. An unrecognized value 422s.
    - FacadeEngagementsFilters: Filters for ``type='engagements'`` (routes to ``get_engagement_queue``).
      - `status` string, nullable: Engagement status: draft, approved, sent, failed, skipped.
      - `sort_by` string, nullable: Sort: priority (default), created_at, or status.
      - `source` string, nullable: Engagement source: comment_reply, warming, nurture, or marketing.
      - `objective` string, nullable: Objective name or UUID used to filter authored engagement rows.
    - FacadeContentFilters: Filters for ``type='content'`` (routes to ``get_content_calendar``).
      - `days` integer: Number of days of calendar history to show (default 14 — same as the underlying endpoint).
    - FacadeKbFilters: Filters for ``type='kb'`` (routes to ``search_knowledge_base``).
      - `query` string, nullable: Fuzzy keyword search. Matches authored docs (name/summary/keywords, typo-tolerant) AND synced connector documents (Google Drive / Notion) by title + body — e.g. meeting transcripts.
      - `doc_type` string, nullable: Filter by type: positioning, case_study, objection_handling, battlecard, process, other (authored docs), or 'connector' for synced Drive/Notion documents only. Omit to search both.
      - `document_id` string, nullable: Fetch full content of one document (ignores query/doc_type). Accepts an authored-doc UUID or a connector id of the form '<connection_uuid>:<source_record_id>' (as returned in search results).
      - `include_content` boolean: Include full document text in search results (default false for a compact catalog). Connector docs return snippets in search mode regardless; read one in full via document_id.
      - `modified_after` string, nullable: ISO-8601 timestamp (no offset = UTC); requires doc_type='connector'. Returns only synced documents modified strictly after this instant — with no query, ordered newest-first. Use this (NOT a keyword query, which is a relevance-ranked top-N sample) for exhaustive 'what synced since <date>' discovery, e.g. finding new meeting transcripts past a watermark.
    - FacadeSkillsFilters: Filters for ``type='skills'`` (routes to the MCP ``list_skills`` route).
      - `scope` string, nullable: Skill scope filter: private, company, or operator. Omit for every scope the caller can see.
    - FacadeCtaLinksFilters: Filters for ``type='cta_links'`` (routes to ``get_cta_links``). The underlying endpoint takes no filters and no pagination — this model is intentionally empty (pagination on ``cta_links`` is rejected at the request level, never silently ignored).
    - FacadeRelationshipAttemptsFilters: Filters for durable web/MCP relationship actions.
      - `target_ref` string, nullable: Opaque entity_ target reference.
    - FacadeDirectoryPeopleFilters: Shared people-directory lookup, with no tenant-private fields.
      - `query` string, required: Name, title, company, or email search text.
    - FacadeDirectoryCompaniesFilters: Shared company-directory lookup by text, canonical industry, or both.
      - `query` string, nullable: Optional company name, domain, or website search text.
      - `industry` 'Unspecified' | 'Agriculture' | 'Construction' | 'Consumer Goods' | 'Consumer Services' | 'Education' | 'Energy & Utilities' | 'Financial Services' | 'Government' | 'Healthcare' | 'Hospitality & Travel' | 'Legal Services' | 'Manufacturing' | 'Marketing & Advertising' | 'Media & Entertainment' | 'Nonprofit' | 'Professional Services' | 'Real Estate' | 'Retail & E-commerce' | 'Software & Technology' | 'Staffing & Recruiting' | 'Telecommunications' | 'Transportation & Logistics' | 'Wholesale & Distribution' | 'Other': Canonical research values plus the fallback bucket used by search.
    - FacadeClaimsFilters: Filters for ``type='claims'`` (routes to ``list_claims`` — the VRU-840 hypothesis ledger).
      - `status` 'open' | 'supported' | 'refuted' | 'stale' | 'retired', nullable: Claim status filter.
      - `person_id` string, nullable: Claims scoped to this person UUID.
      - `company_id` string, nullable: Claims scoped to this company UUID.
      - `deal_id` string, nullable: Claims scoped to this deal UUID.
      - `objective_id` string, nullable: Claims scoped to this objective UUID.
      - `segment` string, nullable: Claims scoped to this named segment.
      - `surface` string, nullable: Claims on this surface, e.g. 'positioning_diagnostic' for the viability claim set (VRU-846).
      - `dimension` string, nullable: Viability dimension, e.g. 'icp_reachability' or 'price_plausibility'.
      - `kind` string, nullable: Claim kind in scope, e.g. 'observed_conversion' for the loop's measurements.
      - `exclude_retired` boolean: Drop retired (superseded) claims so live claims are never crowded out.
      - `limit` integer
  - `limit` integer, nullable: Page size. Supported for people, deals, messages, warm_paths, and relationship_attempts (max 100), engagements (max 200), and directory searches (max 40); people keyword-query mode caps at 40. Ignored for a people batch `query` array, which returns exactly one match record per candidate. Rejected (422) for other types.
  - `offset` integer, nullable: Pagination offset. Supported for people (list mode), deals, messages, engagements, warm_paths, and relationship_attempts. Rejected (422) for other types and for people query mode (a people batch array accepts only 0).

## Response `200`

Successful Response

- unknown

## Other responses

- `422`: Validation Error

---

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