Route Salesforce leads with round-robin using Flow Builder
Prerequisites
- Salesforce org with Flow Builder access (Enterprise, Unlimited, or Developer edition)
- System Administrator profile or "Manage Flows" permission
- Slack workspace with Salesforce for Slack app installed (for notifications)
- A list of Salesforce User IDs for your rep rotation
Overview
Flow Builder has no native round-robin logic. The core pattern is to store a counter in a Custom Setting, increment it on each new Lead, and use modulo arithmetic to pick the next rep. You'll split the work into a before-save flow (fast field update for OwnerId) and an after-save flow (Slack notification, since HTTP callouts aren't allowed in before-save context).
Step 1: Create a Custom Setting for the counter
Go to Setup → Custom Settings → New.
- Label:
Round Robin Counter - API Name:
Round_Robin_Counter__c - Setting Type: Hierarchy
- Visibility: Public
Add a custom field:
- Field Label:
Last Index - API Name:
Last_Index__c - Type: Number (0 decimal places)
- Default Value: 0
After saving, click Manage and create an org-level default record with Last_Index__c = 0.
Custom Settings are accessible in flows without a SOQL query counting against governor limits. They persist across transactions, making them ideal for storing a simple counter.
Step 2: Create a Custom Metadata Type for the rep roster
Go to Setup → Custom Metadata Types → New.
- Label:
Round Robin Rep - API Name:
Round_Robin_Rep__mdt
Add these fields:
| Field | API Name | Type |
|---|---|---|
| Rep Order | Rep_Order__c | Number (0 decimals) |
| User ID | User_Id__c | Text (18 chars) |
| Slack User ID | Slack_User_Id__c | Text (15 chars) |
| Is Active | Is_Active__c | Checkbox (default: true) |
Create records for each rep in the rotation:
| Label | Rep Order | User ID | Slack User ID | Is Active |
|---|---|---|---|---|
| Alice Smith | 0 | 005xx0000012345 | U01AAAA | true |
| Bob Jones | 1 | 005xx0000023456 | U02BBBB | true |
| Carol Chen | 2 | 005xx0000034567 | U03CCCC | true |
| Dave Kim | 3 | 005xx0000045678 | U04DDDD | true |
Uncheck Is_Active__c for reps who are unavailable. The flow will skip inactive reps automatically.
Step 3: Create the before-save flow (assignment)
Go to Setup → Flows → New Flow → Record-Triggered Flow.
- Object: Lead
- Trigger: A record is created
- Optimize for: Fast Field Updates (Before Save)
Get the current counter
Add a Get Records element:
- Object:
Round_Robin_Counter__c - Store: First record →
varCounter
Get active reps
Add a Get Records element:
- Object:
Round_Robin_Rep__mdt - Filter:
Is_Active__cequalstrue - Sort:
Rep_Order__c, Ascending - Store: All records →
colReps
Calculate assignment with a Formula
Add a Formula resource:
- Name:
frmNextIndex - Type: Number
- Formula:
MOD({!varCounter.Last_Index__c}, {!colReps.Size})
This gives you the index of the next rep to assign.
Get the specific rep
Add an Assignment element to loop through the collection and pick the rep at the calculated index, or use a Loop element with a counter variable that breaks when it matches frmNextIndex.
Update the Lead owner
Add an Assignment element:
- Set:
{!$Record.OwnerId}= the selected rep'sUser_Id__c
Since this is a before-save flow, the field update happens automatically — no separate Update Records element needed.
Increment the counter
Add an Update Records element:
- Object:
Round_Robin_Counter__c - Filter: Use the record ID from
varCounter - Set:
Last_Index__c={!varCounter.Last_Index__c} + 1
You cannot send Slack messages from a before-save flow. The assignment logic must be in a before-save flow for performance (no extra DML), but the Slack notification needs a separate after-save flow or Platform Event.
Step 4: Create the after-save flow (Slack notification)
Create a second Record-Triggered Flow:
- Object: Lead
- Trigger: A record is created
- Optimize for: Actions and Related Records (After Save)
- Entry condition:
OwnerIdis not null
Send Slack notification
If you have Salesforce for Slack installed, add a Send Slack Message action:
- Slack Workspace: Select your connected workspace
- Channel or User: The assigned rep's Slack User ID (you'll need to look this up from the Custom Metadata Type using the Lead's OwnerId)
- Message: Include the lead's Name, Email, Company, and a link back to the Lead record
Alternatively, add an HTTP Callout action (available in Flow Builder as an External Service or Apex invocable):
- URL:
https://slack.com/api/chat.postMessage - Method: POST
- Headers:
Authorization: Bearer xoxb-YOUR-BOT-TOKEN - Body: Channel set to the rep's Slack User ID, with lead details in the message text
Step 5: Activate and test
- Activate both flows
- Create a test Lead manually or via the API
- Verify the Lead's OwnerId was set to the expected rep
- Check Slack for the notification DM
- Create a few more Leads and confirm the rotation cycles through all reps
If your org already has an active Lead Assignment Rule, it will run after your before-save flow. The assignment rule could overwrite the OwnerId your flow just set. Either deactivate the existing rule or add logic to your rule that preserves flow-assigned owners.
Alternative: Queue + Omni-Channel
If you're on Enterprise+ edition, Salesforce Omni-Channel provides workload-based routing out of the box:
- Create a Lead Queue and add your reps as members
- Set your assignment rule to route all Leads to the queue
- Enable Omni-Channel and configure a Routing Configuration with "Least Active" or "Most Available" routing
- Reps receive Leads in their Omni-Channel widget based on current workload
This is the officially supported path for workload-balanced routing, but it requires Enterprise edition, Omni-Channel setup, and reps to be logged into the Omni-Channel widget.
Cost
- Flow Builder: Included in all Salesforce editions with Flow access (Enterprise+)
- Custom Settings and Custom Metadata Types: Included, no additional cost
- Omni-Channel: Included in Enterprise and Unlimited editions
Need help implementing this?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.