---
name: parent-subsidiary-signal-routing
description: "Route intent and website signals across parent and subsidiary accounts: hierarchy lookup, a written tie-break order, a RevOps conflict queue, and Slack. Use when an intent or website signal arrives on a domain that matches the parent company, while the CRM account, the open opportunity, and the owner sit on a subsidiary record, so an agent that merges by domain alerts the parent owner, two reps, or nobody, and two reps end up working the same buying group."
---

# Route Parent Company Signals to the Right Subsidiary Owner

An intent or website signal arrives on a domain that matches the parent company, while the CRM account, the open opportunity, and the owner sit on a subsidiary record, so an agent that merges by domain alerts the parent owner, two reps, or nobody, and two reps end up working the same buying group.

## When to use this skill

- The user wants to set up or run this workflow: "Route Parent Company Signals to the Right Subsidiary Owner".
- The user describes this problem: An intent or website signal arrives on a domain that matches the parent company, while the CRM account, the open opportunity, and the owner sit on a subsidiary record, so an agent that merges by domain alerts the parent owner, two reps, or nobody, and two reps end up working the same buying group.

## At a glance

- Category: RevOps
- Difficulty: Advanced
- Time saved: 3 hours per week. This figure is an estimate, not a measured result.

## Tools

Options separated by "or" are alternatives; use whichever the user already has.

- RB2B, Vector, G2 Buyer Intent, or Bombora
- Clay
- HubSpot or Salesforce
- Google Sheets
- Slack

## Steps

1. Normalize every signal before any lookup: lowercase the domain, strip www and paths, keep the raw payload (source, domain, topic or page, country, visitor email if known, timestamp) unchanged, and drop repeats of the same signal id; send one JSON object per signal to a Clay webhook from the signal tool or a Zapier or Make relay
2. Find every CRM account that matches, not the first one: search Salesforce Account Website (or your own domain field) or the HubSpot company domain and additional domains, plus an alias_domains tab in Google Sheets for acquired brands and regional domains
3. Read the account family around each match: walk Salesforce Parent Account (ParentId) up to the top and read the direct children, or read the HubSpot parent and child company associations, carrying owner, owner active flag, territory, segment, customer flag, open opportunity count and amount, and last activity date for every account
4. Pick the owner with a written tie-break order that sales leadership signs off on: start with every account in the family as a candidate, apply each rule in turn, stop when one candidate is left, skip a rule that matches nobody, and pass ties to the next rule; the order is (1) an unexpired named override, (2) the subsidiary the visitor email domain or an alias points to, (3) the account with an open opportunity, (4) the account whose territory covers the signal country, (5) the parent owner, only where your policy says the parent owner covers the family
5. Send everything else to a RevOps conflict queue instead of a rep: more than one candidate after the last rule, a chosen owner who is inactive, or a domain that matches accounts in two separate families; each queue row carries the signal, the candidates and their owners, the rule where the tie stayed, and a resolution deadline (1 business day here, an assumption), and RevOps fills the resolved owner, who resolved it, and when
6. Let the agent combine signals only after an owner is chosen: attach the signal to the chosen account as a note, task, or signal field, roll it up to the family for reporting, and never change an account owner from this workflow; owner changes go through your normal territory process
7. Alert the chosen owner in Slack with the decision and the reason: the signal, the account it was routed to and its parent, the rule that fired, the other owners in the family so they know who is working it, and a link to the log row; post conflicts to a RevOps channel with the candidates, and alert no rep until the conflict is resolved
8. Review the log weekly: signals by rule fired, conflicts and time to resolve, and the most common conflict causes (missing ParentId, the same domain on two accounts, expired overrides); fix the hierarchy data at the source, and after any rule change, re-run last week's signals and compare owners before publishing

## Cost, time saved, and break-even

Clay's plan prices and the plan features this workflow needs are listed below as checked on 2026-10-21. Signal volume and lookup counts depend on your tools and data, so every input is an assumption; replace each with your own figure.

### Listed prices

- Clay plans with webhook automation and CRM integrations: Growth and above
- Clay Growth, billed monthly: 6,000 data credits and 40,000 actions: $495/mo
- Clay Growth, billed annually, shown per month: $446/mo
- Each enrichment or AI prompt that returns a result, and each CRM record written: 1 action
- Webhook imports into Clay: 0 actions

### Inputs (every value is an assumption; replace it with your own figure)

