Intermediate~15 min setupCommunication & CRMVerified April 2026
Slack logo
Copper logo

How to Sync Slack Members to Copper with Power Automate

When a new member joins a designated Slack channel, Power Automate fires a webhook, extracts the user's profile data, and creates a contact record in Copper automatically.

Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.

Best for

Teams already in the Microsoft 365 ecosystem who add external partners to Slack channels and need those people in Copper without manual data entry.

Not ideal for

Teams adding more than 50 new contacts per day — at that volume, a batch import via Copper's CSV API is faster and cheaper.

Sync type

real-time

Use case type

sync

Real-World Example

💡

A 20-person consulting firm runs a private Slack channel called #client-partners where they invite every new external stakeholder at project kickoff. Before this flow, an admin manually copied names, emails, and company names into Copper every week — a task that took 30 minutes and often lagged 3-4 days. Now, within 90 seconds of a partner joining the channel, a Copper contact exists with name, email, and a source tag of 'Slack-Onboarded'.

What Will This Cost?

Drag the slider to your expected monthly volume.

/mo
505005K50K

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

Skip the setup

Import this workflow directly into Power Automate

Copy the pre-built Power Automate blueprint and paste it straight into Power Automate. 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.

Power Automate account with a Microsoft 365 plan that includes cloud flows (not just the free Power Automate plan, which disables premium HTTP connector)
Slack account with 'channels:read' and 'users:read.email' OAuth scopes granted — these are required to read channel membership and retrieve email from user profiles
Copper API key — found in Copper under Settings > Integrations > API Keys. You also need the email address tied to your Copper account for the X-PW-UserEmail header
Membership in the target Slack channel using the same Slack account you will authorize in Power Automate — private channels are invisible to users who are not members
HTTP connector access in Power Automate — this is a premium connector and requires a per-user or per-flow Power Automate plan (approximately $15/user/month)

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Contact Namename
Email Addressemails[0].email
Email Categoryemails[0].category
5 optional fields▸ show
Job Titletitle
Phone Numberphone_numbers[0].number
Source Tagtags[0]
Slack Channeltags[1]
Slack User IDcustom_fields[0].value

Step-by-Step Setup

1

make.powerautomate.com > + Create > Automated cloud flow

Create a new Automated cloud flow

Go to make.powerautomate.com and sign in with your Microsoft 365 account. Click '+ Create' in the left sidebar, then select 'Automated cloud flow' from the options on screen. Give the flow a name like 'Slack Channel Member → Copper Contact'. You will be prompted to choose a trigger before the canvas opens.

  1. 1Click '+ Create' in the left sidebar
  2. 2Select 'Automated cloud flow'
  3. 3Enter flow name: 'Slack Channel Member → Copper Contact'
  4. 4Click 'Skip' on the trigger picker — you will add it manually on canvas
What you should see: The flow canvas opens with an empty trigger block at the top labeled 'Choose a trigger'.
Common mistake — Do not choose 'Instant cloud flow' or 'Scheduled cloud flow'. This flow must be Automated so it fires on the Slack event, not on a timer or manual button.
2

Flow Canvas > Trigger Block > Search: Slack > When a new member joins a channel

Add the Slack 'When a new member joins a channel' trigger

Click the empty trigger block on the canvas. The connector search panel opens on the right side. Type 'Slack' in the search bar and select the Slack connector. Scroll through the trigger list until you see 'When a new member joins a channel' — click it. Power Automate will immediately ask you to create or select a Slack Connection.

  1. 1Click the trigger block on the canvas
  2. 2Type 'Slack' in the connector search bar
  3. 3Select the 'Slack' connector
  4. 4Click 'When a new member joins a channel' from the trigger list
What you should see: A trigger configuration card appears showing a 'Channel Name' dropdown and a 'Connection' field at the top.
Common mistake — Power Automate's Slack connector uses polling under the hood for this trigger even though you're in an Automated flow. The poll interval is approximately 1 minute on most Microsoft 365 plans — not instant. Factor this into expectations.
message template
🔔 New Record: {{text}} {{user}}
channel: {{channel}}
ts: {{ts}}
#sales
🔔 New Record: Jane Smith
Company: Acme Corp
3

Trigger Card > Connection > Sign in > Slack OAuth popup

Connect your Slack workspace

Click 'Sign in' in the Connection field at the top of the trigger card. A browser popup opens asking you to authorize Power Automate in your Slack workspace. Sign in with the Slack account that has access to the target channels. After authorization, the popup closes and the Connection field shows your workspace name.

  1. 1Click 'Sign in' in the Connection field
  2. 2Log into Slack in the popup window
  3. 3Click 'Allow' to grant Power Automate access
  4. 4Confirm the popup closes and your workspace name appears in the Connection field
