Endpoints

Search

Query companies, people, or a document corpus with natural language, structured filters, or both.

POST/v1/search

Search a category of the Sprouts corpus

Search one category — companies, persons, or a document vertical.

mode decides how the query is interpreted; resolved_search in the response says what we decided it meant.

Scope: dsp.search.read

Use it when you are finding companies, people, or documents that match a description or a set of constraints. Outcome: a ranked, pageable list in the standard envelope, with resolved_search echoing how the request was interpreted. Worked use cases: search guide.

category decides what you search and what every returned row is — the two are the same fact, so results[].category always echoes the request. query and filters are each optional, but every request must carry at least one of them: describe what you want in words, pin it down with structured constraints, or do both and let the response's resolved_search tell you how the two were combined.

Every search is metered by mode (dsp.search.fast, dsp.search.auto, …). A Basic (fast) search costs 0.5 credits for its first 10 results and 0.08 per extra result; an AI (auto) search 0.595 and 0.085, counted across all the pages of one search. A Basic or AI search that finds nothing costs nothing (a deep search is charged a flat price even when it returns no rows), and meta.credits_charged states what each response cost. Test keys run the same query against the same corpus for zero credits — the response says meta.environment: "test".

Request#

categoryEntityCategory | null

What to search. Omit it to have prism classify query and pick a category automatically (POST /v1/search/query upstream). That path takes query only — no filters, no domain restrictions, and only under mode: auto, since classification is itself one LLM call routing into an already-parsed vertical.

cursorstring | null
exclude_domainsarray of string, ≤ 100

company, person, and job_opening only.

filtersDiscoverFilters | object | null

For company and person, the typed discover vocabulary documented above — unknown names and wrong shapes are refused here, by name. For the document categories, a free-form mapping of that vertical's own top-level filters, validated upstream.

b2b_b2cTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

certificationsTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

companyEntityFilter | null
excludearray of EntityRef, ≤ 1000
by"name" | "domain" | "li" | "id" | null

Force a resolution mode. When omitted the server classifies the token.

valuestringrequired

≥ 1 chars.

includearray of EntityRef, ≤ 1000
by"name" | "domain" | "li" | "id" | null

Force a resolution mode. When omitted the server classifies the token.

valuestringrequired

≥ 1 chars.

company_keywordTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

degreeTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

departmentTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

domain_presenceTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

employee_by_departmentDepartmentHeadcountFilter | null
boundsarray of DepartmentHeadcountBound, ≥ 1, ≤ 1000required
departmentstringrequired

≥ 1 chars.

maxinteger | null

≥ 0.

mininteger | null

≥ 0.

employee_countRangeFilter | null
gteinteger | number | null
lteinteger | number | null
employment_historyEmploymentHistoryFilter | null
groupsarray of EmploymentHistoryGroup, ≥ 1, ≤ 1000required
companyEntityFilter | null
excludearray of EntityRef, ≤ 1000
includearray of EntityRef, ≤ 1000
role_endedDateBound | null
gtestring | null
ltestring | null
presetDatePreset | null
role_startedDateBound | null
gtestring | null
ltestring | null
presetDatePreset | null
tenure_gteinteger | number | null
tenure_lteinteger | number | null
titleTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

employment_typeTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

founded_yearRangeFilter | null
gteinteger | number | null
lteinteger | number | null
funding_stageTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

geoGeoFilter | null
placesarray of GeoPlace, ≥ 1, ≤ 1000required
level"country" | "state" | "city" | "region"required

Required: there is no place-name -> level resolver on the request path, so berlin is only a city because you said so.

negatebooleandefault: false

Exclude this place instead of requiring it.

scope"subject" | "company" | "person"default: subject

Whose location a place constrains. subject (default) is whatever record type is being searched. company/person force that side regardless of the search target, which is what lets a contact search constrain the parent company's HQ.

valuestringrequired

≥ 1 chars.

global_presenceGlobalPresenceFilter | null
countriesarray of string, ≤ 1000

Countries (names or ISO3 codes) or regions (EU, APAC, Nordics, DACH, LATAM, ...).

gteinteger | null

Per-country headcount floor. ≥ 0.

lteinteger | null

≥ 0.

match_allbooleandefault: false

People in EVERY place named, not any one.

min_countriesinteger | null

≥ 1.

gov_nongovTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

governance_levelTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

has_direct_access_to_c_suiteTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

hiring_locationTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

