Search contacts (entity-aggregated)

Discover distinct contacts that have one or more signals matching the
filter, sorted by most-recent signal. Each result is a single contact
with its top-N signals attached.

Subtype filtering

Pass signal_subtypes (array, max 25 — OR semantics) to narrow to
specific subtypes, e.g. only jobChange within work-milestones.
The list is CROSS-TYPE: it applies across all requested
signal_types. Discover valid values via the per-type subtypes
array on GET /v1/signals/types?include_counts=true. Matching is
case-insensitive against the known vocabulary; unknown values fall
back to exact match (0 results, never a 400). The singular
signal_subtype remains supported and is unioned with the array.

content_filters (social + podcast search)

Pass content_filters to search inside the enriched content of
social posts and podcast transcripts (the seven social + two podcast
signal types only — see ContentFilters). Structured clauses
(tech_mentioned, competitors_mentioned, pain_points,
initiatives) are exact/fast (typically sub-second) and match social
types only — keywords is the only clause that matches podcast
content; broad free-text keywords over a wide window is the one
thing that can be slow.

Self-service responses

  • 408 query_timeout (default, always on): a broad content search
    that runs out of time returns tailored guidance — message names the
    broad term(s) and lists ordered fixes, with
    details.suggestions / details.broad_terms. Apply a suggestion and
    retry; not charged.
  • 422 query_too_broad (OFF by default, behind
    SEARCH_REJECT_BROAD_KEYWORD): when enabled, an obviously-too-broad
    query is rejected up front with the same guidance body instead of
    grinding into a 408.
  • hint (on a 200 with 0 results from a content_filters
    search): an optional top-level string explaining the likely cause
    (e.g. exact-match fields need canonical names like "Salesforce",
    not "Sales"; or widen detected_after).
  • notice (on a 200 when an entity filter is applied, or when a
    subtype filter includes a high-volume signal type): an optional
    top-level string noting results were limited to the most recent 14
    days (see the detected_after 14-day cap).

Credit cost: 2 per contact returned.

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…
Body Params

Filters for entity-aggregated contact search. At least one
signal_types value is required.

signal_types
array of objects
required
length ≥ 1
signal_types*
string
length ≤ 200

Filter by a single signal subtype. Prefer signal_subtypes (array); when both are sent they are unioned (the singular value acts as one more array member).

signal_subtypes
array of strings
length ≤ 25

Filter by signal subtypes — OR within the array (a signal matching ANY value passes). CROSS-TYPE: the list applies across ALL requested signal_types; SEC filing types share content-tag subtypes, so e.g. {"signal_types":["sec-8k","sec-10k"],"signal_subtypes":["aiInvestment"]} is a first-class pattern. Values are matched case-insensitively against the known vocabulary (see the per-type subtypes array on GET /v1/signals/types?include_counts=true); unknown values fall back to exact match (0 results — never a 400). NOTE: subtype filtering on high-volume types (linkedin-post-, work-milestones, website-intelligence, twitter-, seo-traffic) caps the scanned window to the most recent 14 days (a notice is returned).

signal_subtypes
date-time

ISO-8601 lower bound. Defaults to 50 days ago when omitted, so monthly-cadence signal types always have their latest batch in the default window (bounds the GROUP BY scan; pass an older value to query further back). NOTE: when the request includes an entity filter (industries, employee_count_min/max, revenue_min/max, seniority, department, or job_title) — or a signal_subtype/signal_subtypes filter together with a high-volume signal type (linkedin-post-, work-milestones, website-intelligence, twitter-, seo-traffic, hiring-trends, hiring-velocity) — the scanned window is capped to the most recent 14 days. A wider detected_after is narrowed to a 14-day slice ending at NOW (or, when detected_before is supplied, ending at detected_before). This is a temporary safeguard against statement timeouts on high-volume signal types; unfiltered (type-only) searches are not affected.

date-time
integer
1 to 100
Defaults to 20
integer
0 to 10000
Defaults to 0
integer
1 to 100
Defaults to 25
company_domains
array of strings
length ≤ 100

Filter to signals about these company domains.

company_domains
string
length ≤ 253

Singular alias for company_domains.

industries
array of strings
length ≤ 25

Filter by company industry.

industries
integer
≥ 0

Minimum company employee count.

integer
≥ 0

Maximum company employee count.

string
length ≤ 100

Minimum annual-revenue bucket, inclusive (enrichment-backed). One of "Under 1 Million", "1 Million to 5 Million", "5 Million to 10 Million", "10 Million to 25 Million", "25 Million to 50 Million", "50 Million to 100 Million", "100 Million to 250 Million", "250 Million to 500 Million", "500 Million to 1 Billion", "1 Billion and Over". Matched case-insensitively; unknown labels return 400 with the valid list.

string
length ≤ 100

Maximum annual-revenue bucket, inclusive. Same bucket labels as revenue_min.

seniority
array of strings
length ≤ 10

