Automation · Revenue operations
How to build lead routing that assigns in seconds
A form is filled at 14:02 and reaches a rep on Thursday. This is the design behind routing that does not do that, the prompts that build it, and what production adds.
Built with Tray Headless
- System Marketo
- Step Enrich
- Step Match to account
- Step Rule chain
- System Salesforce
The matcher runs before the rule chain, which is what stops a live deal being routed to a stranger.
The short answer
What is lead routing?
Lead routing comes down to four things: matching a lead to an account before you route it, a rule chain that evaluates in a fixed order and stops at first match, a fallback that catches everything the rules missed, and speed measured from arrival instead of from assignment. The part teams get wrong is the fallback. A routing table with no catch-all silently drops the leads nobody wrote a rule for, and nobody notices, because they were never assigned to anybody who would complain.
What matters here
- Match before you route. A lead that belongs to an open opportunity already has an owner, and routing it by territory hands a live deal to a stranger.
- Rules evaluate top down and stop at first match. A rule set where two rules can both fire is a rule set nobody can debug.
- The fallback queue should be empty. When it is not, that is a rule waiting to be written, and it is the most useful number on the page.
- Measure arrival to first touch, not assignment to first touch. Queue time is the part you can actually fix.
- Stamp which rule fired on every lead. Without it nobody can answer why a lead went where it went, and the rules never get corrected.
Who this is for
You run revenue operations, marketing operations or sales operations. You already have rules somewhere, probably in a Salesforce assignment rule nobody wants to touch. What you want is routing you can read, change without a deployment, and defend when a rep asks why they did not get a lead.
How it works in practice
What happens between a form being submitted and a rep picking up the phone.
- 1
A form fill lands and enrichment runs
Company, size and industry from the email domain. If enrichment times out, routing proceeds on what is there instead of holding the lead.
- 2
The lead is matched to an account before any rule fires
Domain, then fuzzy name, then parent hierarchy. An open opportunity on that account short-circuits everything below.
- 3
Rules evaluate top down and stop at first match
Named account, open opportunity, territory, round robin. Which rule fired is stamped on the lead.
- 4
Assignment posts to the rep where they already work
With the enrichment and the matched account attached, so the first touch does not start with research.
- 5
Anything unmatched lands in the fallback and alerts
Not a null owner, not a silent drop. An empty fallback is the goal and a non-empty one is the signal.
- 6
Ops changes the rule table without a deployment
The same workflow opens in Tray Build, so a territory change is a visual edit rather than a ticket.
What lead routing is made of
Routing is not a rules table. It is four parts, and the third one is the one teams leave out.
Account matching
Domain match, then fuzzy company name, then parent hierarchy. A lead on an account with an open opportunity goes to that owner and skips the rules entirely.
An ordered rule chain
Named accounts, then open opportunity, then territory, then round robin by segment. Top down, first match wins, and the order is the design.
A fallback that should be empty
Everything the rules missed lands in one queue with an alert. It is a monitoring surface, not a bin.
Timing from arrival
Three timestamps: arrived, assigned, first touch. Speed to first contact runs from the first to the last, because the middle is the part you own.
The Tray Headless prompts
Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.
Once per project, run
/tray-workflows:set-workspace
to pick the workspace these build in. Point it at a sandbox first.
- 1
Set up, and see what is actually connected
Before anything is built, confirm the ground truth.
Headless skills
build-workflowUse build-workflow. The systems in play are Salesforce, Marketo, Clearbit, Slack, Outreach, Workday and Snowflake, or whatever we run in those seats. Before you plan anything, tell me which of them are already authenticated in the workspace, because I do not want a connector stubbed that I have not authenticated. I expect Salesforce, Marketo and Slack. Tell me what is missing before we build anything, and do not stub a connector I have not authenticated.
- 2
Match the lead to an account first
The step that decides whether routing is right instead of merely fast.
Headless skills
build-workflowWork against Salesforce so the query uses the real operations and field names, then build the matcher in this order: 1. Exact match on email domain against Account.Website 2. Strip generic domains first: gmail, outlook, yahoo, hotmail, icloud 3. Fuzzy match Lead.Company against Account.Name at 0.85 similarity 4. Walk Account.ParentId up two levels for subsidiaries 5. Check for an Opportunity on that Account where StageName is not in Closed Won or Closed Lost If there is an open opportunity, the lead goes to that opportunity owner and skips every rule below. Write the matched AccountId back to the lead so nobody has to redo this later.Stripping generic domains first is not a nicety. Without it every Gmail signup matches whichever account happens to have gmail.com in a website field.
- 3
Build the rule chain, in order, stopping at first match
The order is the design. Write it so somebody can read it.
Headless skills
build-workflowUse build-workflow. Trigger on Lead created where LeadSource is not null. Rules evaluate top down, first match wins: 1. Named account list, owner from Account.OwnerId 2. Open opportunity, owner from the matcher above 3. Territory: Country then State, from a rules table I can edit 4. Segment round robin: under 200 employees to the SMB pool, 200 to 2000 to mid-market, above that to enterprise 5. Fallback queue Set Lead.OwnerId, stamp Routed_Rule__c with which rule fired, and post to the rep in Slack with the enrichment and the matched account. Never leave the fallback out. The queue that should be empty is the one that tells you a rule is wrong. - 4
Handle the five things that actually break it
Every one of these has quietly lost somebody a lead.
Headless skills
tray-gotchastray-patternsUse tray-gotchas, then handle these explicitly: Rep is out of office. Read the out of office flag and route to their deputy rather than assigning to somebody who will not look until Monday. Same lead submitted twice inside a minute. Dedupe on lower(email) before routing, not after. Enrichment times out. Route on what you have. Do not hold a lead in a queue waiting for a firmographic field. Territory with nobody assigned. Fall through to the fallback and alert. Never assign to a null owner. Lead arrives before its account exists. Create it, leave it unmatched, and re-run the matcher nightly.
- 5
Time it from arrival
Because the queue is the part you can fix.
Stamp three fields: Arrived__c on creation, Assigned__c when OwnerId is set, and First_Touch__c on the first logged Task or Event. Speed to first contact is arrival to first touch, not assignment to first touch. The gap between those two is the queue, and the queue is the part you own. Report median and 90th percentile by rule, by segment and by rep, plus the count that hit the fallback. If the fallback is not empty, that number is the most useful one on the page.
- 6
Validate it, then hand the rules to ops
The step that decides whether this survives its first territory change.
Run the per-step schema checks and the whole-workflow audit before this touches production. Then open the same workflow in Tray Build so revenue operations can change a territory or add a named account in the visual canvas, without coming back to a coding assistant. Same workflow, same governance, same audit trail underneath.
This is the step that decides whether the thing you built is still yours in six months, or whether every territory change becomes a ticket.
What it connects to
Routing sits between where leads arrive and where reps work, so it reads from both ends.
Salesforce
Read leads, accounts, opportunities and the owner model. Write the assignment, the matched account and the rule that fired.
Reads and writes
Marketo
Take the form fill the moment it lands, with the campaign and UTM context that decides which rule applies.
Reads
Clearbit
Enrich on email domain for company, size and industry, which is what the segment round robin bands on.
Reads
Slack
Tell the rep in the channel they already watch, with the enrichment and the account attached.
Writes
Outreach
Put the lead into a sequence the moment it is assigned, which is what speed to first contact actually measures.
Writes
Workday
Read approved time off and the reporting line, so a lead never lands with somebody who is away.
Reads
Snowflake
Land every routing decision with its timestamps, so rule performance over a quarter is a query.
Writes
Same build, other stacks
The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, Google BigQuery, Microsoft Teams, SAP SuccessFactors, HubSpot or Databricks.
Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.
Running it in production
The build gets you working routing. Leads are revenue, and the rules change monthly, so it needs to run properly.
It lives on the platform, not in a terminal window
Routing fires on every inbound lead, at whatever rate marketing generates them. That runs on the same engine as everything else, with retries and a record of each decision.
Governance is inherited, not added
Audit trail, access control and policy come from the platform, so a routing change is attributable to a person without anybody building logging.
Credentials are held by the platform, never hardcoded
The CRM, the enrichment provider and the messaging tool are each an authentication in your workspace. A routing workflow holding a Salesforce admin key in code is the finding that ends an audit.
Ops owns the rule table
Open the same workflow in Tray Build. A territory change is a visual edit by the person who owns territories, not a ticket to whoever wrote it.
Failures are visible before a rep complains
Alert on a non-empty fallback, on enrichment timeouts, and on any lead unassigned past its target. The first person to notice should not be the customer.
Questions people ask
Why match to an account before routing?
Because a lead that belongs to an account with an open opportunity already has an owner. Routing it by territory hands a live deal to somebody who has never spoken to them, and the rep who owns the deal finds out later.
Why does rule order matter so much?
Because the alternative is a rule set where two rules can both fire, and then nobody can explain why a lead went where it went. Top down with first match wins is readable and debuggable.
What should the fallback queue contain?
Nothing, ideally. It exists so a lead nobody wrote a rule for is visible, not silently unassigned. A non-empty fallback is the signal that a rule needs writing.
Why measure from arrival rather than assignment?
Because assignment to first touch measures the rep, and arrival to first touch measures the system. The gap between them is queue time, which is the part automation actually removes.
Can revenue operations change the rules without engineering?
Yes. The workflow is built from a coding assistant and then opens in Tray Build, so a territory change or a new named account is an edit by the person who owns it.
Vibe-coding app guides
Vibe-code an entire app with Helix
This moves the data between systems. It does not give anybody a screen to work in. Build that app in Claude Code, Codex or Cursor, then deploy and run it governed on Tray Helix. Same kind of guide, same kind of prompts.
How to build a lead routing app (opens helix.tray.ai in a new tab)
Further reading
Background on the same subject, for the case rather than the build.
Related guides
Revenue operations
How to build lead-to-account matching
Domain first, then fuzzy name, then hierarchy, with a confidence score and a review queue for the ones that are close. The Headless prompts that build it.
Revenue operations
How to build lead import and validation
Validate before you write, quarantine the bad rows instead of dropping them, dedupe against what is already there, and keep the source. The prompts that build it.
Revenue operations
How to build a CRM to marketing automation sync
Decide field ownership before you build, sync deltas not everything, handle the person-versus-lead model gap, and break loops. The prompts that build it.
Revenue operations
How to build a sales engagement to CRM sync
Log activity without flooding the timeline, suppress sequences on the accounts you must not touch, and keep one definition of engagement. The prompts that build it.
Last reviewed September 2026.