hiring_recencyDateBound | null
gtestring | null
ltestring | null
presetDatePreset | null
hiring_roleTextFilter | null
exactbooleandefault: false
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
hiring_typeTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

industries_servedTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

industryTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

investorsEntityFilter | null
excludearray of EntityRef, ≤ 1000
by"name" | "domain" | "li" | "id" | null

Force a resolution mode. When omitted the server classifies the token.

valuestringrequired

≥ 1 chars.

includearray of EntityRef, ≤ 1000
by"name" | "domain" | "li" | "id" | null

Force a resolution mode. When omitted the server classifies the token.

valuestringrequired

≥ 1 chars.

is_subsidiaryTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

keywordsCompanyKeywordsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
match_allbooleandefault: false
target_fieldsarray of "name" | "keywords" | "description", ≥ 1required

Which company fields to search. At least one is required.

last_funding_amountRangeFilter | null
gteinteger | number | null
lteinteger | number | null
last_funding_dateDateBound | null
gtestring | null
ltestring | null
presetDatePreset | null
last_job_changedDateBound | null
gtestring | null
ltestring | null
presetDatePreset | null
linkedin_connectionsRangeFilter | null
gteinteger | number | null
lteinteger | number | null
linkedin_followersRangeFilter | null
gteinteger | number | null
lteinteger | number | null
linkedin_presenceTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

listing_statusTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

naicsTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

owned_by_organizationEntityFilter | null
excludearray of EntityRef, ≤ 1000
by"name" | "domain" | "li" | "id" | null

Force a resolution mode. When omitted the server classifies the token.

valuestringrequired

≥ 1 chars.

includearray of EntityRef, ≤ 1000
by"name" | "domain" | "li" | "id" | null

Force a resolution mode. When omitted the server classifies the token.

valuestringrequired

≥ 1 chars.

personTextFilter | null
exactbooleandefault: false
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
product_serviceTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

profit_nonprofitTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

revenueRangeFilter | null
gteinteger | number | null
lteinteger | number | null
seniorityTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

sicTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

skillsTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

stock_exchangeTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

sub_industryTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

technologyTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

tenureRangeFilter | null
gteinteger | number | null
lteinteger | number | null
titleTextFilter | null
exactbooleandefault: false
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
total_fundingRangeFilter | null
gteinteger | number | null
lteinteger | number | null
universityTermsFilter | null
excludearray of string, ≤ 1000
includearray of string, ≤ 1000
include_groupsarray of array of string, ≤ 1000 | null

The include values, one list per thing named: any value in a list satisfies it, and match_all requires every LIST rather than every value. technology resolves a product onto every name the index stores it under and reports them this way, so a resolved filter sent back keeps "both X and Y". include stays the source of truth: a value removed from it leaves its group.

match_allbooleandefault: false

True requires every include value (AND). False (default) is OR.

years_workedRangeFilter | null
gteinteger | number | null
lteinteger | number | null
include_domainsarray of string, ≤ 100

company, person, and job_opening only (the company that posted the role) — every other category is a document with no domain of its own.

limitintegerdefault: 10

≥ 1, ≤ 100.

mode"fast" | "auto" | "deep"default: fast

How hard to work on the query. The distinction is *what the words mean*, not how many results come back: - fast — match my words. The query is matched by meaning (vector retrieval, falling back to keywords where vectors are unavailable); no LLM in the path, so nothing is extracted into filters. - auto — understand my intent. The parser extracts filters. - deep — reason about it. Multi-step, slowest, most expensive. fast was very nearly defined as "filters only, no LLM", which would have made query — the primary parameter — silently inert. A parameter that does nothing is worse than one that is missing.

querystring | null

≤ 2000 chars.

sortarray of SortClause, ≤ 3 | null

How to order the results, strongest key first. Omit it to get the engine's own ordering — relevance when there is a query to be relevant to, and a quality ranking when there is not. Every field accepts both asc and desc. Ask GET /v1/sorts/{category} for the fields a category accepts, with labels and default directions; do not hardcode a list.

direction"asc" | "desc"default: desc
fieldstringrequired

≥ 1 chars, ≤ 64 chars.

Headers

Idempotency-Keystring

Makes a retry safe. Send a unique value per request and reuse it when you retry that same request: with the same body and credential, on the same UTC day, rows already charged are not charged again.

filters is a different set per category — 51 typed fields for company and person, a smaller vertical-specific set for each document category. Every one of them, with its value shape, is in the filters guide; what a given filter can be set to comes from GET /v1/search/filters/{name}.