Filter by contact seniority. Canonical values (case-insensitive): "Staff", "Manager", "Director", "Vp", "Cxo". For accounts with enrichment-backed matching enabled, this filter resolves against the contact enrichment record (strict match), and unrecognized values return HTTP 400 with the list of valid values.

seniority
department
array of strings
length ≤ 20

Filter by contact department. Canonical values (case-insensitive): "Administrative", "Community And Social Services", "Education", "Engineering", "Executive", "Finance", "Government", "Health Services", "Human Resources", "Information Technology", "Legal", "Marketing", "Media And Communications", "Military And Protective Services", "Operations", "Product Management", "Real Estate", "Sales". For accounts with enrichment-backed matching enabled, this filter resolves against the contact enrichment record (strict match), and unrecognized values return HTTP 400 with the list of valid values.

department
string
length ≤ 200

Filter by job title keyword (partial match).

content_filters
object

FISH-892 — search inside the enriched content of social and podcast
signals. Think of it as: "give me the companies/people posting (or
talking) about X, and show me the posts." You get the deduped entity
with its matching signals attached.

Only supported for social + podcast signal types — the seven
social slugs: linkedin-post-company, linkedin-post-contact,
linkedin-comments-contact, twitter-company-posts,
twitter-contact-posts, youtube-company, youtube-contact — plus
the two podcast slugs: podcast-company, podcast-contact. If
content_filters is present and the request includes any other
signal_types, the API returns 400 invalid_request
(content_filters is only supported for social signal types); the
body lists both the allowed set and the offending types. (signal_types
itself is always required — a request without it is rejected at
validation, so there is no "typeless" content search.)

The five fields

Each field below is an independent contains / not_contains clause
(each capped at 20 terms, 1–500 chars per term — see
ContentFilterClause):

  • keywords — substring (ILIKE), case-insensitive, across the
    union of post/comment/video text and summaries (post_text,
    comment_text, video_description, summary, comment_summary);
    for podcast types, the transcript-derived text (headline,
    evidence, quotes[], talking_points[].{point,quote},
    offer_texts[], topics[]). The fuzzy catch-all.
  • tech_mentionedexact (case-insensitive) match on the
    extracted technologies_mentioned[].name. Canonical names only:
    "Salesforce" matches, "Sales" does not.
  • competitors_mentionedexact (case-insensitive) match on
    the extracted competitors_mentioned[].name. Canonical names only.
  • pain_points — substring (ILIKE) on the extracted
    pain_points[].topic.
  • initiatives — substring (ILIKE) on the extracted
    initiatives[].topic.

Podcast caveat: podcast payloads carry only transcript-derived
text — none of the four extracted arrays — so keywords is the only
clause that matches podcast content
; tech_mentioned,
competitors_mentioned, pain_points, and initiatives match social
types only and never match a podcast row. The same asymmetry governs
not_contains: pain_points.not_contains / initiatives.not_contains
exclude all podcast rows (the searched text is NULL for podcast,
and NOT (NULL ILIKE …) is not true — the same semantics as a social
row missing the field), while tech_mentioned.not_contains /
competitors_mentioned.not_contains keep podcast rows (an empty
array matches no excluded term).

Boolean logic

  • Within a contains array → terms are OR'd (match ANY).
  • not_contains → exclude the row if ANY term hits.
  • Across the five fields → clauses are AND'd (a row must
    satisfy every field you specify).

Prefer the structured fields over free text when they fit your intent:
"companies mentioning Salesforce" → tech_mentioned: {contains: ["Salesforce"]} (exact + fast), not keywords: {contains: ["Salesforce"]}.

Performance

Structured clauses (tech_mentioned, competitors_mentioned,
pain_points, initiatives) run against indexed extracted fields and
are typically sub-second. The one thing that gets slow is a broad
free-text keywords search over a wide date window — a common word
matches an enormous number of posts and grouping them is the cost. To
stay fast:

  • Keep keywords searches to a ≤ 30-day detected_after window.
    Social data refreshes on a biweekly (LinkedIn posts) /
    monthly (Twitter, YouTube, comments) cadence, so a 30-day window
    already contains everything fresh — scanning wider buys latency, not
    recency.
  • Pair keywords with a selective clause — a tech_mentioned /
    competitors_mentioned clause or company_domains shrinks the
    candidate set first and makes even a wide window fast.
  • Send fewer signal_types per call.

A broad query that still runs out of time returns 408 query_timeout
with tailored, ordered guidance (term names + fixes in
details.suggestions / details.broad_terms) — apply a suggestion and
retry; it is not charged. A 408 means "too broad," not "down." When the
SEARCH_REJECT_BROAD_KEYWORD flag is enabled (OFF by default), an
obviously-too-broad query is instead rejected up front with 422
query_too_broad
carrying the same guidance body. A 200 with 0
results
is normal for exact-match fields over sparse windows and
comes with an explanatory top-level hint.

Responses

Language
Credentials
Header
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json