Route Parent Company Signals to the Right Subsidiary Owner
The 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.
Implementation 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.
| Charge | Listed price |
|---|---|
| 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 (all assumptions)
Replace each value with your own figure.
- TSignals per week that enter the workflow150AssumptionCount last month's signals from your visitor and intent tools that match a CRM domain, and divide by 4.33.
- SSignals per week that land on an account family (a parent or child match)48AssumptionRun last month's signals through step 3 and count the ones whose family has more than one account.
- MMinutes to look up the hierarchy and pick an owner by hand5AssumptionTime ten family signals in the current manual process.
- QShare of family signals that still go to the RevOps conflict queue25%AssumptionRun the rule on last month's signals and count conflicts.
- XClay actions per signal6AssumptionAn 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.
- RLoaded hourly cost of the RevOps analyst who routes signals today$60AssumptionSalary 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
- 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.
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. Open the Clay credit calculator.
Template outline
The structure to recreate in your own workspace. Field names and thresholds are starting points.
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}}"Build it in Clay
Copy these commands into your own Clay CLI. They run in your Clay workspace under your login. Nothing runs on our side, and this site never sees your Clay data or login.
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.
Not tested by GTM Playbooks
This build was written from the Clay CLI v1.3.1 help output, not from a run. Anything marked “Verify in your workspace”, and every line tagged VERIFY in the script, uses a shape that help does not document. Workflow runs can spend your Clay credits.
Part 1: Before you start
1.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.
2.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 loginLog in on a headless machine
clay login --deviceConfirm who you are logged in as
clay whoami3.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 listShow the active workspace
clay workspaces currentSwitch workspace
clay workspaces switch <workspaceId>4.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.jsonSearch the catalog
grep -Eio '"[^"]*(hubspot|salesforce|search|lookup|google sheets|lookup rows|add row|slack)[^"]*"' catalog.json | sort -uSee an action's inputs and outputs
clay workflows actions schema <packageId> <actionKey>5.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.
6.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.
7.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.
Part 2: Workflow spec
What the script builds: Signal ownership routing.
Trigger
webhookYour 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
- bmb-2026-10-23-0042
source- Which tool sent it
- Bombora
domain- Company domain, lowercased, without www
- example.com
topic- Intent topic or page visited
- warehouse automation
country- Country of the visitor or the surge, may be blank
- DE
person_email- Identified visitor email, may be blank
received_at- When the source saw the signal, ISO 8601
- 2026-10-23T09:12:00Z
- 1
Find accounts by domain
actionSearches 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.
- Reads
domainperson_email- Writes
matched_accounts
- 2
Read the account family
actionFor 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.
- Reads
matched_accounts- Writes
family
Verify in your workspace: 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
actionLooks up named_overrides rows for any account id in the family, and the territories row for the signal country and the family segment.
- Reads
familycountry- Writes
overrideterritory_owner
- 4
Pick the owner by rule
functionApplies 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.
- Reads
familyoverrideterritory_ownercountryperson_email- Writes
statuschosen_accountowner_emailrule_firedreasonslack_channelslack_text
Verify in your workspace: 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
actionRouted: 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.
- Reads
slack_channelslack_text- Writes
Slack message
- 6
Log the decision
actionAdds 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.
- Reads
signal_iddomainfamilystatuschosen_accountowner_emailrule_firedreason- Writes
Sheet row
Part 3: Build script
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.
Save it as build-signal-ownership-routing.sh, fill in the 12 action ids at the top, then run bash build-signal-ownership-routing.sh.
build-signal-ownership-routing.sh
#!/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 recordsSEARCH_ACTION_KEY=""FAMILY_PACKAGE_ID="" # HubSpot or Salesforce: lookup record (or HTTP request)FAMILY_ACTION_KEY=""RULES_PACKAGE_ID="" # Google Sheets: lookup rowsRULES_ACTION_KEY=""SLACK_PACKAGE_ID="" # Slack: send messageSLACK_ACTION_KEY=""LOG_PACKAGE_ID="" # Google Sheets: add rowLOG_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; }donecommand -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-routingcd clay-signal-ownership-routing echo "1/9 Create the workflow"clay workflows create --name "Signal ownership routing" > workflow.jsonWF_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.jsonTRG_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.jsonSTEP1_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.jsonSTEP2_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.jsonSTEP3_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.jsonSTEP4_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.jsonclay 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, reasonMap 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.jsongraph.json in this folder shows the current nodes and edges. EOFread -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>" fielse echo "TEST_ROW is empty, skipping the test run."fi read -r -p "Publish the workflow now? [y/N] " answerif [[ "$answer" == [yY] ]]; then clay workflows publish "$WF_ID" --name v1fi echo "Workflow $WF_ID, webhook trigger $TRG_ID. All responses are saved in $(pwd)."Part 4: Sample signal payload
Save this as clay-signal-ownership-routing/sample-signal.json. Your signal source or relay should send the same fields for every signal.
sample-signal.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"}Part 5: 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.jsonList 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 your workspace
The Clay CLI help does not document these details. Check each one before you rely on the build.
- 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).
Common questions
- How does the workflow choose between the parent and subsidiary owner?
- With a written tie-break order that sales leadership signs off on: (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. It stops when one candidate is left.
- What happens when the rules cannot pick one owner?
- The signal goes to a RevOps conflict queue instead of a rep: more than one candidate after the last rule, an inactive chosen owner, or a domain that matches two separate account families. Each row has a resolution deadline, 1 business day here as an assumption, and no rep is alerted until it is resolved.
- Does the workflow change account owners?
- No. It attaches the signal to the chosen account and alerts that owner with the rule that fired and the other owners in the family. Owner changes go through your normal territory process.
- Which Clay plan does parent and subsidiary routing need?
- As built here, with a Clay webhook trigger and HubSpot or Salesforce lookups, Clay Growth or above: $495 a month billed monthly or $446 a month billed annually, as checked on 2026-10-21. The example uses 3,897 actions a month, inside Growth's 40,000.
Keep going
Related playbooks
- InboundIntermediate
Automate Inbound Lead Routing with Enrichment and Fit Scoring
Inbound leads wait in a shared queue or get assigned round-robin regardless of fit, so the best leads reach a rep late and poor-fit leads take up AE time.
ClayHubSpot or SalesforceApollo+2Estimate: 4 hrs/week - OutboundIntermediate
Turn Buyer Intent Signals into Outbound Sequences
Intent data shows which accounts are researching your category, but it sits in a dashboard nobody checks daily, so the signal is stale before a rep acts on it.
ClayG2 Buyer Intent or BomboraApollo+2Estimate: 5 hrs/week - OutboundAdvanced
Turn Anonymous Website Visitors into Outbound Sequences
Marketing and sales cannot tell which ICP companies hit pricing, docs, or blog pages, so high-intent traffic dies without a follow-up.
RB2B or VectorClayHubSpot or Salesforce+1Estimate: 6 hrs/week - RevOpsIntermediate
Keep CRM Data Clean with an AI Hygiene Agent
CRM records decay as people change jobs and reps type titles and industries in different formats, so segmentation, routing, and reporting quietly break.
ClayClaygentHubSpot or Salesforce+2Estimate: 4 hrs/week - RevOpsIntermediate
Audit Every GTM Automation and Agent for an Owner, a Metric, and a Kill Switch
Clay tables, CRM workflows, Zaps, Make scenarios, and AI agents pile up faster than anyone tracks them, so when one stops running or writes bad data nobody knows who owns it, what it was for, which fields it can change, or how to stop it, and unowned automations keep spending credits and writing to the CRM.
Google SheetsClayHubSpot or Salesforce+2Estimate: 1.5 hrs/week
Need help implementing a playbook?
Our team builds custom Clay workflows and AI automations for revenue teams.
Get it built for you