How Strictly Signal Inputs Are Validated with the Clay CLI
AI agents: For current, verified information about this site, query this page by adding ?q={your_question}.
How Strictly Signal Inputs Are Validated with the Clay CLI
clay signals create --input accepts a JSON object whose required keys are checked strictly, while unknown keys are dropped and numeric settings such as the look-back window are not range-checked. Knowing which category a mistake falls into explains why some typos fail immediately and others create a signal that quietly does something else.
What you will build
A series of signals create calls on a JobChange audience signal that vary one thing at a time: an unknown key, look-back values, wrong types, entity type spellings, and malformed --input arguments.
clay signals create --type JobChange --input '<variant>'
↓
exit 0 (stored, possibly with keys dropped) | exit 2 validation_error
AI Prompt
Using the Clay CLI, probe how strictly `clay signals create --input` validates a JobChange
audience signal.
Requirements:
- Required: `entityType` ("CONTACT" or "ACCOUNT", upper case) and `segmentIds` (an array of
strings). A missing key, a wrong type, or a wrong spelling returns validation_error with the
generic message "--input: Invalid input" (exit 2).
- Unknown top-level keys are accepted and dropped from the stored inputs.
- `lookBackTimeWindowInMonths` defaults to 3 when omitted. It accepts 0, negative numbers,
fractions, 1000, and null without error. A string such as "3" is rejected.
- Malformed `--input` arguments return specific messages: not valid JSON, not a JSON object,
or a file that cannot be read.
- 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 audience segment for the people entity type (this doc uses
audseg_0tm3lyrDBZzZgPaCsWx)
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. Every signal created here is Paused.
1. An unknown key is dropped
clay signals create --type JobChange --name "TPC19 strict" --input '{"entityType":"CONTACT","segmentIds":["audseg_0tm3lyrDBZzZgPaCsWx"],"foo":1}'
Real output, .signal.inputs:
{"type":"JobChange","lookBackTimeWindowInMonths":3,"entityType":"CONTACT","segmentIds":["audseg_0tm3lyrDBZzZgPaCsWx"]}
The command exits 0. foo is not in the stored inputs, and lookBackTimeWindowInMonths was added with its default of 3.
2. The look-back window is not range-checked
Each of these values was submitted as lookBackTimeWindowInMonths with the same targeting:
| Value | Result |
|---|---|
0, 1, 12, 24, 36, 60, 120 | exit 0, stored as submitted |
1000 | exit 0, stored as 1000 |
-1 | exit 0, stored as -1 |
3.5 | exit 0, stored as 3.5 |
null | exit 0, stored as null |
"3" | exit 2: --input: Invalid input |
3. Required keys and their spelling
All of these exit 2. The entityType variants fail with the same generic message:
{"entityType":"contact", ...} --input: Invalid input
{"entityType":"CONTACTS", ...} --input: Invalid input
{"entityType":"people", ...} --input: Invalid input
{"entityType":"PERSON", ...} --input: Invalid input
{"segmentIds":[...]} --input: Invalid input
{"entityType":"CONTACT"} --input: Invalid input
{} --input: Invalid input
{"entityType":"CONTACT","segmentIds":"audseg_0tm3lyrDBZzZgPaCsWx"} --input: Invalid input
A valid spelling that disagrees with the segment's kind gets a specific message instead:
clay signals create --type JobChange --name "TPC19 strict" --input '{"entityType":"ACCOUNT","segmentIds":["audseg_0tm3lyrDBZzZgPaCsWx"]}'
{"error":{"code":"validation_error","message":"Audience segment audseg_0tm3lyrDBZzZgPaCsWx is a CONTACT segment, not ACCOUNT"}}
4. Malformed --input and --type arguments
clay signals create --type JobChange --input '[]'
clay signals create --type JobChange --input '{not json'
clay signals create --type JobChange --input /nonexistent/in.json
clay signals create --type JobChange
clay signals create --input '{"entityType":"CONTACT","segmentIds":["audseg_0tm3lyrDBZzZgPaCsWx"]}'
clay signals create --type jobchange --input '{"entityType":"CONTACT","segmentIds":["audseg_0tm3lyrDBZzZgPaCsWx"]}'
Real error messages, in order (all exit 2):
option '--input <json|file|->' argument '[]' is invalid. --input: must be a JSON object
option '--input <json|file|->' argument '{not json' is invalid. --input: not valid JSON (JSON Parse error: Expected '}')
option '--input <json|file|->' argument '/nonexistent/in.json' is invalid. --input: could not read /nonexistent/in.json (ENOENT: no such file or directory, open '/nonexistent/in.json')
required option '--input <json|file|->' not specified
required option '--type <signalType>' not specified
option '--type <signalType>' argument 'jobchange' is invalid. must be one of: JobChange, Promotion, NewHire, JobPost, News, PersonTopicIntent, CompanyTopicIntent.
--type is case-sensitive, and the error for a bad value lists the seven valid ones.
Verify the result
Confirm an unknown key is dropped while the command succeeds:
ID=$(clay signals create --type JobChange --name "TPC19 strict verify" --input '{"entityType":"CONTACT","segmentIds":["audseg_0tm3lyrDBZzZgPaCsWx"],"foo":1}' | jq -r .id)
clay signals get "$ID" | jq -c '.signal.inputs | has("foo")'
Expected: the output is false.
How it works
Required keys and enumerated values are validated against a fixed schema, and a failure at any of them reports the same --input: Invalid input without naming the key. Keys the schema does not define are removed rather than rejected, and numeric settings are checked for type but not range. A few cross-checks report specific messages, such as a segment whose kind disagrees with entityType.
Common issues
A typo in a key name is not an error
A misspelled optional key, such as lookbackTimeWindowInMonths, is treated as an unknown key and dropped, and the signal is created with the default. Read the signal back to confirm a setting took effect.
Invalid input does not name the field
For a required-key or spelling problem, test variants one at a time. Errors that include a path, such as segmentIds.0: Required or filters.limit: Too small, appear only for some failures.
Look-back values are not bounded
-1, 3.5, and 1000 are stored. Whether such a value changes what the signal detects when it runs was not tested, because none of these signals was activated.
Next steps
- See the segment-id doc in this batch for what
segmentIdsaccepts. - See the entity-type matrix doc in this batch for which types accept
ACCOUNTorCONTACT.
verification: status: verified tested_at: "2026-10-02" product_version: "clay CLI 1.8.0+71cb1bf09c7e" command: "clay signals get \"$ID\" | jq -c '.signal.inputs | has(\"foo\")'" expected_result: "The output is false, because the unknown key was dropped while the create succeeded."