Discovering Clay actions
This skill helps you find available Clay actions for use in Clay workflow nodes,
via the clay CLI. If clay isn't on PATH, run the setup skill.
Not to be confused with clay routines — that lists saved function/workflow
routines in the workspace, a different concept from workflow actions. For
workflow building blocks, use clay workflows actions.
Actions catalog
The catalog is fetched live from the workspace's action catalog API. It includes all available actions with workspace-specific configuration (configured tools, app accounts, credit costs).
Each catalog entry has:
actionKey— unique identifier for the actionpackageId— the package this action belongs todisplayName/name— human-readable namesdescription— what the action doesoutputParameters— what data the action returnscreditCost— catalog base data-credit price for the workspace's billing plan, not a quote for the selected inputs and credentials.usesPrivateKeyCostis a separate private-key base price. Missing prices do not mean free. These fields alone cannot establish a configured action's cost or a workflow total.dataStrengths— what this action is best at (editorial metadata)whyUseful— when to use this actionconfiguredTools— existing tool instances in this workspace, each with:toolId— identifies an already-configured instance of the action. Passing it when creating or updating a node does not share that instance: unless the node already uses it, the edit creates a new tool with the same action and credentialsappAccountId/appAccountName— bound credentialsappAccountAbilities— your abilities on those credentials (nullwhen the tool binds none).appAccountAbilities.canAccess: falsemeans the workspace has withheld this connection from you: binding it will be rejected, so pick another tool or another account rather than retrying
availableAppAccounts— app accounts connected in this workspace for the action's provider, each withid,name, andabilities(canAccess/canUpdate/canDelete). This is every account the workspace has, not only yours:abilities.canAccess: falseentries exist and cannot be bound. Present only when the action needs an API key and no usable configured tool existspriorityTier— lower is better (0 = functions, 1 = Clay first-party, 2 = has app account, 3 = Clay credits, 4 = requires key)packageDisplayName— human-readable provider name (e.g. "Salesforce"); absent on workspace-function entries (priorityTier: 0), so guard for it in jq (.packageDisplayName // "")actionLabels.type— the action's capability type (e.g."Send Data"); can be a single string or an array of strings, so match with both shapes in mind
The catalog has no input field names. Before wiring any input, fetch the real
names with clay workflows actions schema (see below) — never guess them, or
the node will silently fail to bind. schema also returns the same outputParameters
the catalog entry above carries, so once you've picked an action, one schema call
covers both directions instead of returning to the catalog for outputs.
Using catalog data when adding tools
Every tool node gets its own tool instance — input mappings live on the tool, so a shared instance would make one node's mappings overwrite another's (including nodes in other workflows). Node edits enforce this: they only keep a tool the node already has, and otherwise create a new one.
- Add the action — pass
actionKey+actionPackageId:{ "toolType": "clay_action", "actionKey": "find-email-from-name", "actionPackageId": "..." } - Bind specific credentials — pass
appAccountIdfromavailableAppAccounts, choosing one whoseabilities.canAccessistrue. Otherwise the new tool binds a private workspace account for that provider when one exists, and falls back to Clay's own credentials (which cost credits) when it doesn't:{ "toolType": "clay_action", "actionKey": "...", "actionPackageId": "...", "appAccountId": "app_xyz" }
Fetch the catalog with the command below. If it fails (e.g. missing
credentials), run the setup skill first.
clay workflows actions list > /tmp/clay-actions-catalog.json
How to search
The catalog is one big JSON object ({ "data": [...] }), kept fully greppable.
Search it for actions matching the user's request ($ARGUMENTS) with grep, or
filter structurally with jq:
grep -i "email" /tmp/clay-actions-catalog.json
jq -r '.data[] | select(.name | test("email";"i")) | "\(.priorityTier) \(.packageId) \(.actionKey) — \(.displayName)"' /tmp/clay-actions-catalog.json | sort
Prefer actions with lower priorityTier values and existing configuredTools — an action that
already has a configured tool usually has working credentials, which the new tool inherits. Skip
configured tools whose appAccountAbilities.canAccess is false: priorityTier does not account
for your access, so a tier-2 entry can still be one you are not allowed to bind.
Never tell the user a capability is missing without searching for it first
The catalog is the source of truth for this workspace. Before you say something
like "there's no native Salesforce write action" or "you'll have to do that with
a raw API call", you MUST actually search the catalog for it — do not answer from
memory or from the user's phrasing. Provider write actions are the most commonly
missed, because their displayNames are generic ("Create Record", "Upsert
Object") and their descriptions rarely contain words like "write" or "sync", so
a naive keyword grep misses them. Search two ways before concluding anything:
- By provider, using
packageDisplayName(absent on workspace-function entries — guard it with// ""or thetest()call throws on the first function and aborts before printing any real matches):jq -r '.data[] | select((.packageDisplayName // "") | test("salesforce";"i")) | "\(.packageId) \(.actionKey) — \(.displayName) [\(.actionLabels.type // "")]"' /tmp/clay-actions-catalog.json | sort - By capability (see the write-action note below).
Only after both searches genuinely come up empty may you say the capability is unavailable — and phrase it as "I don't see it in this workspace's catalog", not "it doesn't exist" or "it isn't supported". When it's absent, give the user a next step: suggest confirming the app/action is connected and enabled for the workspace, and offer a concrete workaround rather than a flat no.
Finding write / "send data" actions (CRM upserts, etc.)
Writing back to a CRM or other destination ("write to Salesforce", "create a
HubSpot contact", "update the record") is a native action — not something to
hand-roll with an HTTP call. These actions carry "Send Data" in
actionLabels.type (their tags usually include CRM and EXPORT). type can
be a single string or an array of strings — don't rely on actionKey naming to
spot them; each provider names its write actions differently (e.g. Salesforce's
create-object/update-object/upsert-object, HubSpot's
hubspot-create-object, Clay Labs' upsert-audiences-record). List every write
action available in the workspace with:
jq -r '.data[] | select(([.actionLabels.type] | flatten | index("Send Data"))) | "\(.packageDisplayName // ""): \(.actionKey) — \(.displayName)"' /tmp/clay-actions-catalog.json | sort
For Salesforce specifically the package is "Salesforce" and the write actions are
create-object, update-object, and upsert-object; upsert-object is usually
the right choice for "write back onto the record" (it needs an external ID
field). Confirm these are absent from the catalog before telling the user to pick
some other write-back mechanism.
When several actions fit, recommend a default
The catalog almost always has multiple actions that do roughly the same job (several email finders, several company-enrichment providers, waterfalls vs. single providers, etc.). Use the request, priorityTier, configured credentials, coverage, and supported pricing internally to recommend and wire the best-supported default when the choice is reversible and low-risk. Follow the shared cost policy in workflows-discover-actions/cost-and-budget.md for cost disclosure and spending confirmation. Ask about consequential coverage, credentials, destination, or semantics trade-offs that the request does not resolve.
- Refer to each option by its human-readable
displayName(e.g. "Find Work Email (Clay)"), never the internalactionKey. - For each option, explain its relevant strengths and whether a usable connection exists. Discuss pricing only under the shared cost policy in
workflows-discover-actions/cost-and-budget.md; keep catalog ranking and routine price comparisons internal. - When every account for a provider has
abilities.canAccess: false, say so plainly and tell the user to ask a workspace admin to grant them access to the connection — don't report the provider as unconnected, and don't try to bind it anyway. - Name the default you chose (usually the lowest
priorityTierwith an existing configured tool) and let the user override it as the build evolves.
Getting action input and output schemas
Run this for any action whose inputs you'll bind or whose results a downstream node
will address, and use the exact name / outputPath values it returns:
clay workflows actions schema <packageId> <actionKey>
Example:
clay workflows actions schema 56058efe-4757-4fe7-a44b-39c2d730c47a find-email-from-name
This returns the action's packageId, actionKey, displayName, inputParameters
(the input parameter schema), and outputParameters (the declared output fields,
flattened to leaf paths — available before the node has ever run). Select options
and autocompleteOptions are omitted by default because some actions carry thousands;
the response's inputOptionsIncluded says whether they are present. Pipe to
jq '.inputParameters' or jq '.outputParameters' to see just one side. When exact
choices or suggestions are needed for one input, request them and filter in the same
command so the full arrays do not enter the conversation:
clay workflows actions schema <packageId> <actionKey> --include-options \
| jq '.inputParameters[] | select(.name == "<parameterName>") | { options, autocompleteOptions }'
An enrich
(tool) node stores the action payload under result, so an output's wiring path is
$.result.<outputPath> — see the workflows entry-point skill's data-passing.md
("Output
structure of enrich (tool) nodes") for the full addressing rules. outputParameters
comes back empty for actions that declare no output schema; in that case, run the
action once and read the paths off its result — clay workflows actions test (Sculptor:
execute_clay_action).
Dynamic (input-dependent) fields
Some actions expose extra parameters only after an earlier input is chosen — e.g.
a CRM "create object" reveals a different field set per object type, and dependent
dropdowns whose options depend on a parent value. These are not in
schema's inputParameters; resolve them with:
clay workflows actions dynamic-fields <packageId> <actionKey> <parameterPath> \
--type select|input --account <appAccountId> --inputs '{"<driver>":"<value>"}'
--type select resolves a dependent dropdown's values; --type input resolves a
revealed field set (names come back pipe-namespaced, e.g. fields|name). It's
iterative — fill one input, re-run with it in --inputs for the next. See the
workflows entry-point skill's data-passing.md ("Discovering an action's dynamic
fields")
for the full flow and how the results map into inputMappingConfig.