Clay search
Search Clay's GTM database with advanced queries and return matching records — people or companies.
Audiences is the workspace's own people and companies — read and segment what they already have. Search is Clay's GTM database for net-new lists. This is not the tables entry-point skill (querying data already in a table) and not the workflows entry-point skill (automations). Reach for Search when the user wants to find prospects or accounts not in the workspace yet.
How it works
A search is a three-step, forward-only iterator:
- Discover the query grammar and queryable fields.
- Create the search and receive a
searchId. - Run it to pull the next page of records. Repeat while
hasMoreistrue.
There is no cursor: the iterator's position lives server-side and can't be replayed, so
each run call returns the records after the previous one.
Before authoring a query, save the reference to a file in your working directory and read it from there — it is about 2,000 lines, far larger than one tool result can hold, so never print it to stdout or read it end to end:
clay searches query-mode reference | jq -r '.reference' > ./clay-search-reference.md
grep -n '^##' ./clay-search-reference.md
The grep lists every section with its line number. Read these sections by line offset, once per conversation:
- Grammar, Operators, Where Semantics, and Query mode policy.
- Common query guardrails plus the People or Companies query guardrails for the entity you are searching.
- Your entity's field catalog in full — People fields and Experience fields for people searches, Companies fields for companies searches. Every field name and every allowed enum value is there; a value that is not listed fails validation.
Read a topic section (Location filtering, Dates/tenure/recency, Company identification,
Products and services, Company size and revenue) only when the request needs it, and grep
Examples for a field or phrase to see a worked query. Do not re-read sections already in
your context. Queries return people or companies only; job-posting criteria are nested
filters on those (jobs.exists(...), company.jobs.any(...)). Workspace audience
references are covered in the Audiences section below.
Run clay searches --help (and clay searches <cmd> --help) for flags and output shapes.
If clay isn't on PATH or clay whoami fails on auth, run the setup skill.
Audiences
The query language supports @audience_segment("segmentId") references; they resolve
against the workspace when the search runs. clay searches query-mode reference also
serves the Clay UI, so wherever it says to route an audience to a picker ("Resource
selection required … in the Clay Search panel"), that applies only to the UI surface.
When authoring a query here, resolve the audience yourself:
- To exclude everything the workspace already has — "exclude my existing contacts",
"net-new accounts only", "not already in Clay", "exclude all my audiences" — use the
built-in sentinel
@audience_segment("ALL"), the whole Audiences dataset for the query's entity:clay.exclude_people_identifiers(@audience_segment("ALL"))orclay.exclude_company_identifiers(@audience_segment("ALL")). No lookup, no segment to create. Only resolve a specific segment when the user names a particular audience. clay audiences list --entity-type people|companiesreturns segment ids. Contact segments match people queries; Account segments match companies queries. Follow each response'scursorwith--cursoruntil it is absent before matching a name or checking for duplicates. Write the id into@audience_segment("<segmentId>"). The reference's "Workspace resource references" section has the function signatures — e.g.clay.exclude_people_identifiers(@audience_segment("SEGMENT_ID"))to exclude a Contact audience, orclay.filter_to_companies(@audience_segment("SEGMENT_ID"))to target current employers from an Account audience.- Never invent a segment id. If the user names an audience you cannot resolve, ask rather than guessing. Confirm with the user if multiple segments match the name.
When a criterion isn't supported
Check the reference before deciding whether it can express the criteria. Do not invent a field or operator that is not in the reference.
If the query can't express a criterion, split the request into what search can do and what a routine does:
- Search on the closest available built-in criteria to get a candidate set (e.g. industry, size, or title criteria that approximate the intent).
- Feed those results into a saved routine that enriches or scores each record for the attribute the user actually asked about, then filter or act on that routine's output.
Tell the user the field isn't a native search filter and offer this search → routine path
rather than returning nothing. See the routines skill and "Next: enrich or persist the
results" below for the handoff.
Warn before large generic searches
Before create, if the ask is generic and large — few criteria beyond something like
industry + location (e.g. "all tech companies in NYC") — stop and suggest refining first.
Offer 2–3 concrete narrowing options search can express (company size, title/seniority,
open roles, tech stack, products and services, named companies/domains, or a small result
limit). Do not create until they confirm or narrow; continue with the broad query only if
they insist. Skip when the ask is already clearly bounded. After they insist, still apply
Warn before near-exhaustion below when relevant.
Start a search
clay searches query-mode reference | jq -r '.reference' > ./clay-search-reference.md
clay searches query-mode create --query '<query>'
create returns { "searchId": "search_..." }.
Paging
run returns { "data": [ ... ], "hasMore": <boolean>, "periodQuota"?: { "limit", "used", "remaining", "resetsAt" } }. --limit is the page size. periodQuota appears on
successful run responses only — not on create; do not invent values.
Reuse the same searchId; each call returns the next page. Continue while hasMore is
true, but after every run that returns periodQuota, apply Warn before
near-exhaustion below before the next page. Stop when hasMore is false, or when the
quota is near exhaustion — unless the user explicitly asks to continue.
clay searches query-mode run <searchId> [--limit <n>]
Warn before near-exhaustion
Keep routine quota checks internal under the shared cost policy in workflows-discover-actions/cost-and-budget.md. Do not
announce a quota or seek approval merely because a search consumes results. The verified
near-exhaustion condition below is an exception.
When periodQuota is present, before a create or run that will consume N results (the
volume you plan to pull, not the full match set), check remaining − N. If that would
leave under 15% of limit, stop and ask first:
This search will return {{N}} results and leave {{remaining − N}} of your period quota.
Continue only if they confirm. Otherwise offer a smaller pull that keeps at least 15%
remaining, or stop. Skip when periodQuota is absent.
Example: limit 10,000, remaining 2,000, N 1,500 → 500 left (5% of cap) → warn.
Quotas
If a create or run fails with quota_exceeded (exit 1, HTTP 402), the workspace has hit a
plan result cap (per-request, per-search, or period) or a credit/usage limit. Short backoff
will not help. Read the error message and choose one of:
- Per-request size — message names a "per request" limit. This is the only exception:
reissue once with
--limit≤ that cap (e.g. free plans often allow 50 per request). - Per-search, period, or credits — anything else. Stop spending allowance: no further
runat any--limit(including 1), and no newcreateto work around a per-search cap. The report is the finished deliverable. Give the short cap account from the error (upgrade, named period reset, or contact support). Always include the plan selector — resolve<workspaceId>withclay whoami | jq -r '.workspace.id'when the error has no URL:https://app.clay.com/workspaces/<workspaceId>/billing/plan-selector(bare URL; prefer a plan-selector URL from the error when present). If the error includes an upgrade URL or upgrade copy, make that selector extremely prominent: near the top of the reply and again as the last line (Upgrade your plan now at: <url>). If the error says to contact support, lead with that path and still add one plan-selector line so they can self-serve if they prefer. Also share the public search docs for follow-up questions:https://developers.clay.com/searches#result-limits. If the user asks to upgrade their plan, open the plan selector link for them. Pull a remainder only if they ask for it in a later message after that report; the original request for N results is not that ask.
validation_error (exit 2) means malformed input (bad flags/filters/query), not a quota.
server_error (exit 1) on query-mode create/run can be a transient upstream fault (on run,
e.g. the semantic-query embedding service timed out). On create, retry once after a short
wait. On run, retry once only when no data came back — a retry re-serves the current page
and can charge and count it again if the failure happened after billing.
rate_limited (exit 4) is a short HTTP 429 backoff and may be retried after details.retryAfter.
Next: enrich or persist the results
Search only finds records. After paging results, offer one of two plugin paths — both via
clay routines runs start. See the routines skill for sizing runs and fetching results.
Enrich without persisting
Prefer Clay-managed routines for standard enrichment. Before reaching for the raw
action catalog or building a workflow, list the full, paginated routines set and check
source: managed first. Clay ships managed routines that cover most enrichment — e.g.
Work Email, Company Domain, Enrich Person, Enrich Person and Find Contact
Details, Company Job Openings. Match on each routine's input schema
(clay routines get <id>), not its name. Only fall through to the action catalog or a new
workflow when no managed or custom routine fits.
clay routines list
clay routines get function:t_abc123
After Search has results, use the routines skill to start the run: list or get
the routine schema, then clay routines runs start.
Persist into Audiences
When the user wants Search hits kept in the workspace, find or create a routine whose
underlying workflow upserts with upsert-audiences-record. If none exists, build the workflow
using the workflows skill's audiences.md, then to run in bulk see the routines skill.