Outcome. New leads are split into territory groups and each group is assigned to the right owner pool in round-robin order, with no manual triage.
Workflow mapEnrollment, branches and actions at a glance
flowchart TD
A[Contact created / Territory set] --> B{Territory value?}
B -->|north-america| C[Rotate to NA pool]
B -->|emea| D[Rotate to EMEA pool]
B -->|apac| E[Rotate to APAC pool]
B -->|blank / unknown| F[Notify sales ops + add to Needs manual routing list]
C --> G[Set routed date, notify owner, create call task]
D --> G
E --> G
When to use it / when not to
- Use it when the sales team is split by geography (country, state, or region) and each territory has its own pool of 2+ reps.
- Use it when leads currently sit unassigned for hours because a manager triages them by hand.
- Do not use it if only one rep exists per territory. Use a simple
Set property value(owner) action instead, see Variants. - Do not use it for named/strategic accounts that need a fixed owner. Exclude those with a list-based suppression, see lead-routing-011.
Prerequisites
- Property:
Territory(internal nameterritory), object contact, field type dropdown select, options matching your sales regions (for examplenorth-america,emea,apac). Why: this is the field the branch logic reads. Populate it via form hidden field, lifecycle enrichment, or a country-to-territory lookup (see lead-routing-033 for the postal/zip variant). - Active HubSpot Teams or manually built owner rotation lists per
territory, one per branch. Why:
Rotate record to ownerneeds an explicit, static list of owners to rotate across. - Confirm every rep listed in a rotation pool has a seat and is set to active. Deactivated reps break the rotation, see lead-routing-012.
- A test contact per territory value, for the test plan.
- Property:
Lead routed date(internal namelead_routed_date), object contact, field type date picker. Why: it stamps the moment a lead was routed, used for SLA timing and rotation reporting.
Enrollment
- Trigger type: event-based.
- Criteria:
Contact was createdORTerritory has been setwith a value present (is known). Add a filterLifecycle stage is not customerto keep existing customers out of new-lead routing. - Re-enrollment: off. A contact should not re-roll the dice every time a property changes; reassigning an active lead mid-cycle causes handoff confusion.
- Suppression: static list
Do not auto-route - named accountsexcluded via enrollment triggerNot in list.
Steps
- If/then branch:
Territoryisnorth-america- Rotate record to owner: pool = NA rep list (round-robin, evenly distributed)
- Set property value:
Lead routed date= current date - Send internal email notification to: record owner, subject "New lead assigned: {{contact.firstname}} {{contact.lastname}}"
- Create task: type "Call", title "First contact - {{contact.firstname}}", due in 1 business day, assigned to record owner
- If/then branch:
Territoryisemea- Same 4 actions as above, pool = EMEA rep list
- If/then branch:
Territoryisapac- Same 4 actions as above, pool = APAC rep list
- Else branch (territory unknown or blank)
- Send internal email notification to sales ops distribution owner: "Lead with no territory value: {{contact.hs_object_id}}"
- Add to static list: "Needs manual routing"
Known pitfalls
Rotate record to ownerrotates evenly across the list at the moment the action runs. Adding or removing a rep from the list does not retroactively rebalance past assignments.- If a rep is deactivated but stays in the rotation list, the action simply skips them: deactivated users are skipped by the rotate record owner action and are removed as options when setting the owner of a record (https://knowledge.hubspot.com/user-management/remove-hubspot-users).
- Hidden form fields that set
Territoryonly fire on form submission. Leads created via import or API will not get a territory unless you also branch on country/company properties. - Re-enrollment left on will re-roll an already-assigned, already-contacted lead to a new owner the next time territory is edited. Keep it off unless you explicitly want reassignment behavior (see lead-routing-005).
- Round-robin pools defined as static lists do not auto-update when someone joins the team. Review pool membership quarterly.
Test plan
- Create 3 test contacts, one per territory value, using the actual form or by manually setting the property.
- Open workflow history (Automation > Workflows > this workflow > History tab) and confirm each contact enrolled within a minute.
- Check each contact's record timeline for the "Owner changed" event and confirm it matches the expected pool.
- Confirm the internal email notification arrived in the assigned owner's inbox.
- Confirm the call task appears in the owner's task queue with the correct due date.
Variants
- Single rep per territory: replace
Rotate record to ownerwithSet property value(owner = fixed rep) per branch. - Company-level routing instead of contact-level: same structure,
object = company, trigger on
Company was created. - Weighted rotation by rep capacity instead of even split: see lead-routing-014.
Build spec
trigger:
type: event-based
event: contact_created_or_property_changed
property: territory
criteria:
- territory: is_known
- lifecycle_stage: not_equal customer
reenrollment: false
suppression_list: "Do not auto-route - named accounts"
branches:
- condition: territory == "north-america"
actions:
- type: rotate_record_to_owner
pool: "NA rep rotation list"
- type: set_property_value
property: lead_routed_date
value: current_date
- type: send_internal_email_notification
to: record_owner
subject: "New lead assigned: {{contact.firstname}} {{contact.lastname}}"
- type: create_task
task_type: call
title: "First contact - {{contact.firstname}}"
due: +1_business_day
assigned_to: record_owner
- condition: territory == "emea"
actions: [same_as_above, pool: "EMEA rep rotation list"]
- condition: territory == "apac"
actions: [same_as_above, pool: "APAC rep rotation list"]
- condition: else
actions:
- type: send_internal_email_notification
to: sales_ops_owner
subject: "Lead with no territory value: {{contact.hs_object_id}}"
- type: add_to_static_list
list: "Needs manual routing"