sort replaces the engine's own ordering with up to three explicit clauses, strongest key first. It requires an explicit category, and the fields a category accepts come from GET /v1/sorts/{category} — see Sorting for the rules.

Response#

Results arrive in the standard envelope: results plus pagination (has_more / next_cursor — opaque, signed, no page numbers), what the parser decided your query meant (resolved_search), data provenance (attribution), and anything that degraded mid-request (degradation).

attributionarray of Attribution
as_ofstring | null
domainstring | null
quotestring | null

RESERVED for per-fact citation. Always null in v1.

source_corpusSourceCorpus

Where content came from. Closed set — it appears in attribution[]. The first four are the GTM entity graph. The rest are the document corpora behind the non-entity categories, each a distinct index with its own refresh cadence — which is the reason they are named separately rather than lumped under one label: attribution[].as_of means nothing if two corpora updated a month apart share a name.

urlstring | null

RESERVED for per-fact citation. Always null in v1.

columnsarray of object | null

The answer table's columns, in order, when a run carries extra columns beyond the entity's own fields -- a job-opening link, a value joined from another dataset. Each entry is {name, description, source}; the value for each sits on every row in results keyed by the column name. Null means a plain entity table. Additive, so it breaks no existing client.

coverageCoverage | null

How much of the addressable set this answer represents. Null means coverage was not measured for this request -- fast and auto do not enumerate -- and never that coverage was zero. Additive, so it breaks no existing client.

auditedbooleandefault: false

Whether the query was checked against the executed filter for dropped requirements. Reported because an empty constraints_unmet only means something if something looked.

constraints_unmetarray of string

Requirements in your query that the search could not express, in your own words. Non-empty means part of the question was not answered -- most often because it needs a dataset this search cannot reach (job postings, employment history, patents, news, funding dates). When this is non-empty, universe_exhausted is withheld: 'we returned everything that matches' cannot be true of a question that was never asked.

criteriaarray of object

Per criterion: evaluated, passed, success_rate, and whether it was *proven* by the query or *judged* by a model. Without this a thin result leaves the caller guessing which requirement thinned it.

enumeratedinteger

How many of them this answer carries. ≥ 0.

enumeration_recallnumber | null

enumerated / universe. Null when the universe was not exact, because a ratio over an estimate is not a recall figure. Note this measures coverage of the *resolved query*, not of the user's intent -- a wrong predicate can be exhaustively enumerated. ≥ 0, ≤ 1.

linkagearray of object

One entry per other dataset this answer joined against: corpus, join_key, observable, of_constrained, ratio, is_lower_bound. ratio is the fraction of your matching accounts that dataset can even see -- measured at 5-60% depending on the dataset and how large the companies are, and never 100%. Non-empty therefore means universe_exhausted is withheld by construction: we returned everything reachable, and a dataset cannot see the rest.

linkage_coveragenumber | null

The joins combined, as a product rather than a minimum: two datasets seeing 27% and 24% of your accounts jointly see about 6.5%, not 24%. Null when no join was performed or when any leg's coverage is unknown.

linkage_coverage_is_lower_boundbooleandefault: false

True when a key set was capped or coverage was estimated rather than measured, making linkage_coverage a floor. Narrowing the question makes it exact.

similarityarray of object

Narrowings done by ranking rather than by predicate. Each entry carries the concept, how many ids it resolved to, the k asked for, whether the list was cut at that ceiling, and the fraction of candidates that could be compared at all. Non-empty means universe_exhausted is withheld on purpose: a cosine is a degree, so a top-k ranking has no complete state, and 2.9% of companies carry no embedding to compare.

truncated_bystring | null

Which limit stopped the enumeration short, when one did.

universeinteger

Records matching the resolved query, counted, not sampled. ≥ 0.

universe_exhaustedbooleandefault: false

Every matching record was returned and the count agrees. The claim an unbounded-corpus search engine cannot make.

universe_is_exactboolean

False when the count hit a cap. Always serialized: a capped count presented as exact is the same lie as an unmeasured one.

degradationarray of Degradation
detailstring
impact"recall" | "precision" | "freshness" | "fields"
reasonDegradationReason

Why an answer is less than it should be. Closed, because a client that cannot branch on the reason can only show the user a shrug. These are the honest constraints — partial vector coverage, smry mapped as keyword so it cannot be scored lexically, a federated corpus being unreachable — surfaced at runtime instead of in a footnote.

