Skip to content

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

  1. System Marketo
  2. Step Enrich
  3. Step Match to account
  4. Step Rule chain
  5. System Salesforce
Also Slack Outreach

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

    Set up, and see what is actually connected

    Before anything is built, confirm the ground truth.

    Headless skills build-workflow

    Use 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. 2

    Match the lead to an account first

    The step that decides whether routing is right instead of merely fast.

    Headless skills build-workflow

    Work 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. 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-workflow

    Use 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. 4

    Handle the five things that actually break it

    Every one of these has quietly lost somebody a lead.

    Headless skills tray-gotchas tray-patterns

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

Last reviewed September 2026.