- T = 150 (assumption): Signals per week that enter the workflow. Count last month's signals from your visitor and intent tools that match a CRM domain, and divide by 4.33.
- S = 48 (assumption): Signals per week that land on an account family (a parent or child match). Run last month's signals through step 3 and count the ones whose family has more than one account.
- M = 5 (assumption): Minutes to look up the hierarchy and pick an owner by hand. Time ten family signals in the current manual process.
- Q = 25% (assumption): Share of family signals that still go to the RevOps conflict queue. Run the rule on last month's signals and count conflicts.
- X = 6 (assumption): Clay actions per signal. An assumption: domain search, family lookup, sheet lookup, Slack post, and log row, plus one more for a second family read. Read the real count from one test run.
- R = $60 (assumption): Loaded hourly cost of the RevOps analyst who routes signals today. Salary plus benefits, divided by working hours.

### Formulas

- Time saved per week: S x M x (1 - Q) / 60 = 48 x 5 x 0.75 / 60 = 3 hours, the time-saved estimate on this page
- RevOps review time left per week: S x Q x M / 60 = 48 x 0.25 x 5 / 60 = 1 hour for the conflict queue
- Clay actions per month: T x X x 4.33 = 150 x 6 x 4.33 = 3,897 actions, inside Growth's 40,000
- Value of time saved per week: S x M x (1 - Q) / 60 x R = 3 x $60 = $180.00
- Break-even hours per month on Growth bought only for this: plan price / R = $495 / $60 = 8.25 hours a month, against 3 x 4.33 = 12.99 hours saved

### Notes

- As built here, with a Clay webhook trigger and HubSpot or Salesforce lookups, the workflow needs Clay Growth or above. If Clay already runs on Growth for other work, the added cost is the actions above, not the plan price.
- The workflow uses no data credits when the signal already carries a domain. Adding enrichment to find a missing domain or country adds data credits per signal.
- The math counts routing time only. Two reps working the same buying group, or a signal nobody follows up, can cost more than the time, but measure duplicate outreach and time to first touch before and after instead of assuming a number.
- The rule is only as good as the hierarchy. Count conflicts caused by a missing Parent Account or a duplicate domain in the weekly review; those are data fixes, not rule changes.

## Calculator

To estimate cost with the user's own numbers, point them to the Clay credit calculator: https://gtmplaybooks.io/calculators/clay-credits/. Each signal uses Clay actions for the domain search, the family lookup, the sheet lookup, the Slack post, and the log row. Check your monthly signal volume against your plan's actions.

## Template outline

Field names, thresholds, and message text are starting points to adapt.

~~~text
Google Sheet: Signal routing (RevOps owns it; sales leadership signs off on overrides and territories)

Tab alias_domains: domain, account_id, note (acquired brand, regional domain)
Tab named_overrides: account_id, owner_email, reason, approved_by, expires_on
Tab territories: region, countries, segment, owner_email, active
Tab routing_log: signal_id, received_at, source, domain, topic, country, person_email,
  family_ids, candidates, status (routed, conflict, unmatched), chosen_account, owner_email,
  rule_fired, reason, resolved_owner, resolved_by, resolved_at
Conflict queue = routing_log filtered to status = conflict and resolved_at blank

Clay workflow (webhook trigger, one run per signal):
1. Find accounts by domain: domain + alias_domains; return every match
2. Read the account family: ParentId up to the top (Salesforce) or parent company
   association (HubSpot), plus direct children; owner, active, territory, segment,
   customer, open_opps, open_amount, last_activity
3. Read overrides and territories: named_overrides for family ids; territories for country
4. Pick the owner by rule (formula or code step):
   candidates = every account in the family
   for rule in [override, specific_match, open_opportunity, territory, parent_policy]:
     matched = candidates that pass the rule
     if matched has 1 account: choose it, stop
     if matched has 2 or more: candidates = matched
     if matched is empty: keep candidates, go to the next rule
   still 2 or more candidates            -> conflict
   chosen owner inactive or blank        -> conflict
   no CRM match at all                   -> unmatched, hand to new-account routing
5. Slack: routed -> DM the owner; conflict -> #revops-routing; unmatched -> no post
6. Log every decision to routing_log

