How to Create Automated Deal Rotation and Assignment
Route new deals to the right rep based on territory, capacity, and expertise.
Jay Banlasan
The AI Systems Guy
Manual deal assignment wastes time and creates uneven workloads. This system automates deal assignment and rotation for your sales team based on territory, capacity, and expertise. I set this up for teams of 5 to 50 reps.
What You Need Before Starting
- Python 3.8+
- CRM API with webhook support
- SQLite for tracking assignments
- Flask for webhook receiver
Step 1: Define Routing Rules
Set up rules for how deals get assigned. Territory, deal size, and industry all factor in.
ROUTING_RULES = {
"territories": {
"US-West": ["rep_alice", "rep_bob"],
"US-East": ["rep_carol", "rep_dave"],
"UK": ["rep_emma"],
},
"size_tiers": {
"enterprise": {"min_amount": 50000, "reps": ["rep_alice", "rep_carol"]},
"mid_market": {"min_amount": 10000, "reps": ["rep_bob", "rep_dave"]},
"smb": {"min_amount": 0, "reps": ["rep_emma"]},
},
"max_active_deals": 25,
}
Step 2: Track Rep Capacity
Keep a live count of each rep's active deals. Nobody gets new deals when maxed out.
import sqlite3
def get_rep_capacity(rep_id):
conn = sqlite3.connect("assignments.db")
active = conn.execute(
"SELECT COUNT(*) FROM deals WHERE owner = ? AND status = 'open'",
(rep_id,)
).fetchone()[0]
return ROUTING_RULES["max_active_deals"] - active
def get_available_reps(rep_list):
available = []
for rep in rep_list:
capacity = get_rep_capacity(rep)
if capacity > 0:
available.append({"rep": rep, "capacity": capacity})
return sorted(available, key=lambda x: -x["capacity"])
Step 3: Build the Assignment Engine
When a new deal comes in, find the right rep based on territory and capacity.
def assign_deal(deal):
territory = deal.get("territory", "US-East")
amount = deal.get("amount", 0)
eligible_reps = ROUTING_RULES["territories"].get(territory, [])
for tier_name, tier in ROUTING_RULES["size_tiers"].items():
if amount >= tier["min_amount"]:
eligible_reps = [r for r in eligible_reps if r in tier["reps"]]
break
available = get_available_reps(eligible_reps)
if available:
assigned_rep = available[0]["rep"]
update_crm_owner(deal["id"], assigned_rep)
return assigned_rep
return None
Step 4: Handle the Webhook
Listen for new deal creation events from your CRM.
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/webhook/new-deal", methods=["POST"])
def handle_new_deal():
deal = request.json
assigned = assign_deal(deal)
if assigned:
return jsonify({"status": "assigned", "rep": assigned})
else:
notify_manager("No available reps for new deal")
return jsonify({"status": "escalated"})
Step 5: Add Round-Robin Fallback
When multiple reps have equal capacity, rotate through them evenly.
def round_robin_select(available_reps, deal_type):
conn = sqlite3.connect("assignments.db")
last = conn.execute(
"SELECT rep_id FROM assignment_log WHERE deal_type = ? ORDER BY created_at DESC LIMIT 1",
(deal_type,)
).fetchone()
if last:
rep_ids = [r["rep"] for r in available_reps]
if last[0] in rep_ids:
idx = (rep_ids.index(last[0]) + 1) % len(rep_ids)
return available_reps[idx]["rep"]
return available_reps[0]["rep"]
What to Build Next
Add performance weighting. Reps with higher close rates on a given deal type should get priority for similar deals.
Related Reading
- Setting Up Automated Task Assignment - automated task assignment setup
- How to Automate Your Sales Pipeline Updates - automate sales pipeline updates
- Building Automated Sales Enablement Content - automated sales enablement content guide
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment