Routing breaks at the point where the rule needs a fact the CRM does not hold. Assignment rules and workflows split by country, round-robin a queue and reassign on a stage change, and for that they are the right tool: they are already paid for and they sit next to the record. The moment the correct decision depends on how many leads the rep already took this week, on whether the lead’s company is the same account under a different domain, or on a score computed in the warehouse, the rule cannot be written where the CRM keeps its rules.
This is the case for moving assignment out of the CRM, what the three classes of alternative actually are, and what capacity-aware routing looks like when it is declared as code.
Where CRM-native routing stops #
Native routing has four walls, and teams hit them in roughly this order.
The deciding fact lives somewhere else. Product usage, a warehouse model, an enrichment result, a fit score computed by something other than the CRM. You can sync the field in and route on it, and now every routing decision depends on a sync running on its own schedule. The rule is correct and the data behind it is eleven hours old.
A lead is a person and routing is a decision about an account. Lead-to-account matching is exact-domain matching in most native setups, which fails on subsidiaries, personal-email signups, resellers and rebrands. When it fails, four leads from one buying committee land on four different reps, each of whom starts a first-touch email.
Capacity is a counting problem. “Has this rep already taken twelve this week” needs a window, a count of distinct records inside it, and a rule about when the count resets. Assignment rules hold no counter, so capacity is usually approximated by shrinking the pool and reopening it by hand.
A change to a routing rule is not reviewable. It is edited in a UI and it applies on save. Salesforce Flow keeps versions, but the difference between two of them is not something a reviewer can read before it takes effect, and no record says which version assigned the account you are looking at. The failure is quiet: leads keep landing, on the wrong reps, until a quarterly review finds it.
Three classes of alternative #
| What it is | Fits when | |
|---|---|---|
| Dedicated routing tool | Routing and lead-to-account matching as a product installed against the CRM (LeanData, Distribution Engine, Traction Complete) | The CRM is the system of record and routing is the whole problem |
| General automation | An iPaaS or workflow tool wiring systems together (n8n, Workato, Zapier) | One or two flows, owned by someone who will maintain them |
| GTM infrastructure | Routing as one node in the same engine that enriched, matched and scored the record, declared as code | The decision depends on data the CRM does not hold, and the logic has to be reviewable |
The first row is the honest default for a team whose routing is “round-robin the inbound queue by country”. Moving that out of the CRM buys nothing. The third row is what the rest of this page is about, and it is a different purchase: not a better router, an engine where routing is the last step of a chain rather than an isolated feature.
Capacity-aware and territory-based routing #
Assignment that holds at scale needs six things: the territory, the existing account owner, the lead source, the rep’s current load, a fallback when nobody is eligible, and a record of what happened. In Cargo those are primitives rather than fields.
Members are imported from the connected CRM, Salesforce, HubSpot, Pipedrive or another, and stay in sync, so the routing pool is the sales org rather than a copy of it. They carry roles (SDR, AE, CSM, or your own) and metadata such as languages or specializations.
Territories are named pools of members distributed across with weighted round-robin, each with an optional fallback member.
Capacities cap how many distinct records a member can hold inside a window. The window can be hourly, daily, weekly, monthly, quarterly or yearly, sliding by default or resetting at a fixed boundary such as Monday at 09:00 UTC. A model-based capacity goes further and derives the load from real pipeline data, counting each rep’s open opportunities rather than only what Cargo itself allocated.
Declared, the whole thing is a few lines:
import { defineCapacity, defineMember, defineTerritory } from "@cargo-ai/cdk";
const alice = defineMember("alice@acme.com");
const bruno = defineMember("bruno@acme.com");
const headOfSales = defineMember("sam@acme.com");
export const emeaEnterprise = defineTerritory("emea-enterprise", {
label: "EMEA Enterprise",
members: [{ ref: alice, weight: 2 }, { ref: bruno }],
fallback: headOfSales,
});
export const aeWeeklyLoad = defineCapacity("ae-weekly-load", {
name: "AE weekly load",
memberCapacity: 12,
allocationExpirationPolicy: { interval: "weekly", weekDay: 1 },
});
Members are addressed by email rather than by id, which is what lets the same file deploy into a second workspace: a uuid belongs to one workspace, an email belongs to a person.
The fallback is the service-level answer. When every eligible member is at capacity, the lead goes to the fallback member and the allocation is flagged as a fallback assignment, so the overflow is visible as a number instead of as a complaint. With no fallback set, allocation fails with an explicit error rather than silently leaving the record unowned. Both are better than the usual outcome, which is a lead that was routed correctly to somebody who could not work it.
Every assignment is written to an allocation history that links back to the run that made it, which is the question a rep actually asks: not how the algorithm works, but why this one came to me and not to her.
One engine for scoring, assignment and activation #
Routing is rarely wrong on its own. It is wrong because the record reached it half-enriched, matched to the wrong account, or carrying a score computed from stale inputs. Splitting those steps across a routing tool, an enrichment tool and a CRM workflow means each is correct in isolation and the chain is not.
In one engine the chain is a single run: enrich the record from the providers you already pay for, resolve it to an account in the unified model, score it against the rubric, decide the motion, allocate it to a territory with capacity respected, then write to the CRM, post to Slack and enrol in the sequence. One trace covers all of it, so a bad assignment is traceable to the step that caused it rather than to a system boundary.
That is also what makes third-party signals usable in the decision instead of decorative. An intent feed or a usage threshold is a typed input to the same run that allocates, so “which accounts are ready” and “who gets them” are answered by one policy rather than two teams’ tools.
For the process itself, independent of tooling, see how to implement a B2B lead routing process. For the scoring layer that feeds it, the right approach to lead scoring in B2B. For where assignment sits in the wider decision layer, revenue orchestration.
Frequently asked questions #
Three classes. A dedicated routing product installed against the CRM, such as LeanData, Distribution Engine or Traction Complete, when routing is the whole problem. A general automation or iPaaS tool such as n8n, Workato or Zapier, when there are one or two flows and someone owns them. Or GTM infrastructure such as Cargo, where assignment is one step in the same engine that enriched, matched and scored the record, and the logic is declared as code instead of configured in a UI.
Not directly. Capacity means counting how many distinct records a rep already holds inside a window and stopping when the count is reached, and assignment rules keep no such counter. Teams approximate it by removing reps from the queue by hand. A routing layer with a capacity primitive does the counting, and the better ones can derive the load from real pipeline data, such as each rep’s open opportunities, rather than only from what they themselves assigned.
It is resolving an inbound person to the account they belong to before deciding who owns them. Routing decisions are account decisions: existing owner, open opportunity, territory, customer or prospect. Exact-domain matching misses subsidiaries, personal-email signups and companies that rebranded, and each miss puts one buying committee in front of several reps at once.
Orchestration platforms and GTM infrastructure platforms, where scoring, matching, assignment and the outbound action are steps in one run against one data model. The test is not whether a vendor lists all four features, it is whether a single trace shows the score that was used, the account it matched, the rep it allocated to and what was written back.
In the CRM while the rule only reads fields the CRM owns and stays simple enough to hold in your head. Outside it when the decision needs product usage, warehouse data, enrichment or capacity, or when a change to the rule should be reviewed before it takes effect. The CRM remains the system of record for the assignment either way: the decision moves, the ownership field does not.