Worked example (fictional family, test these four rows before real traffic):
  Example Holdings (example.com), owner Jordan, no open opportunity
    Example Logistics GmbH, territory EMEA (DE), owner Priya, open opportunity $80,000
    Example Retail Inc (alias example-retail.com), territory NA (US), owner Marcus, customer
  Parent policy: subsidiary owners own their accounts (rule 5 off)

  Signal                                   Rule that decided         Result
  A Bombora, example.com, DE               3 open opportunity        Priya (Example Logistics GmbH)
  B RB2B, jo@example-retail.com, US        2 alias match             Marcus (Example Retail Inc)
  C G2, example.com, US, after Retail      3 leaves 2 candidates,    Marcus (Example Retail Inc)
    also opens an opportunity                4 territory US
  D G2, example.com, no country, both      3 leaves 2, 4 skipped,    Conflict: Priya or Marcus,
    have open opportunities                  5 off                     RevOps queue, no rep alert

Slack DM to the chosen owner:
"Signal: {{source}} on {{domain}} ({{topic}}, {{country}}). Routed to you as owner of
 {{chosen_account}}, part of {{parent_account}}. Rule: {{rule_fired}}. Why: {{reason}}.
 Others in this family: {{other_owners}}. Log: {{log_row_url}}"

Slack to #revops-routing for a conflict:
"Conflict: {{source}} on {{domain}}. Candidates: {{candidates_with_owners}}.
 Tie stayed after rule {{rule_fired}}. Resolve by {{resolve_by}}: {{log_row_url}}"
~~~

## Optional: build it with the Clay CLI

This builds signal routing as a Clay workflow with a webhook trigger. Each signal becomes one run: find every CRM account that matches the domain, read the parent and child accounts around it, read your override and territory tables, pick exactly one owner or a conflict with a written rule, then post the decision to Slack and log it. Nothing here changes an account owner in the CRM. The Clay CLI cannot create tables, so this build uses a workflow.

Written against Clay CLI v1.3.1. Run these commands only in the user's own Clay workspace, logged in with their own account, after they confirm. Items marked VERIFY are config shapes the CLI help does not document; check them in the workspace before relying on them.

### Prerequisites

- Install the Clay CLI: Use version 1.3.1 or later, installed from Clay's own instructions. This page does not include an install command because the CLI reference it was written from does not list one. You also need jq, which the script uses to read the JSON the CLI prints.
- Log in to your workspace: Browser login is the default. Use the device flow on a headless machine. A static key in the CLAY_API_KEY environment variable also works. Workflow commands need the terracotta:cli scope, so an auth error that names it means your login cannot manage workflows.
  - Log in with a browser: `clay login`
  - Log in on a headless machine: `clay login --device`
  - Confirm who you are logged in as: `clay whoami`
- Pick the workspace to build in: The workflow is created in your active workspace. Switch first if you belong to more than one.
  - List workspaces: `clay workspaces list`
  - Show the active workspace: `clay workspaces current`
  - Switch workspace: `clay workspaces switch <workspaceId>`
- Find your action keys: Action package ids and keys are specific to your workspace. Save the catalog, search it for your CRM search and lookup actions, the Google Sheets "Lookup rows" and "Add row" actions, and Slack, then paste their ids into the top of the script. Skip "clay workflows actions test": it spends credits.
  - Save the action catalog: `clay workflows actions list > catalog.json`
  - Search the catalog: `grep -Eio '"[^"]*(hubspot|salesforce|search|lookup|google sheets|lookup rows|add row|slack)[^"]*"' catalog.json | sort -u`
  - See an action's inputs and outputs: `clay workflows actions schema <packageId> <actionKey>`
- Connect your CRM, Google Sheets, and Slack: Connect HubSpot or Salesforce, Google Sheets, and Slack inside Clay. The CRM connection only needs read access for this build, because the workflow never writes an owner.
- Set up the routing sheet: Four tabs: alias_domains (domain, account_id), named_overrides (account_id, owner_email, reason, approved_by, expires_on), territories (region, segment, owner_email, active), and routing_log (one row per signal with the decision). Sales leadership signs off on named_overrides and territories; RevOps owns the sheet.
- Decide what sends signals: Your visitor or intent tool, a CRM workflow, or a Zapier or Make relay POSTs one JSON object per signal to the webhook. Send the domain, not a company name, and include country when the tool has it.

### Workflow: Signal ownership routing

Trigger (webhook): Your signal source or a relay POSTs one JSON object per signal to the trigger's webhook URL. The fields arrive as run inputs as-is.

Inputs (webhook payload fields):

