Query Search Results
query_search_resultsColumns: id, agent_id, entity_type, list_name, source, identifier,
display_name, verdict, verdict_reason, data (JSONB), created_at, person_id,
company_profile_id. Filter by list with "list_name = 'oil-gas'". source is
the discovery tool that surfaced the row ('agent' when no discovery tool did;
'legacy' for rows older than the column). verdict is the curation call
recorded on the row with record_search_results — 'qualified', 'rejected', or
NULL for a row nobody reviewed — with verdict_reason saying why. Rejected rows are left out
unless you pass verdict='rejected' or include_rejected, the same as the user's default view,
so a where_clause on verdict alone never reaches them.
person_id / company_profile_id are the canonical person / company FK ids
(NULL until the row is linked). A person's profile (title, company) and a
company's firmographics (industry, location, employee count, description) — the
values the agent's People and Companies tabs show — live on the linked record, not
in the row's own data: read them with query_people / query_companies on
those ids, and filter on them through the id, e.g. "company_profile_id IN (SELECT
id FROM research_app_company_profiles WHERE industry ILIKE '%oil%')". A company
row with no company_profile_id is an unidentified company and has none.
For a person's LinkedIn degree and warm-intro connectors, or the agent's people
counted by list, source, degree or connector, use query_task_people instead.
data has no single schema — its shape follows whichever source wrote the
row (it is the agent-authored blob). Most person rows nest under person
(data->'person'->>'position',
data->'person'->'company'->>'name') and most company rows under company
(data->'company'->>'name'), but other sources
write those fields flat. A path that doesn't exist yields NULL rather than
an error, and a NULL comparison drops the row — so a filter aimed at the
wrong shape comes back empty or short and reads as a genuine miss. Read a
page of rows without a data filter first, then filter against the shape
you see.
Person rows are annotated with the team connection overlay (mirrors the Find
UI): a matched row's data gains connection_status: {you: bool, teammates: [{email, name, first_name}]} naming the viewer/teammates who are 1st-degree
to that prospect; unmatched rows and company rows carry no such key. A
top-level connections_coverage: {you: 'none'|'partial'|'csv_uploaded', team_missing: int} reports the owner's own connection coverage and how many
active teammates still lack a CSV upload. The viewer is the agent owner.
In row mode (group_by omitted) — a dict with count, truncated, and items
array (each row {id, agent_id, entity_type, list_name, source, identifier,
display_name, verdict, verdict_reason, data, person_id, company_profile_id,
columns, created_at}),
plus connections_coverage {you, team_missing}. columns is the normalized
[label, value] projection of the row's agent-researched data.columns.
In aggregate mode (group_by set) — a dict {group_by, groups} where groups
is a list of {key, count} ordered by count descending.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results (default 50, max 200). | |
| offset | No | Rows to skip for paging (default 0). When the result is truncated, re-call with offset += limit for the next page. | |
| verdict | No | Only the rows with this verdict, 'qualified' or 'rejected' ('rejected' reads the rows the user's default view filters out). Omit for every verdict. | |
| agent_id | Yes | Filter to a specific agent (required). | |
| group_by | No | Aggregate mode, returned instead of the row list — per-bucket counts over the whole agent (not truncated by the row cap). "list" buckets rows by list_name; "company" buckets people by employer; "source" buckets rows by the discovery tool that surfaced them. Omit for the row list. | |
| order_by | No | SQL ORDER BY (default: created_at DESC). | created_at DESC |
| where_clause | No | SQL WHERE condition (default returns all rows for the agent). Examples: "data->'person'->>'position' ILIKE '%VP%'", "entity_type = 'person'", "list_name = 'oil-gas-operators'". | 1=1 |
| include_rejected | No | Also return (and count) the rows marked rejected. Default False. |