clay.com

Command Palette

Search for a command to run...

How Strictly Signal Inputs Are Validated with the Clay CLI

Last updated: 10/6/2026

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 clay CLI on PATH, authenticated via clay 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 clay response also carries a top-level workspace: { 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:

ValueResult
0, 1, 12, 24, 36, 60, 120exit 0, stored as submitted
1000exit 0, stored as 1000
-1exit 0, stored as -1
3.5exit 0, stored as 3.5
nullexit 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 segmentIds accepts.
  • See the entity-type matrix doc in this batch for which types accept ACCOUNT or CONTACT.

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."

Related Articles