- signal_id: Unique id from the source, used to drop duplicates (example: bmb-2026-10-23-0042)
- source: Which tool sent it (example: Bombora)
- domain: Company domain, lowercased, without www (example: example.com)
- topic: Intent topic or page visited (example: warehouse automation)
- country: Country of the visitor or the surge, may be blank (example: DE)
- person_email: Identified visitor email, may be blank (example: )
- received_at: When the source saw the signal, ISO 8601 (example: 2026-10-23T09:12:00Z)

1. Find accounts by domain (action): Searches CRM accounts for the domain and for any alias in alias_domains, and returns every match, not only the first. Salesforce: Website or your domain field on Account. HubSpot: the company domain and additional domains.
   - Inputs: domain, person_email
   - Outputs: matched_accounts
2. Read the account family (action): For each match, reads the parent up to the top (Salesforce Parent Account, the ParentId field; HubSpot parent company association) and the direct children, with owner, owner active flag, territory, segment, customer flag, open opportunity count, and last activity date.
   - Inputs: matched_accounts
   - Outputs: family
   - VERIFY: Whether your CRM action in Clay returns ParentId or HubSpot company-to-company associations depends on the integration. If it does not, read them with an HTTP request step to the CRM API using your own credentials.
3. Read overrides and territories (action): Looks up named_overrides rows for any account id in the family, and the territories row for the signal country and the family segment.
   - Inputs: family, country
   - Outputs: override, territory_owner
4. Pick the owner by rule (function): Applies the tie-break order and returns exactly one owner or a conflict: 1 unexpired named override; 2 the one family account with an open opportunity; 3 the customer account the visitor email or alias maps to; 4 the account whose territory matches the signal country; 5 the parent owner, if your rule rolls ownership down to unowned children. Two candidates at the same level, an inactive owner, or no match at all is a conflict. Outputs the chosen account, owner, rule fired, a one-line reason, and the Slack channel and text.
   - Inputs: family, override, territory_owner, country, person_email
   - Outputs: status, chosen_account, owner_email, rule_fired, reason, slack_channel, slack_text
   - VERIFY: The CLI reference does not document formula or code steps, so the script does not create this one. Add it in the Clay UI between step 3 and the Slack step as a formula or code step.
5. Post the routing alert (action): Routed: a direct message to the chosen owner that names the account, its parent, the rule that fired, and the other owners in the family. Conflict: a post to your RevOps routing channel with the candidates and a link to the routing_log row. No rep is alerted for a conflict.
   - Inputs: slack_channel, slack_text
   - Outputs: Slack message
6. Log the decision (action): Adds one routing_log row per signal with every input, the family ids, status, chosen account, owner, rule fired, and reason. Filter status = conflict for the RevOps queue; RevOps fills resolved_owner, resolved_by, and resolved_at.
   - Inputs: signal_id, domain, family, status, chosen_account, owner_email, rule_fired, reason
   - Outputs: Sheet row

### Script: build-signal-ownership-routing.sh

Creates the workflow, the webhook trigger, and the five action steps, then pauses so you can add the owner rule step in the Clay UI and map inputs. It validates the graph, offers one test run, and asks before publishing.

~~~bash
#!/usr/bin/env bash
# Builds the "Signal ownership routing" Clay workflow
# in YOUR Clay workspace, using YOUR Clay CLI login.
# Written against Clay CLI v1.3.1. Not run or tested by GTM Playbooks.
# Lines tagged VERIFY use a shape the CLI help does not document.
set -euo pipefail

# Copy these from catalog.json (see "Find your action keys").
SEARCH_PACKAGE_ID="" # HubSpot or Salesforce: search or find records
SEARCH_ACTION_KEY=""
FAMILY_PACKAGE_ID="" # HubSpot or Salesforce: lookup record (or HTTP request)
FAMILY_ACTION_KEY=""
RULES_PACKAGE_ID=""  # Google Sheets: lookup rows
RULES_ACTION_KEY=""
SLACK_PACKAGE_ID=""  # Slack: send message
SLACK_ACTION_KEY=""
LOG_PACKAGE_ID=""    # Google Sheets: add row
LOG_ACTION_KEY=""

# One input to test before real traffic. Use yourself or a teammate.
TEST_ROW='{"signal_id":"","source":"","domain":"","topic":"","country":"","received_at":""}'

for v in SEARCH_PACKAGE_ID SEARCH_ACTION_KEY FAMILY_PACKAGE_ID FAMILY_ACTION_KEY RULES_PACKAGE_ID RULES_ACTION_KEY SLACK_PACKAGE_ID SLACK_ACTION_KEY LOG_PACKAGE_ID LOG_ACTION_KEY; do
  [[ -n "${!v}" ]] || { echo "Set $v at the top of this script." >&2; exit 1; }
