

How to Send Copper Lead Alerts to Slack with Pipedream
Fires a Slack DM or channel message to the assigned sales rep within seconds of a new lead being created or reassigned in Copper.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Sales teams using Copper as their CRM who want assigned reps notified in Slack the moment a lead lands in their queue.
Not ideal for
Teams that need two-way sync or want to update Copper records from Slack reactions — use a different pattern for that.
Sync type
real-timeUse case type
notificationReal-World Example
A 12-person SaaS sales team gets inbound leads from a web form that feeds Copper. Before this workflow, reps refreshed Copper manually and routinely missed hot leads for 2-3 hours. Now, each rep gets a Slack DM within 10 seconds of assignment, including the lead name, company, phone, and a direct link to the Copper record. First-response time dropped from 140 minutes to under 8.
What Will This Cost?
Drag the slider to your expected monthly volume.
Each platform counts differently — Zapier: 1 task per trigger. Make: 1 operation per module per record. n8n: 1 execution per run.





Prices shown for annual billing. Based on published pricing as of April 2026.
Estimated ROI
1000
min saved/mo
$583
labor value/mo
Free
no platform cost
Based on ~2 min manual effort per operation at $35/hr fully loaded labor cost.
Implementation
Import this workflow directly into Pipedream
Copy the pre-built Pipedream blueprint and paste it straight into Pipedream. All modules, filters, and field mappings are already configured — you just need to connect your accounts.
Before You Start
Make sure you have everything ready.
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Lead Name | name | |
| Assignee ID | assignee_id | |
| Lead ID | id | |
| Event Type | type | |
5 optional fields▸ show
| Company Name | company_name |
| Phone Number | phone_numbers[0].number |
| Lead Status | status |
| Lead Source | source |
| Email Address | email |
Step-by-Step Setup
pipedream.com > Workflows > + New Workflow
Create a new Pipedream workflow
Go to pipedream.com and log in. Click 'Workflows' in the left sidebar, then click the blue '+ New Workflow' button in the top right. Give it a name like 'Copper Lead Assignment → Slack'. You'll land on the workflow canvas with an empty trigger slot at the top.
- 1Click 'Workflows' in the left sidebar
- 2Click '+ New Workflow' in the top right
- 3Type a name: 'Copper Lead Assignment → Slack'
- 4Click 'Create'
Workflow Canvas > Add a trigger > Search 'Copper' > New Lead (Instant)
Add the Copper webhook trigger
Click the grey 'Add a trigger' block. In the search box, type 'Copper' and select it. Choose the trigger event 'New Lead (Instant)' — this uses Copper's native webhook support, so events fire within 2-5 seconds of creation. Pipedream will generate a unique webhook URL for you automatically.
- 1Click the grey 'Add a trigger' block
- 2Type 'Copper' in the search field
- 3Select 'Copper' from the app list
- 4Choose 'New Lead (Instant)' as the trigger event
- 5Click 'Connect Copper Account' and authenticate with your Copper API key
Copper > Settings > Integrations > API & Webhooks > Add Webhook
Register the webhook in Copper
Copy the webhook URL Pipedream generated. In a new tab, go to your Copper account, navigate to Settings > Integrations > API & Webhooks. Click 'Add Webhook', paste the Pipedream URL, and select the events 'Lead Created' and 'Lead Updated'. Save it. Come back to Pipedream and click 'Generate Test Event' or create a test lead in Copper to fire the trigger.
- 1Copy the webhook URL from Pipedream's trigger panel
- 2In Copper, go to Settings > Integrations > API & Webhooks
- 3Click 'Add Webhook'
- 4Paste the Pipedream URL into the endpoint field
- 5Check 'Lead Created' and 'Lead Updated', then click Save
Workflow Canvas > + Add a step > Custom Code > Node.js
Add a Node.js filter step for event type
Click '+ Add a step' below the trigger and choose 'Run Node.js code'. This step checks whether the incoming event is a new lead creation or specifically an assignee change — and exits early if it's an irrelevant update. Without this, every phone number correction or tag change triggers a Slack ping. Paste the filter logic shown in the Pro Tip section.
- 1Click '+ Add a step'
- 2Select 'Custom Code'
- 3Choose 'Run Node.js code'
- 4Paste the filter and assignee-lookup code from the Pro Tip below
- 5Click 'Test' to verify it passes for a lead creation event
Workflow Canvas > + Add a step > Custom Code > Node.js
Look up the assigned rep's name and Slack user ID
Copper returns an assignee as a numeric user ID (e.g., 12345), not a name or email. To send a Slack DM or @mention the right person, you need to resolve that ID. Add another Node.js step that calls the Copper API to fetch the user's email, then calls Slack's users.lookupByEmail API to get their Slack member ID. This is the critical step most tutorials skip.
- 1Click '+ Add a step' below the filter step
- 2Select 'Custom Code' > 'Run Node.js code'
- 3Use the Copper Users API endpoint: GET https://api.copper.com/developer_api/v1/users/{id}
- 4Pass the Copper API key from your connected account as an Authorization header
- 5Call Slack's users.lookupByEmail with the returned email to get the Slack member ID
Workflow Canvas > + Add a step > Slack > Send a Message
Add the Slack send message step
Click '+ Add a step', search for 'Slack', and select the action 'Send a Message'. Connect your Slack account via OAuth — Pipedream will open a Slack authorization window. Set the channel field to the slackUserId from Step 5 prefixed with '@' to send a DM, or hardcode a channel like '#new-leads' for a team channel. Build the message text using the lead fields extracted in Step 4.
- 1Click '+ Add a step'
- 2Search 'Slack' and select it
- 3Choose 'Send a Message' as the action
- 4Click 'Connect Slack Account' and authorize via OAuth
- 5Set Channel to the slackUserId from Step 5 (for DM) or a channel name like '#new-leads'
channel: {{channel}}
ts: {{ts}}
Workflow Canvas > Slack Step > Blocks field
Format the Slack message with Block Kit
Plain text Slack messages work but look poor. In the Slack step, switch the 'Text' field to 'Blocks' and paste a Block Kit JSON payload. Include the lead name as a header, company and phone in a section block, and a button block linking directly to the Copper lead URL (format: https://app.copper.com/companies/{leadId}). This gives reps one-click access to the record without searching.
- 1In the Slack step, find the 'Blocks' input field
- 2Paste the Block Kit JSON (construct this in the Node.js step before passing it to Slack)
- 3Reference the lead name, company, phone, and Copper URL from Step 4's output
- 4Include a fallback text value in the 'Text' field for notification previews
- 5Click 'Test' to preview the rendered message
pipedream.com > Workflows > + New Workflow
Handle lead reassignment events separately
Go back to Pipedream's Workflows list and create a second workflow. This one handles the 'Lead Updated' events where the assignee field specifically changed. Use the same Copper webhook URL (Copper already sends both events there) but add a filter in the code step that checks if the assignee_id in the current payload differs from the previous one. Copper's webhook payload includes a previous_assignee_id field on update events.
- 1Create a second workflow named 'Copper Lead Reassignment → Slack'
- 2Use an HTTP / Webhook trigger (not the Copper app trigger) to receive the same Copper webhook
- 3Add a Node.js filter step that checks: event.type === 'update' && event.assignee_id !== event.previous_assignee_id
- 4Reuse the same rep lookup and Slack message steps from the first workflow
- 5Register this second Pipedream webhook URL in Copper as an additional webhook endpoint
Workflow Canvas > + Add a step > Custom Code > Node.js
Add error handling and a fallback notification
Add a final Node.js step after the Slack action using Pipedream's $.flow.exit and try/catch pattern. If the Slack API call fails (rate limit, invalid user ID, missing scope), catch the error and post a fallback message to a hardcoded admin Slack channel like '#automation-errors'. This prevents leads from being silently dropped. Log the error payload so you can debug the specific lead that failed.
- 1Click '+ Add a step' after the Slack message step
- 2Select 'Custom Code' > 'Run Node.js code'
- 3Wrap the Slack call in a try/catch block
- 4On catch, use the Slack step to post to '#automation-errors' with the error message and lead ID
- 5Click 'Deploy' when done
pipedream.com > Workflows > [Your Workflow] > Deploy
Test end-to-end and deploy
Create a real test lead in Copper and assign it to yourself. Watch the Pipedream event log in real time — you should see the webhook arrive, each step execute green, and the Slack message land within 5-10 seconds. Then reassign the lead to a colleague and confirm the second workflow fires. Once both pass, click 'Deploy' on each workflow to move them from test mode to live.
- 1Create a new lead in Copper and assign it to yourself
- 2Open Pipedream and watch the event log under your workflow
- 3Verify all steps show green checkmarks
- 4Check Slack for the DM or channel message
- 5Click 'Deploy' on both workflows to go live
Paste this into the Node.js code step added in Step 4. It handles event filtering, Copper user resolution, Slack user ID lookup, and Block Kit message construction in one step — so the Slack action step only needs to receive a pre-built payload.
JavaScript — Code Stepimport axios from 'axios';▸ Show code
import axios from 'axios';
export default defineComponent({
async run({ steps, $ }) {... expand to see full code
import axios from 'axios';
export default defineComponent({
async run({ steps, $ }) {
const event = steps.trigger.event.body;
// Exit early for non-assignment update events
if (event.type === 'update') {
const prevAssignee = event.previous_assignee_id ?? null;
const currAssignee = event.assignee_id ?? null;
if (prevAssignee === currAssignee) {
$.flow.exit('Not an assignee change — skipping');
}
}
const isReassignment = event.type === 'update';
const leadId = event.id;
const leadName = event.name || 'Unknown Lead';
const company = event.company_name || '—';
const phone = event.phone_numbers?.[0]?.number || '—';
const status = event.status || '—';
const copperUrl = `https://app.copper.com/companies/${leadId}`;
const assigneeId = event.assignee_id;
if (!assigneeId) {
$.flow.exit('No assignee on this lead — skipping');
}
// Step 1: Resolve Copper user ID → email
let repEmail;
try {
const copperUserRes = await axios({
method: 'GET',
url: `https://api.copper.com/developer_api/v1/users/${assigneeId}`,
headers: {
'X-PW-AccessToken': process.env.COPPER_API_KEY,
'X-PW-Application': 'developer_api',
'X-PW-UserEmail': process.env.COPPER_USER_EMAIL,
'Content-Type': 'application/json',
},
});
repEmail = copperUserRes.data.email;
} catch (err) {
console.error('Failed to fetch Copper user:', err.message);
throw new Error(`Could not resolve Copper user ${assigneeId}`);
}
// Step 2: Resolve email → Slack user ID
let slackUserId;
let slackDisplayName;
try {
const slackRes = await axios({
method: 'GET',
url: 'https://slack.com/api/users.lookupByEmail',
params: { email: repEmail },
headers: { Authorization: `Bearer ${process.env.SLACK_BOT_TOKEN}` },
});
if (!slackRes.data.ok) {
throw new Error(slackRes.data.error);
}
slackUserId = slackRes.data.user.id;
slackDisplayName = slackRes.data.user.real_name;
} catch (err) {
console.error('Slack lookup failed for', repEmail, err.message);
// Fall back to a team channel rather than failing
slackUserId = process.env.SLACK_FALLBACK_CHANNEL;
slackDisplayName = 'Sales Team';
}
// Step 3: Build Block Kit payload
const headerText = isReassignment
? `🔄 Lead Reassigned to You: ${leadName}`
: `🔔 New Lead Assigned: ${leadName}`;
const blocks = [
{
type: 'header',
text: { type: 'plain_text', text: headerText, emoji: true },
},
{
type: 'section',
fields: [
{ type: 'mrkdwn', text: `*Company:*\n${company}` },
{ type: 'mrkdwn', text: `*Phone:*\n${phone}` },
{ type: 'mrkdwn', text: `*Status:*\n${status}` },
{ type: 'mrkdwn', text: `*Assigned To:*\n${slackDisplayName}` },
],
},
{
type: 'actions',
elements: [
{
type: 'button',
text: { type: 'plain_text', text: 'View in Copper', emoji: true },
url: copperUrl,
style: 'primary',
},
],
},
];
return {
slackUserId,
slackDisplayName,
blocks: JSON.stringify(blocks),
fallbackText: `${headerText} — ${company} | ${phone}`,
copperUrl,
leadName,
isReassignment,
};
},
});Going live
Production Checklist
Before you turn this on for real, confirm each item.
Troubleshooting
Common errors and how to fix them.
Frequently Asked Questions
Common questions about this workflow.
Analysis
Use Pipedream for this if your team has at least one person comfortable reading Node.js, even if they're not a full-time developer. The user ID resolution step — converting a Copper numeric assignee ID to a Slack member ID — requires two API calls chained together, and doing that cleanly in Zapier or Make requires awkward workarounds. In Pipedream, it's 20 lines of async/await. The other reason to pick Pipedream: webhook processing is genuinely instant. Copper fires the event, Pipedream receives and executes it in 2-5 seconds, and the rep has a Slack message before they've finished saving the lead. If your team is entirely non-technical and nobody wants to touch code, use Zapier's Copper + Slack integration instead — the user lookup step is harder to build but Zapier's lookup actions can approximate it.
Pipedream's free tier gives you 10,000 credits/month. This workflow burns roughly 30 credits per run (Copper user lookup, Slack user lookup, Slack send). At 50 lead events per day that's 1,500 credits/day or 45,000 credits/month — you'll need the $19/month plan, which includes 100,000 credits. Make's equivalent setup costs $9/month for 10,000 operations and handles the same volume for less. But Make doesn't give you inline Node.js, so the user ID resolution requires a separate HTTP module chain that's fragile to maintain. Zapier's equivalent is $49/month at the volume needed for multi-step Zaps. Pipedream at $19/month is the right price-to-capability ratio for this specific workflow.
Zapier handles the Copper trigger more reliably out of the box — their native Copper integration has been tested against edge cases for years and you won't hit the payload parsing issues Pipedream sometimes surfaces with Copper's nested phone_numbers array. Make's scenario debugger is better than Pipedream's event inspector for visual step-by-step tracing when something breaks. n8n lets you self-host, which matters if your Copper data has GDPR or data residency constraints. Power Automate has no usable Copper connector and would require custom HTTP actions for everything — skip it here. Pipedream still wins for this use case because the code step makes the two-API-lookup pattern clean, the webhook trigger is fastest, and the $19/month plan covers most small sales teams without hitting limits.
Three things you'll hit after setup. First: Copper's webhook fires on every field edit, not just assignments. If a rep updates a phone number, your workflow triggers. The filter step is not optional — without it, reps get 10-20 Slack pings per lead per day. Second: Copper's API rate limit is 600 requests per minute per account. If you bulk-import 500 leads at once (common after a trade show), Copper fires 500 webhooks in under a minute and your user-lookup calls will start hitting 429 errors. Add retry logic with exponential backoff in your code step or set Pipedream's concurrency limit to throttle execution. Third: the Copper Users API occasionally returns a cached stale email if a user recently changed their Copper account email. If a rep reports not receiving alerts, check that their Copper email and Slack email are currently in sync — not just that they matched at setup time.
Ideas for what to build next
- →Add a Slack reply thread for rep acknowledgment — Extend the workflow to capture a Slack reply (or emoji reaction) from the rep and update the Copper lead's status to 'In Progress' via the Copper API — closes the loop so managers can see who has acknowledged their leads.
- →Build a daily digest for unacknowledged leads — Add a second scheduled Pipedream workflow that runs at 9 AM each morning, queries Copper for leads assigned in the last 24 hours still in 'New' status, and posts a digest to #sales-leads — catches anything that slipped through without pinging reps repeatedly.
- →Route high-value leads to a separate #hot-leads channel — Add a conditional branch in the Node.js step that checks the lead's source or a custom Copper field for lead score — leads above a threshold get posted to both the rep's DM and a shared #hot-leads channel so the whole team sees priority prospects.
Related guides
How to Share Notion Meeting Notes to Slack with Pipedream
~15 min setup
How to Share Notion Meeting Notes to Slack with Power Automate
~15 min setup
How to Share Notion Meeting Notes to Slack with n8n
~20 min setup
How to Send Notion Meeting Notes to Slack with Zapier
~8 min setup
How to Share Notion Meeting Notes to Slack with Make
~12 min setup
How to Create Notion Tasks from Slack with Pipedream
~15 min setup