Watching Companies for Matching New Hires with the Clay CLI
Watching Companies for Matching New Hires with the Clay CLI
Create a signal that fires when a tracked company hires someone matching real seniority and title filters, using Clay's real signals create --type NewHire, scoped to a companies audience segment.
What you will build
A Paused NewHire signal watching a companies audience, narrowed by a real peopleSearch filter (title keywords + seniority levels).
clay signals create --type NewHire --input '{"entityType":"ACCOUNT","segmentIds":[...],"filters":{...}}'
↓
{ id (td_...), runStatus: "Paused", signal: { inputs: { filters: <normalized peopleSearch> } } }
AI Prompt
Using the Clay CLI, create a signal watching a companies audience for new
hires matching specific criteria.
Requirements:
- `clay signals create --type NewHire --input '{"entityType":"ACCOUNT",
"segmentIds":["<audience-id>",...],"filters":{...}}' [--name <name>]`.
- entityType for an audiences-based NewHire signal must be ACCOUNT
("companies" in audiences terms).
- "filters" is a full peopleSearch object. Every key is optional EXCEPT
"start_from_method", which should be "query" -- that's what the real app
sends; a filters document that leaves it out is defaulted to
"CsvOfCompanies" instead, which is very likely not the intended scope.
- Useful real keys: job_title_keywords (array), job_title_seniority_levels_v2
(array of: founder, owner, board-member, partner, c-suite, vp, director,
head, manager, senior, mid-level, entry, intern, unknown),
company_sizes, company_annual_revenues, locations.
- The keys that would name WHICH companies to search (company_identifier,
company_table_id, etc.) are NOT part of this object -- a signal takes its
companies from what it watches (the audience segment or table), not from
a key inside "filters".
- Omitting "filters" entirely means every new hire at the watched companies
counts, with no title/seniority narrowing.
- The response echoes back a NORMALIZED filters object with every optional
key present (as an empty array/string when unset) -- not just the keys
you passed.
- Run the verification step below before finishing.
Prerequisites
- The
clayCLI on PATH, authenticated viaclay login(an OAuth session, not a Public API key) - An existing companies audience segment
Note: JSON samples below are trimmed to the fields relevant to each step. Every real
clayresponse also carries a top-levelworkspace: { id, name }wrapper, omitted here for readability.
1. Create the signal with a real peopleSearch filter
clay signals create --type NewHire --input '{
"entityType": "ACCOUNT",
"segmentIds": ["audseg_0tl84p1ZQ8RRShHSAdX"],
"filters": {
"start_from_method": "query",
"job_title_keywords": ["Sales Engineer"],
"job_title_seniority_levels_v2": ["senior", "mid-level"]
}
}' --name "TPC Docs: New sales hires at targets"
Real output, note the response normalizes the filter object, filling every unset optional key rather than echoing back only what was sent:
{
"id": "td_0tl867o9YZgptA7FcEs",
"runStatus": "Paused",
"signal": {
"type": "NewHire",
"inputs": {
"filters": {
"start_from_method": "query",
"job_title_keywords": ["Sales Engineer"],
"job_title_seniority_levels_v2": ["senior", "mid-level"],
"job_title_mode": "smart",
"job_functions": [],
"locations": [],
"company_sizes": [],
"company_annual_revenues": []
},
"entityType": "ACCOUNT",
"segmentIds": ["audseg_0tl84p1ZQ8RRShHSAdX"]
}
}
}
2. Confirm the filter took by re-reading it
clay signals get td_0tl867o9YZgptA7FcEs | jq '.signal.inputs.filters'
Verify the result
Confirm the behavior above holds by re-running the key command and checking the result:
clay signals create --type NewHire --input '{"entityType":"ACCOUNT","segmentIds":["audseg_0tl84p1ZQ8RRShHSAdX"],"filters":{"start_from_method":"query","job_title_keywords":["Sales Engineer"]}}'
Expected: A real Paused NewHire signal is created scoped to the companies audience, with the peopleSearch filter normalized and echoed back with every optional key present.
How it works
filters is a "narrow what the signal looks for," while the signal's top-level --filter (a different flag, on signals create/update) decides "which detected events actually fire"; the two exist independently: you can have a broad filters scope with a strict top-level --filter, or vice versa. start_from_method defaulting to "CsvOfCompanies" when omitted (rather than the intended "query") is a real, easy-to-hit gotcha, since it's the one key in the whole object without a sensible default.
Common issues
Signal silently scoped to the wrong company source
Cause: omitting start_from_method from filters, assuming it defaults to searching the watched companies.
Fix: it defaults to "CsvOfCompanies" instead of "query" when left out: always set it explicitly to "query" to match what the real app sends.
Trying to name which companies to watch inside filters
Cause: assuming filters is a general-purpose search object that also picks the companies.
Fix: a NewHire signal's companies always come from what it watches (segmentIds/table view): keys like company_identifier are not accepted inside filters for this purpose.
Next steps
- Use
clay signals search-topicsfor the topic-intent signal types, which take a different targeting mechanism entirely (provider topic ids, not a peopleSearch object). - Pause the signal with
clay signals pauseonce it's no longer worth its credit spend, rather than deleting it.
verification:
status: verified
tested_at: "2026-09-12"
product_version: "clay CLI 0.19.0"
command: "clay signals create --type NewHire --input '{\"entityType\":\"ACCOUNT\",\"segmentIds\":[\"audseg_0tl84p1ZQ8RRShHSAdX\"],\"filters\":{\"start_from_method\":\"query\",\"job_title_keywords\":[\"Sales Engineer\"]}}'"
expected_result: "A real Paused NewHire signal is created scoped to the companies audience, with the peopleSearch filter normalized and echoed back with every optional key present."