source_corpusSourceCorpus | null
has_moreboolean
metaResponseMeta

Present on every 2xx, including the ones that are not paginated.

as_ofstring
credential"api_key" | "session"default: api_key

Which credential produced this response. session means the dashboard playground ran it as the signed-in user rather than as an API key — so it is billed to the user, subject to interactive rate limits, and carries no integration compatibility guarantee. Additive and defaulted, so it breaks no existing client.

credits_chargednumber | null

What this request cost, in credits, to at most three decimals. 0 when it cost nothing: a Basic or AI search that found nothing, rows this search already paid for (a cursor sent again, or a request repeated with the same Idempotency-Key on the same UTC day), or a test key. A request without a cursor or a repeated key is a new search, so keep the first page rather than asking for it again. null on a free endpoint.

environment"live" | "test"

Echoed on every response so a developer can never mistake a test-key result for a live one.

request_idstring
next_cursorstring | null

Opaque and signed. Invariant: has_more == (next_cursor is not None). There is no page or offset parameter — not accepted, not deprecated, never present.

resolved_searchResolvedSearch | null
categoryEntityCategory

*What* to search, and what a returned row is. One parameter carries both, because they are the same fact: a search of patent returns patents. The alternative — a source/vertical selector beside a narrower category — lets a caller ask for patents from the people index, a combination that has no meaning and would need rejecting at runtime. A closed set that cannot express the contradiction is better than a validator that catches it. Values are exactly prism's own row types, so category in the request and results[].category in the response are always the same string. company and person are the GTM index; the rest are separate corpora with their own filters, freshness and coverage. Not everything applies everywhere: see SearchRequest, which rejects the GTM-only parameters rather than ignoring them. job_opening is a document corpus like patent/news_article/etc — a posting, not an entity — but its records carry a domain (the posting company's) all the same. It is deliberately not in GTM_CATEGORIES (that set is about the entity/document distinction, and a job posting is still a document), but it *is* in DOMAIN_FILTERABLE_CATEGORIES, which exists specifically to separate those two axes.

conflictsarray of object
filtersFilters
filters_source"caller" | "parser" | "caller+parser" | "none"default: none
mode"fast" | "auto" | "deep"

How hard to work on the query. The distinction is *what the words mean*, not how many results come back: - fast — match my words. The query is matched by meaning (vector retrieval, falling back to keywords where vectors are unavailable); no LLM in the path, so nothing is extracted into filters. - auto — understand my intent. The parser extracts filters. - deep — reason about it. Multi-step, slowest, most expensive. fast was very nearly defined as "filters only, no LLM", which would have made query — the primary parameter — silently inert. A parameter that does nothing is worse than one that is missing.

overridesarray of object
parser_versionstring
querystring | null
semantic_querystring | null
semantic_scope"company" | "person" | null
sortarray of object
resultsarray of object
suggestionSearchSuggestion | null

A better way to have asked this question -- a different category (kind: search), or agentic search via POST /v1/agents (kind: agentic). Advisory: these results came from the search that was asked for, whatever this says. Null when there is nothing worth suggesting, which is the common case. Additive, so it breaks no existing client.

categoryEntityCategory | null

The category to search instead. Set iff kind is search.

kind"search" | "agentic"

search — a different category fits. agentic — no single search fits; use POST /v1/agents.

messagestring

One ready-to-show sentence.

totalinteger

≥ 0.

total_is_estimateboolean

Always serialized, never defaulted away. A field clients can forget exists is a field that renders an estimate as exact.

The shape of each results[] hit varies by category: a company search returns company records, a patent search returns patent documents, and so on. The per-field tables live with the matching entities route — see company records for the company hit shape.

Errors#

StatusCodeSummary
401auth.unauthorizedNo usable credential (cause deliberately unspecified)
402credits.insufficientThe allocation cannot fund this action
403auth.browser_originA secret key was used from a browser
403auth.insufficient_scopeThe credential does not hold the required scope
422pagination.cursor_invalidThe cursor could not be read (e.g. a filter changed mid-pagination)
422request.invalidA field failed validation (extra.errors has the detail)
429quota.burst_exceededInteractive burst limit hit — wait Retry-After seconds
501not_implementedA capability that is not available yet
503credits.unavailableThe billing service could not confirm the charge; retry with the same Idempotency-Key
503upstream.unavailableThe retrieval engine is unreachable (not charged)
504upstream.timeoutThe retrieval engine did not answer in time (not charged)