What you should see: The Connection field displays your Slack workspace name (e.g., 'Acme Corp') and the Channel Name dropdown becomes active.
Common mistake — You must authorize as a Slack user who is a member of the target channel. If you authorize as a user who cannot see the channel, the channel will not appear in the dropdown.
Power Automate settings
Connection
Choose a connection…Add
click Add
Slack
Log in to authorize
Authorize Power Automate
popup window
Connected
green checkmark
4

Trigger Card > Channel Name dropdown

Select the target Slack channel

Click the 'Channel Name' dropdown in the trigger card. The list shows every public and private channel your authenticated Slack user belongs to. Select the specific channel you want to monitor — for example, #client-partners. If the channel is private and does not appear, the authorized user needs to be added to that channel first.

  1. 1Click the 'Channel Name' dropdown
  2. 2Scroll or type to find your target channel
  3. 3Select the channel (e.g., #client-partners)
  4. 4Confirm the channel name populates in the field
What you should see: The trigger card shows your selected channel name. The trigger configuration is complete.
Common mistake — Map fields using the variable picker — don't type field names manually. Hand-typed variable names often have invisible spacing errors that produce blank output.
5

Flow Canvas > + New step > Search: Slack > Get user profile

Add a 'Get user profile' Slack action

Click '+ New step' below the trigger. Search for 'Slack' again and this time select the 'Get user profile' action. The trigger only passes a User ID — not a name or email. This action takes that User ID and returns the full profile including display name, real name, email, and title. Map the 'User ID' field using the dynamic content picker: select 'User' from the trigger's output tokens.

  1. 1Click '+ New step'
  2. 2Search for 'Slack' in the action picker
  3. 3Select 'Get user profile'
  4. 4Click the 'User ID' field
  5. 5Select 'User' from the dynamic content panel (this is the member ID from the trigger)
What you should see: The 'Get user profile' action card shows the User ID field populated with the dynamic 'User' token from the trigger.
Common mistake — Slack's 'User' token from the member-join trigger is a User ID (e.g., U0123ABCDE), not a display name. Never skip this step and map the raw ID directly to Copper — it will create a contact named 'U0123ABCDE'.
6

Flow Canvas > + New step > Control > Condition

Add a Condition to filter out bots and guest accounts

Click '+ New step' and add a 'Condition' control action. Set the left side to 'Is Bot' from the 'Get user profile' dynamic outputs. Set the operator to 'is equal to' and the right side to 'false'. This prevents bot accounts (like Zapier bots or GitHub notification bots) from being created as contacts in Copper. In the 'No' branch, all subsequent steps will run; leave the 'Yes' branch empty.

  1. 1Click '+ New step'
  2. 2Select 'Control' from the connector list
  3. 3Click 'Condition'
  4. 4Set left field to 'Is Bot' from dynamic content
  5. 5Set operator to 'is equal to'
  6. 6Set right field value to 'false'
  7. 7Place all remaining steps inside the 'No' (If false) branch
What you should see: A Condition card appears with two branches labeled 'If yes' and 'If no'. The 'If no' branch is where your Copper action will live.
Common mistake — If you skip this filter and a workspace has Slackbot or integration bots in the monitored channel, you will accumulate junk contacts in Copper within days.
Slack
SL
trigger
filter
Condition
matches criteria?
yes — passes through
no — skipped
Copper
CO
notified
7

If No Branch > + Add an action > HTTP

Add an HTTP action to check for duplicate contacts in Copper

Inside the 'If no' branch, click '+ Add an action' and search for 'HTTP'. Select the built-in 'HTTP' action. Copper does not have a native Power Automate connector, so you will call Copper's REST API directly. Set Method to POST, URI to 'https://api.copper.com/developer_api/v1/people/search', and add the required headers and a JSON body to search by email before creating a new contact. This prevents duplicates.

  1. 1Click '+ Add an action' inside the 'If no' branch
  2. 2Search for 'HTTP' and select the HTTP action
  3. 3Set Method to 'POST'
  4. 4Set URI to 'https://api.copper.com/developer_api/v1/people/search'
  5. 5Add Header: 'X-PW-AccessToken' = your Copper API key
  6. 6Add Header: 'X-PW-Application' = 'developer_api'
  7. 7Add Header: 'X-PW-UserEmail' = your Copper account email
  8. 8Add Header: 'Content-Type' = 'application/json'
  9. 9Set Body to: {"emails": [{"email": "<Profile Email from dynamic content>"}]}
What you should see: The HTTP action card shows all headers and the body with the dynamic email token inserted. When tested, it returns a JSON array — empty if no match, or a contact object if one exists.
Common mistake — Your Copper API key is a secret. Do not paste it as plain text in the HTTP action. Store it in Power Automate's 'Environment Variables' or Azure Key Vault and reference it via expression: parameters('CopperAPIKey').
8

If No Branch > + Add an action > Control > Condition

Add a second Condition to skip if contact already exists

Add another 'Condition' control action directly after the HTTP search step. Use the expression editor to check if the HTTP response body is an empty array. Set the left field expression to: 'length(body('HTTP'))' and the operator to 'is equal to' and the value to 0. In the 'If yes' branch (length is 0, meaning no existing contact), place the Copper create action. Leave the 'If no' branch empty.

  1. 1Click '+ Add an action' after the HTTP step
  2. 2Select 'Control' > 'Condition'
  3. 3Click the left field and switch to 'Expression' tab
  4. 4Enter: length(body('HTTP'))
  5. 5Set operator to 'is equal to'
  6. 6Set right value to 0
  7. 7Place the Copper HTTP create action in the 'If yes' branch
What you should see: A second Condition card appears. The expression 'length(body('HTTP')) is equal to 0' confirms no existing Copper contact with that email was found.
Common mistake — Filters are the most common place setups break. Double-check the field name and value exactly match what your app sends — a single capital letter difference will block everything.
9

If Yes Branch > + Add an action > HTTP

Add an HTTP action to create the Copper contact

Inside the second condition's 'If yes' branch, add another HTTP action. This one POSTs to Copper's people endpoint to create the contact. Set Method to POST and URI to 'https://api.copper.com/developer_api/v1/people'. Use the same three headers from Step 7. Build the JSON body using dynamic content from the 'Get user profile' action, mapping real_name to name and profile_email to the emails array.

  1. 1Click '+ Add an action' inside the 'If yes' branch
  2. 2Select HTTP action
  3. 3Set Method to 'POST'
  4. 4Set URI to 'https://api.copper.com/developer_api/v1/people'
  5. 5Add the same three headers as Step 7
  6. 6Set Body using the template in the pro tip section below
What you should see: The HTTP action shows a POST to the Copper people endpoint. When run, the response body will contain the newly created Copper contact object including its numeric ID.
Common mistake — Copper's API requires the 'emails' field to be an array of objects: [{"email": "value", "category": "work"}]. Passing a plain string will return a 422 error.
10

HTTP Create Action > ... > Configure run after > + Add action > Data Operation > Compose

Add error handling with a Compose action for logging

After the create HTTP action, add a 'Configure run after' setting by clicking the three dots on the action. Enable it to run on 'has failed' as well as 'is successful'. Then add a 'Compose' action that captures the HTTP status code and body for logging purposes. This gives you a visible record when a Copper API call fails without stopping the flow entirely.

  1. 1Click the '...' menu on the Copper create HTTP action
  2. 2Select 'Configure run after'
  3. 3Check both 'is successful' and 'has failed'
  4. 4Click '+ Add an action' after the HTTP create step
  5. 5Search for 'Compose' under Data Operations
  6. 6Set Inputs to: {"status": "@{outputs('HTTP_2')['statusCode']}", "body": "@{body('HTTP_2')}"}
What you should see: The Compose action appears with an expression referencing the HTTP action's status code and response body. In the run history, you will see the exact API response for every execution.
11

make.powerautomate.com > My flows > [Flow Name] > Run history

Test the flow end-to-end

Save the flow by clicking 'Save' in the top right. Then open Slack and add a test user (a real person, not a bot) to your monitored channel. Return to the flow's run history page in Power Automate — refresh after 60-90 seconds. You should see a new run appear. Click into it to inspect each action's inputs and outputs. Verify the Copper contact was created by checking Copper's People list.

  1. 1Click 'Save' in the top right of the canvas
  2. 2Open Slack and add a test user to the monitored channel
  3. 3Wait 60-90 seconds
  4. 4Return to make.powerautomate.com > My flows > select your flow
  5. 5Click 'Run history' and refresh
  6. 6Click the latest run to inspect each step's output
  7. 7Open Copper > People to confirm the new contact appears
What you should see: The run history shows a green checkmark on all steps. In Copper, you see a new contact with the correct name, email, and 'Slack-Onboarded' tag.
Common mistake — If the run history shows no runs at all after 2 minutes, the Slack connection may have been made with a user who is not in the channel. Re-check the connection and channel selection in Step 3-4.

Paste this into the 'Body' field of the Copper create HTTP action (Step 9). It uses Power Automate expressions to build the full Copper API payload, handle null values gracefully, and stamp the source tag. Switch to 'Expression' mode in the Body field, or paste into a Compose action first and reference that output.

JavaScript — Code Step{
▸ Show code
{
  "name": "@{body('Get_user_profile')?['real_name']}",
  "emails": [

... expand to see full code

{
  "name": "@{body('Get_user_profile')?['real_name']}",
  "emails": [
    {
      "email": "@{body('Get_user_profile')?['profile']?['email']}",
      "category": "work"
    }
  ],
  "title": "@{if(empty(body('Get_user_profile')?['profile']?['title']), null, body('Get_user_profile')?['profile']?['title'])}",
  "phone_numbers": [
    {
      "number": "@{body('Get_user_profile')?['profile']?['phone']}",
      "category": "work"
    }
  ],
  "tags": [
    "Slack-Onboarded",
    "@{triggerBody()?['channel']}"
  ],
  "custom_fields": [
    {
      "custom_field_definition_id": 123456,
      "value": "@{body('Get_user_profile')?['id']}"
    }
  ]
}
Power Automate
▶ Test flow
executed
Slack
Copper
Copper
🔔 notification
received

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

VerdictWhy n8n for this workflow

Use Power Automate for this if your organization is already paying for Microsoft 365 E3 or above and your team is not comfortable writing code. The per-user Power Automate plan at $15/month covers the HTTP connector you need for Copper's API, and IT will already know how to govern it. You also get native audit logging and run history inside the same admin portal the rest of your Microsoft stack uses. If your team uses Make or n8n instead, pick those — this specific flow is not complex enough to justify Power Automate on its own merits.

Cost

Cost math: this flow fires once per new channel member. A typical team adding 30 external partners per month runs 30 flow executions — well inside Power Automate's 40,000 runs/month included in a Microsoft 365 Business Premium plan. If you are on a standalone Power Automate per-user plan at $15/month, those 30 runs cost effectively nothing. The HTTP connector is premium, so you cannot use the free Power Automate tier. If you are not already paying for a Microsoft plan that includes it, Make handles the same flow for free up to 1,000 operations per month — and since each contact sync costs roughly 4 operations in Make, you can process 250 contacts/month for $0.

Tradeoffs

Make's Slack module has a proper 'Watch Channel Members' module that uses webhooks, not polling — contacts appear in Copper in under 5 seconds vs. up to 60 seconds in Power Automate. Zapier has both apps natively connected and requires zero HTTP knowledge, but at $0.10 per task and 2 tasks per run, 30 contacts/month costs $0.60 — trivial, but it adds up at scale and Zapier offers no duplicate-checking step without a Formatter workaround. n8n gives you full JavaScript in a Code node so you can handle edge cases (blank emails, null names, custom field resolution) without fighting expression syntax — if you self-host n8n, this entire flow costs $0/month. Power Automate is still right if Microsoft governance, SSO, and admin visibility matter to your IT department more than raw speed or cost.

Three things you will hit after setup: First, the Slack 'users:read.email' scope is not always granted by default in enterprise Slack workspaces with strict app policies. Your Slack admin may need to explicitly approve Power Automate as an app before emails come through. Second, Copper's People API silently ignores phone_numbers entries where the number field is an empty string — it does not return an error, it just drops the field. Always check the created contact manually for the first few runs. Third, Power Automate's run history only retains 28 days of execution logs by default. If you need longer audit trails, add a SharePoint list write or Azure Table Storage log step to capture every run's outcome permanently.

Ideas for what to build next

  • Add Copper Lead AssignmentAfter the contact is created, add a second Copper API call to assign the contact to a specific owner based on which Slack channel they joined — for example, contacts from #enterprise-partners go to your enterprise sales rep.
  • Post a Slack confirmation messageAdd a Slack 'Post message' action at the end of the flow to notify a #crm-updates channel with the new contact's name and Copper profile URL, so the team knows the record exists without logging into Copper.
  • Build the reverse sync from Copper to SlackCreate a second flow that watches for new Copper contacts tagged 'Slack-Onboarded' and sends the sales rep a Slack DM with a direct link to the contact record, closing the loop between both tools.

Related guides

Was this guide helpful?
Slack + Copper overviewPower Automate profile →