Round-robin assign Pipedrive deals and notify reps using n8n
Install this workflow
Download the n8n workflow JSON and import it into your n8n instance.
round-robin.n8n.jsonPrerequisites
- n8n instance (cloud or self-hosted)
- Pipedrive account with API access (Growth plan or higher)
- Pipedrive API token (from Settings > Personal > Tools and Integrations > API)
- Slack app with Bot Token (
chat:writescope) or Slack credential configured in n8n - n8n credentials configured for both Pipedrive and Slack
- A mapping of Pipedrive User IDs to Slack User IDs for each rep
Why n8n?
n8n is the best fit for round-robin deal routing because its static data feature ($getWorkflowStaticData) persists the rotation counter across executions without external storage. The Code node handles roster management, counter logic, and rep selection in a single step — and the visual canvas makes it easy to add branches for territory routing or value-based filtering later.
The Pipedrive Trigger node uses webhooks, not polling. When you activate the workflow, n8n automatically registers a webhook with Pipedrive, so new deals are processed in real time — typically within 1-2 seconds of creation. Self-hosted n8n is free with unlimited executions, so there is no per-deal cost regardless of volume.
How it works
- Pipedrive Trigger node receives a webhook from Pipedrive whenever a deal is created — fires in real time, not on a polling interval
- Code node reads the round-robin counter from n8n static data, selects the next rep from a roster array, increments the counter, and passes deal details downstream
- HTTP Request node updates the deal's
owner_idin Pipedrive viaPUT /v1/deals/{'{'}id{'}'} - Slack node sends a Block Kit DM to the assigned rep with deal title, value, pipeline, and a direct Pipedrive link
Step 1: Configure Pipedrive credentials in n8n
- In Pipedrive, go to Settings > Personal > Tools and Integrations > API
- Copy your API token
- In n8n, go to Credentials > New > Pipedrive API
- Paste the API token and save
- Optionally set the Company Domain (the subdomain from your Pipedrive URL, e.g.,
yourcompanyfromyourcompany.pipedrive.com)
Step 2: Add a Pipedrive Trigger node
Create a new workflow and add a Pipedrive Trigger node:
- Credential: Select your Pipedrive API credential
- Action: Created
- Object: Deal
This fires every time a new deal is created in Pipedrive. The payload includes the full deal object with id, title, value, pipeline_id, stage_id, and other fields.
Unlike the Salesforce Trigger (which polls every 1-5 minutes), the Pipedrive Trigger registers a webhook with Pipedrive automatically when you activate the workflow. New deals are processed within seconds. No polling interval to configure — it is real-time.
Step 3: Add a Code node with round-robin logic
Add a Code node. This is where the round-robin rotation happens. n8n's static data persists across executions, so the counter survives between deals without needing a database or external store:
// Rep roster: Pipedrive User ID → Slack User ID
const reps = [
{ pipedriveUserId: 12345678, slackUserId: "U01AAAA", name: "Alice" },
{ pipedriveUserId: 23456789, slackUserId: "U02BBBB", name: "Bob" },
{ pipedriveUserId: 34567890, slackUserId: "U03CCCC", name: "Carol" },
{ pipedriveUserId: 45678901, slackUserId: "U04DDDD", name: "Dave" },
];
// Get and increment the counter using n8n static data
const staticData = $getWorkflowStaticData('global');
const currentIndex = staticData.roundRobinIndex || 0;
const assignedRep = reps[currentIndex % reps.length];
staticData.roundRobinIndex = (currentIndex + 1) % reps.length;
// Pass deal data and assigned rep downstream
const deal = $input.first().json;
return [{
json: {
dealId: deal.id,
dealTitle: deal.title,
dealValue: deal.value,
dealCurrency: deal.currency || 'USD',
pipelineId: deal.pipeline_id,
stageId: deal.stage_id,
personId: deal.person_id,
orgName: deal.org_name || 'Unknown organization',
assignedRep: assignedRep,
}
}];Replace the pipedriveUserId values with your actual Pipedrive user IDs (visible in Settings > Manage Users) and the slackUserId values with each rep's Slack member ID (click their Slack profile > More > Copy member ID).
n8n's $getWorkflowStaticData('global') persists across executions but resets if you delete and recreate the workflow, or export and reimport it. If the counter resets, the worst case is one round of uneven distribution before it balances out. For critical fairness guarantees, store the counter in a Google Sheet cell or Redis instead.
Step 4: Update deal owner via Pipedrive API
Add an HTTP Request node to assign the deal to the selected rep:
- Method: PUT
- URL:
https://api.pipedrive.com/v1/deals/{{ $json.dealId }} - Authentication: None (token in query parameter)
- Query Parameters:
api_token= your Pipedrive API token - Body Content Type: JSON
- Body (JSON):
{
"owner_id": {{ $json.assignedRep.pipedriveUserId }}
}This sets the deal's owner in Pipedrive so it appears in the assigned rep's pipeline view. The PUT /v1/deals/{'{'}id{'}'} endpoint accepts any deal field for update.
Instead of hardcoding the API token in the query parameter, you can reference it from your Pipedrive credential. However, since the HTTP Request node's predefined Pipedrive auth uses OAuth, the simplest approach for API token auth is the query parameter method shown above.
Step 5: Send Slack DM to the assigned rep
Add a Slack node:
- Resource: Message
- Operation: Send
- Channel:
{{ $json.assignedRep.slackUserId }}(DM by user ID) - Message Type: Block Kit
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":arrows_counterclockwise: *New Pipedrive Deal Assigned to You*\n*{{ $json.dealTitle }}*\n\n*Value:* {{ $json.dealCurrency }} {{ $json.dealValue }}\n*Organization:* {{ $json.orgName }}\n*Assigned to:* {{ $json.assignedRep.name }} (round-robin)"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": { "type": "plain_text", "text": "View in Pipedrive" },
"url": "https://YOURCOMPANY.pipedrive.com/deal/{{ $json.dealId }}"
}
]
}
]
}Replace YOURCOMPANY with your actual Pipedrive subdomain.
To send a Slack DM, use the user ID (e.g., U01AAAA) as the channel value. The bot must have chat:write scope and the user must be in the workspace.
Step 6: Activate
- Click Execute Workflow to test — create a new deal in Pipedrive while the workflow is in test/listening mode
- Verify the deal's owner was updated in Pipedrive
- Confirm the Slack DM arrived with the correct deal details and Pipedrive link
- Create a second deal and verify the next rep in rotation was assigned
- Toggle the workflow to Active
Once active, n8n registers the webhook with Pipedrive automatically. You can verify it exists in Pipedrive under Settings > Tools and apps > Webhooks.
Troubleshooting
Common questions
How does the round-robin counter persist between deals?
n8n's $getWorkflowStaticData('global') stores key-value data that survives across workflow executions. The counter increments after each deal and picks up where it left off for the next one. This data is tied to the workflow instance — it resets only if you delete and recreate the workflow from scratch (not on edits or version updates). For a 4-person team, the assignment pattern is always Alice, Bob, Carol, Dave, Alice, Bob, and so on.
What happens if two deals arrive at the exact same time?
n8n processes webhook events sequentially within a single workflow execution queue. Even if Pipedrive sends two webhooks within milliseconds, n8n handles them one at a time, so the counter increments correctly and each deal gets a different rep. There is no race condition with static data.
How do I skip a rep who is out of office?
Add an availability check in the Code node. Maintain a list of active rep indices — either hardcoded or read from a Google Sheet. Wrap the counter logic in a loop that skips unavailable reps:
const reps = [
{ pipedriveUserId: 12345678, slackUserId: "U01AAAA", name: "Alice", active: true },
{ pipedriveUserId: 23456789, slackUserId: "U02BBBB", name: "Bob", active: false },
{ pipedriveUserId: 34567890, slackUserId: "U03CCCC", name: "Carol", active: true },
{ pipedriveUserId: 45678901, slackUserId: "U04DDDD", name: "Dave", active: true },
];
const activeReps = reps.filter(r => r.active);
const staticData = $getWorkflowStaticData('global');
const currentIndex = staticData.roundRobinIndex || 0;
const assignedRep = activeReps[currentIndex % activeReps.length];
staticData.roundRobinIndex = (currentIndex + 1) % activeReps.length;When the rep returns, set their active flag back to true. The counter adjusts automatically since it uses modulo against the active roster length.
Cost
- n8n Cloud Starter: $24/mo for 2,500 executions. Each new deal = 1 execution.
- Self-hosted: Free. Unlimited executions. Requires a server with a public URL for Pipedrive to deliver webhooks.
Looking to scale your AI operations?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.