done
command -v clay > /dev/null || { echo "Clay CLI not found on PATH." >&2; exit 1; }
command -v jq > /dev/null || { echo "jq is required to read CLI output." >&2; exit 1; }
clay whoami > /dev/null || { echo "Not logged in. Run: clay login" >&2; exit 1; }

# VERIFY: only "workflows create" documents an "id" field in its output.
read_id() {
  local id
  id=$(jq -r '.id // empty' "$1")
  [[ -n "$id" ]] || { echo "No id found in $1. Open it and adjust read_id." >&2; exit 1; }
  echo "$id"
}

mkdir -p clay-signal-ownership-routing
cd clay-signal-ownership-routing

echo "1/9 Create the workflow"
clay workflows create --name "Signal ownership routing" > workflow.json
WF_ID=$(read_id workflow.json)
WF_URL=$(jq -r '.url // empty' workflow.json)

echo "2/9 Add the webhook trigger"
clay workflows triggers create "$WF_ID" --input '{"triggerType":"webhook","inputSchema":{"type":"object"}}' > trigger.json
TRG_ID=$(read_id trigger.json)

echo "3/9 Step 1: find accounts by domain"
# VERIFY: help shows nodeType and name only; actionPackageId and actionKey are a guess.
STEP1=$(jq -nc --arg p "$SEARCH_PACKAGE_ID" --arg k "$SEARCH_ACTION_KEY" '{nodeType: "tool", name: "Find accounts by domain", actionPackageId: $p, actionKey: $k}')
clay workflows nodes create "$WF_ID" --input "$STEP1" > step1.json
STEP1_ID=$(read_id step1.json)

echo "4/9 Step 2: read the account family"
# VERIFY: action fields inside "step" are inferred from the documented utility example.
STEP2=$(jq -nc --arg n "$STEP1_ID" --arg p "$FAMILY_PACKAGE_ID" --arg k "$FAMILY_ACTION_KEY" '{target: {type: "after-node", nodeId: $n}, step: {kind: "action", actionPackageId: $p, actionKey: $k}}')
clay workflows nodes insert "$WF_ID" --input "$STEP2" > step2.json
STEP2_ID=$(read_id step2.json)

echo "5/9 Step 3: read overrides and territories"
# VERIFY: same inferred insert shape as step 2.
STEP3=$(jq -nc --arg n "$STEP2_ID" --arg p "$RULES_PACKAGE_ID" --arg k "$RULES_ACTION_KEY" '{target: {type: "after-node", nodeId: $n}, step: {kind: "action", actionPackageId: $p, actionKey: $k}}')
clay workflows nodes insert "$WF_ID" --input "$STEP3" > step3.json
STEP3_ID=$(read_id step3.json)

echo "6/9 Step 4: post the routing alert"
# VERIFY: same inferred insert shape as step 2.
STEP4=$(jq -nc --arg n "$STEP3_ID" --arg p "$SLACK_PACKAGE_ID" --arg k "$SLACK_ACTION_KEY" '{target: {type: "after-node", nodeId: $n}, step: {kind: "action", actionPackageId: $p, actionKey: $k}}')
clay workflows nodes insert "$WF_ID" --input "$STEP4" > step4.json
STEP4_ID=$(read_id step4.json)

echo "7/9 Step 5: log the decision"
# VERIFY: same inferred insert shape as step 2.
STEP5=$(jq -nc --arg n "$STEP4_ID" --arg p "$LOG_PACKAGE_ID" --arg k "$LOG_ACTION_KEY" '{target: {type: "after-node", nodeId: $n}, step: {kind: "action", actionPackageId: $p, actionKey: $k}}')
clay workflows nodes insert "$WF_ID" --input "$STEP5" > step5.json
clay workflows graph get "$WF_ID" --mode full > graph.json

echo "8/9 Map step inputs"
cat <<EOF

Step inputs are specific to your workspace. Map them before validating:
  Step 1 search: domain, plus alias_domains matches; return all records
  Step 2 family: ParentId or parent company association, up to the top,
                 and direct children, with owner and open opportunity count
  Step 3 rules:  named_overrides by family account ids; territories by
                 country and segment
  Add in the UI: "Pick the owner by rule" as a formula or code step
                 between step 3 and step 4 (see the tie-break order)
  Step 4 Slack:  slack_channel and slack_text from the rule step
  Step 5 log:    every input plus status, chosen_account, owner_email,
                 rule_fired, reason
