Research
Run prospect/company research and save the results — the consolidated research tool.
- start_account_brief: explicitly delegate one account brief to Vruum's durable worker, for an objective or for the account alone. First fetch research_work_list with company_id (and objective_id for an objective brief); inspect existing work and use the returned scope planning_version. Payload requires {company_id, request_id (UUID), source_mode (saved_public or refresh_public)}, plus {objective_id, expected_planning_version (positive integer)} for an objective brief. Without objective_id the brief is framed by the workspace's own profile and live offers, and any workspace member may request it. Search and model work runs after this call and survives leaving the page. A matching active or unresolved job is reused; retain request_id on retries. Start only after the user requests this exact scope. A model suggestion is not approval. The native assistant uses its write approval card; an external harness must obtain its user's authorization before calling. saved_public uses permitted saved public sources and business configuration. Both modes add the account's captured mail (newest 12 messages from the last 180 days whose participants share the account's domain). The brief may propose commitments from that mail (owed_by us/them, due_on) as open Claims; record a verdict on one only when the user asks. refresh_public also authorizes one public-domain search and live verification of up to three company pages before synthesis. Search excerpts are not evidence. Retain the exact source_mode on retries; existing work with another mode conflicts. Failed or partial refreshes remain visible in source coverage. Neither mode grants other private source access, transcript persistence, browser credential storage, or external-harness execution handoff. Poll fetch research_work; read Claims and citations with fetch account_brief, both id=returned Action UUID. The worker automatically recovers saved provider response IDs and terminal receipts after interruption. A missing or unavailable provider response needs operator investigation; manual repair is unsupported and a fresh request_id cannot authorize replay.
- cancel_account_brief: id=Action UUID; payload={expected_version} from the current saved work. Stops continuation and requests cancellation of pending saved model responses. A dispatched search or model call may still finish; cancellation does not prove the provider stopped. Both account-brief writes accept one request only, without items or batches.
- preview_gaps: READ ONLY assignment, no research or spend. id=objective UUID; payload={subjects:[{type, company_id}], question_ids?, stage?, use_public_web?:true, use_history?:false}. Each subject names its type and exactly that type's ids: company {company_id}, person {person_id}, person_at_company {person_id, company_id}, deal {deal_id}. Up to 20 subjects and 40 unique gaps. Reuses current account answers across people. Equivalent reviewed fact definitions also reuse original observations across objectives when their subject, schema, sources, quality and freshness match. Reused answers retain original evidence IDs; do not save duplicate copies. Read gaps, question definitions, source permissions and limits before choosing work.
- stop_gaps: id=objective UUID, payload={action_id}. Stop future calls and answer writes. Already sent provider work can finish.
- propose_gaps: same input; saves an Action without executing research.
- approve_gaps: id=objective UUID, payload={action_id}. Only after the user approves that exact saved assignment. Starts bounded Vruum research. Poll fetch research_run id=action UUID. Never repeat approval to retry. For research on YOUR compute, use preview_gaps, fetch research_sources, your permitted tools, then save_answer. Do not approve Vruum research as a substitute for external research. Your harness pays its own compute. Use the exact subject, question ID and definition fingerprint from the assignment. Public URL excerpts remain reported. Never assert customer confirmation without an explicit operator attestation.
- save_answer: record one answer for a saved objective research question (id = objective UUID; payload = {idempotency_key, question_id, definition_fingerprint, subject (one preview_gaps subject), state: answered|unknown|unavailable, value, source: {kind, reference?, excerpt, observed_at}, note?, supersedes_evidence_id?}). Read the question and answer_schema through fetch research_answers first. Source kinds: operator_report, public_url (reported only), activity, evidence, meeting, customer_confirmation (explicit operator attestation). Existing references must match the tenant, subject, excerpt and original observation time. Exact retries retain their UUID; changed content needs a new UUID. Corrections explicitly supersede one observation. Answers never authorize outreach. Generic save_evidence/save_claim cannot write research answers.
Lookup and enrichment actions (results are returned, not stored unless noted). Synchronous lookups without a saved result (find_email, linkedin_fetch, enrich_company, careers_parse) are on research_lookup.
- find_linkedin: locate a person's LinkedIn URL (id = person UUID; payload optional {name_override?, company_override?, auto_save?} — auto_save stores a high-confidence match).
- enrich_account: acquire a bounded first-party evidence bundle for a tenant-visible account (id = canonical company UUID). The response also carries canonical company fields, cached shared research, and freshness metadata for the harness to combine with its own web and MCP sources. Persist sourced conclusions with save_company. research_lookup action=enrich_company remains the domain/page website-fetch primitive.
- enrich_person: enrich each person according to missing contact and profile fields (id = person UUID, or an array of up to 100; payload optional {force_refresh?}). Returns a job_id; poll it with fetch type=job. Outcomes report a stable reason code, and jobs with any errored outcome terminate as completed_with_failures. Successful outcomes report readiness=email_ready, incomplete, or manual_review plus the canonical employer binding. Vruum applies separate monthly profile and Hunter-credit soft limits. Harness web search and other MCP tools remain complementary for deeper research. The legacy enrich_profile name is an alias.
- enrich: canonical scoped enrichment. It inspects each person and runs only the needed profile or verified-email work. Pass payload with exactly one of {person_ids: [...]}, {objective_id: ...}, or {list_id: ...}. Returns a job_id; poll it with fetch type=job. The enrich_emails action remains as a compatibility alias for the same scoped planner.
Save actions (write research rows):
- save_person: UPDATE research on an EXISTING person — pass the person UUID as payload.person_id (preferred; refreshes researched_at and the research fields in place), or matching email/linkedin anchors. Cannot create: new prospects go through manage_person action=save_discovered with payload.person + payload.assessment. Never pass the person UUID as id — this action takes no id.
- save_company: atomically patch sourced public company research. Pass payload={company_id?, allow_create?, idempotency_key, name, industry, person_id?, website?, linkedin_url?, company_summary?, company_stage?, current_priorities?, funding_data?, growth_metrics?, sources_by_field}. industry is required and must be one CanonicalIndustry value: 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, or Other. Provider labels and Unspecified are rejected. Omitted research fields are preserved; explicit null clears. When researching a specific person's employer, ALWAYS pass their UUID as payload.person_id — the response's person_link confirms the write landed on that person's linked company (repointing an anchorless duplicate link when needed); a mismatch status means the person's touches will NOT see this research, and a conflict status is a transient race — replay the identical payload (person_id is exempt from the idempotency hash, so adding it to a replay is the supported repair). For a researched-prospect save, save_company is also the company identity resolution step. For an existing account, ALWAYS pass payload.company_id, including the ID returned by enrich_account. Updates never create or merge a company. Otherwise call save_company with allow_create=true plus name and website and/or linkedin_url. Never combine company_id with allow_create=true. Conflicts require identity reconciliation; never retry by dropping the ID. Identity selection, missing native identifiers, and research commit together. Call it even with no new research fields, and capture the returned company_id for manage_person action=save_discovered. A company name alone is not a save identity. sources_by_field must contain exactly every supplied non-null research field, with entries {url, title?, observed_at}. Example: {"allow_create":true,"idempotency_key":"pipeline/example.com/save-v1","name":"Example", "industry":"Software & Technology","website":"https://example.com", "company_summary":"Example sells …", "sources_by_field":{"company_summary":[{"url":"https://example.com/about", "title":"About","observed_at":"2026-07-30T20:00:00Z"}]}}.
Hypothesis-ledger actions (VRU-840 — beliefs with scoreboards, never prose):
- save_claim: record one falsifiable belief. payload = {statement, scope ({person_id|company_id|deal_id|objective_id|segment|tenant}), origin (diagnostic|system|operator|pin|experiment), invalidating_conditions?: [..], evidence?: [{kind, payload, source, method?, staleness_class (durable|slow|fast|volatile), trust? (first_party|untrusted_capture|third_party), stance? (supports|contradicts), weight?, person_id?|company_id?| deal_id?|objective_ref?|tenant_scoped? (accounts are the tenant-company pair — link company_id)}]}. Confidence is derived from the linked evidence and cannot be asserted; identical evidence payloads dedupe. origin='diagnostic' requires non-empty evidence and invalidating_conditions, so a diagnostic cannot save unsupported prose. Positioning-diagnostic scopes (scope.surface='positioning_diagnostic') always need evidence + invalidating_conditions (any origin) and must carry tenant=true, a dimension, a trimmed segment, and — for icp_reachability / price_plausibility / motion_fit only — a cohort objective_id anchor plus a structured scope.test ({version:'viability_test.v1', metric, comparator, threshold, min_sample>=20, window_days}) that the viability loop evaluates from spine outcomes. Returns the claim with its full scoreboard. Use items to save a batch (e.g. a positioning diagnostic's claim set).
- save_evidence: mint one observation with provenance, optionally linking it to an existing claim (payload.claim_id + stance/weight).
- record_claim_verdict: append a verdict (id = claim UUID; payload = {status, basis, confidence?, note?, experiment_id?, superseded_by?}). basis='causal' requires experiment_id — the laboratory honesty rule. A retired verdict may name superseded_by (the LIVE replacement claim's UUID) so readers can follow a retired scope to its successor; any non-retired verdict clears the pointer. Read claims with search type='claims' and fetch type='claim'.
Batch research returns per-item results (partial failure is reported per item, never silent). The facade's backward-compatible request cap is 100; enrich_account accepts up to 10 accounts per request. Operators should execute the smaller policy waves documented by pipeline-fill (10 companies or 5 people at a time) so progress and retries stay bounded. find_linkedin also takes person-id arrays. Payloads are validated by the underlying route's own schema.
Request
- Base URL: https://api.vruum.ai
- URL: https://api.vruum.ai/api/facade/research
- Auth: HTTPBearer (a scheme the document does not define)
Request body
Response
Successful Response
Changes
No recorded changes to this operation across all 1 revision of this API.