Map them in the Clay UI${WF_URL:+ at $WF_URL}, or per node with:
  clay workflows nodes get $WF_ID <nodeId>
  clay workflows nodes update $WF_ID <nodeId> --input node.json
graph.json in this folder shows the current nodes and edges.

EOF
read -r -p "Press Enter when inputs are mapped. "

echo "9/9 Validate, test once, publish"
clay workflows graph validate "$WF_ID"
clay workflows diagram "$WF_ID"

if jq -e 'all(.[]; . != "")' <<< "$TEST_ROW" > /dev/null; then
  read -r -p "Run TEST_ROW once? It reads your CRM and sheet, adds a sheet row, and posts to Slack. [y/N] " answer
  if [[ "$answer" == [yY] ]]; then
    clay workflows runs test "$WF_ID" --inputs "$TEST_ROW" > test-run.json
    echo "Saved test-run.json. Check each step with: clay workflows runs steps $WF_ID <runId>"
  fi
else
  echo "TEST_ROW is empty, skipping the test run."
fi

read -r -p "Publish the workflow now? [y/N] " answer
if [[ "$answer" == [yY] ]]; then
  clay workflows publish "$WF_ID" --name v1
fi

echo "Workflow $WF_ID, webhook trigger $TRG_ID. All responses are saved in $(pwd)."
~~~

### Sample signal payload: sample-signal.json

~~~json
{
  "signal_id": "bmb-2026-10-23-0042",
  "source": "Bombora",
  "domain": "example.com",
  "topic": "warehouse automation",
  "country": "DE",
  "person_email": "",
  "received_at": "2026-10-23T09:12:00Z"
}
~~~

### Send it signals

After publishing, read the webhook URL and send the sample payload once, using a domain that matches a test account family. Each POST is one run.

- Load the saved ids (run inside clay-signal-ownership-routing/): `WF_ID=$(jq -r '.id' workflow.json); TRG_ID=$(jq -r '.id' trigger.json)`
- Read the webhook URL (argument order inferred, see the verify notes): `WEBHOOK_URL=$(clay workflows triggers get "$WF_ID" "$TRG_ID" | jq -r '.webhookUrl')`
- Send the sample payload (needs a published workflow, one run per request): `curl -sS -X POST "$WEBHOOK_URL" -H 'Content-Type: application/json' --data @sample-signal.json`
- List runs: `clay workflows runs list "$WF_ID"`
- Inspect one run: `clay workflows runs get "$WF_ID" <runId>`
- See each step's output for that run: `clay workflows runs steps "$WF_ID" <runId>`

### Verify in the workspace

- The webhook trigger shape comes from the CLI help, but the help does not say how "triggers get" orders its arguments. If the run commands fail, copy the webhook URL from the Clay UI instead.
- The help documents "nodes create" with nodeType and name only. If it rejects actionPackageId and actionKey, create the node with a name only and pick the action in the Clay UI.
- The reference says action steps take actionPackageId and actionKey but shows only a utility example for "nodes insert", so the placement of those fields inside "step" is inferred.
- Only "workflows create" documents an id field in its response. The script reads .id from trigger and node responses too and stops if it is missing.
- Package ids and action keys differ by workspace and depend on which integrations you have connected. Copy them from your catalog; this page does not guess them.
- Step input mapping is dynamic per workspace. The CLI path is "nodes get" then "nodes update", where incomingEdges is a full replacement. The argument order for "nodes get" is inferred from "nodes update".
- The help does not say whether step 1 connects to the trigger automatically. "clay workflows graph validate" reports a disconnected graph.
- The rule step is a formula or code step you add in the Clay UI. Test it against the worked example rows in the template outline before real traffic: each one should return the owner and rule shown there.
- "runs test" without --live is assumed to run the draft. The reference lists --live without describing it.
- Workflow runs can spend Clay credits and write to connected tools. Exit code 3 means re-run clay login, and exit code 4 means you are rate limited (wait for details.retryAfter).

## Guardrails

- Work only in the user's own accounts and workspaces, with their credentials.
- Confirm with the user before any step that writes to a CRM, sends email or messages, spends credits, or moves money.
- Treat every hours, cost, and threshold figure as a starting assumption and replace it with the user's numbers.
- Do not invent data, prices, or results. If a vendor price matters, check the vendor's current pricing page.

## Source

https://gtmplaybooks.io/playbooks/parent-subsidiary-signal-routing/
