Skip to content
Default help center home
Default help center home

How to Bulk Sync Slack Channel IDs to Salesforce with Default

Use Case:

Automatically populate Salesforce Account records with their corresponding Slack channel IDs.


The Problem

Many B2B companies use Slack Connect channels to communicate with customers and internal channels to discuss accounts. But there's no easy way to link these channels to your CRM records.

What we wanted:

  • Store the External Slack Channel ID (customer-facing Slack Connect channels) on each Account

  • Store the Internal Slack Channel ID (internal team channels about that customer) on each Account

  • Do this for 500+ existing channels in bulk, then keep it updated going forward


The Solution Overview

We built a Default workflow that:

  1. Receives channel data via webhook

  2. Uses AI to parse the channel name into an Account name

  3. Matches against Salesforce Account records

  4. Updates the appropriate Slack Channel ID field

  5. Notifies us of any unmatched channels for manual review

Then we wrote a simple Python script to send all existing channels through the workflow.

Result: 567 channels synced in under 30 seconds, with only ~35 needing manual matching.


Prerequisites

  • Default account with Salesforce integration connected

  • Slack Bot Token with channels:read scope

  • Two custom fields on your Salesforce Account object:

    • Internal_Slack_Channel_ID__c

    • External_Slack_Channel_ID__c

  • Python 3 installed (for the bulk send script)


Step 1: Define Your Channel Naming Convention

Before building the workflow, document your Slack channel naming patterns. Ours were:

Channel Type

Naming Pattern

Example

External (Slack Connect)

default-{customer_name}

default-companyname

Internal (Team channels)

internal-customer-{customer_name}

internal-customer-companyname

Prospects (Ignore)

default_{customer_name}

default_prospectname

All other channels (Ignore)

general-chat

nyc-office-chat

This consistency is key—the AI parser thrives with predictable patterns to extract Account names accurately.


Step 2: Export All Slack Channels

Slack's API limits results to 1,000 channels per request. We wrote a Python script with cursor-based pagination to fetch all channels:

#!/usr/bin/env python3 """ Fetch all Slack channels using cursor-based pagination. Requires SLACK_BOT_TOKEN environment variable to be set. """ import os import requests import csv from time import sleep SLACK_TOKEN = os.environ.get('SLACK_BOT_TOKEN') def fetch_all_channels(): url = "https://slack.com/api/conversations.list" headers = {"Authorization": f"Bearer {SLACK_TOKEN}"} all_channels = [] cursor = None while True: params = { "types": "public_channel,private_channel", "limit": 1000, "exclude_archived": "true" } if cursor: params["cursor"] = cursor response = requests.get(url, headers=headers, params=params) data = response.json() channels = data.get("channels", []) all_channels.extend(channels) next_cursor = data.get("response_metadata", {}).get("next_cursor", "") if not next_cursor: break cursor = next_cursor sleep(0.5) return all_channels # Save to CSV channels = fetch_all_channels() with open("all_slack_channels.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["Channel ID", "Channel Name"]) for ch in channels: writer.writerow([ch["id"], ch["name"]])

Run it:

export SLACK_BOT_TOKEN="xoxb-your-token-here" python3 fetch_all_slack_channels.py

This outputs all_slack_channels.csv with all your channel IDs and names.


Step 3: Build the Default Workflow

Create a new workflow in Default with the following structure:

Screenshot 2025-12-31 at 6.05.48 PM.png

3.1 Webhook Trigger

Add a Webhook received trigger. This generates a unique URL that will receive channel data.

Screenshot 2025-12-31 at 5.59.37 PM.png

Expected payload structure:

{ "channel_id": "C06769H3H0E", "channel_name": "default-customername", "channel_type": "external" }

3.2 AI Prompt: Account Name Parser

Add an AI Prompt block to extract the Account name from the channel name.

Configuration:

  • Model: gpt-4o-mini (fast and cost-effective)

  • Step Name: Account Name parser

Screenshot 2025-12-31 at 6.02.36 PM.png

Prompt:

You are a data parser. Given a Slack channel name, extract and return ONLY the company/account name in proper title case formatting. Rules: 1. Remove these prefixes if present: "default-", "internal-customer-" 2. Replace dashes (-) and underscores (_) with spaces 3. Remove common suffixes like "_app", "_ai", "_io", "_com" 4. Convert to proper company name casing (e.g., "customername" → "CustomerName", "customer-name" → "Customer Name") 5. Known acronyms should be uppercase: AI, IO, HQ, CRM, API, PDL, RFP 6. Return ONLY the account name, nothing else - no quotes, no explanation Examples: - "default-customername" → CustomerName - "internal-customer-customer-name" → Customer Name - "default-customer-name-ai" → Customer Name AI - "internal-customer-customer-name_app" → Customer Name Channel name: {{ channel_name }}

3.3 Match Salesforce Record

Add a Match Salesforce Record block to find the corresponding Account.

Screenshot 2025-12-31 at 6.04.29 PM.png

Configuration:

  • Type: Account

  • Match Condition: Account Name contains Output from "Account Name parser"

  • Priority Condition: Last Activity = MAX (picks the most recently active account if multiple matches)

3.4 If/Else: Internal or External

Add an If/Else block to route to the correct update action based on channel type.

Screenshot 2025-12-31 at 6.09.47 PM.png

Condition:

  • If channel_type equal to external → Update External Slack Channel ID

  • Else → Update Internal Slack Channel ID

3.5 Update Salesforce Record (External)

For the "Is true" branch, add an Update Salesforce Record block:

Screenshot 2025-12-31 at 6.10.42 PM.png

Configuration:

  • Type: Account

  • Record to update: Previous Account record

  • Field mapping: channel_idExternal Slack Channel ID

3.6 Update Salesforce Record (Internal)

For the "Is false" branch, add another Update Salesforce Record block:

Screenshot 2025-12-31 at 6.10.47 PM.png

Configuration:

  • Type: Account

  • Record to update: Previous Account record

  • Field mapping: channel_idInternal Slack Channel ID

3.7 Send Slack Message (No Match)

For the "Not matched" branch from the Salesforce match step, add a Send Slack Message block to notify your team of channels that couldn't be auto-matched.

Screenshot 2025-12-31 at 6.10.55 PM.png

Configuration:

  • Send to: A designated channel (e.g., #ops-alerts)

  • Message:

    Account not matched {{ channel_id }} {{ channel_name }} {{ channel_type }}

    Step 4: Test the Workflow

    Before bulk sending, test with a single channel using ?mode=test on your webhook URL:

    import requests WEBHOOK_URL = "https://nucleus.default.com/webhooks/YOUR_ID?mode=test" payload = { "channel_id": "C06769H3H0E", "channel_name": "default-customername", "channel_type": "external" } response = requests.post(WEBHOOK_URL, json=payload) print(response.status_code)

    Step 5: Bulk Send All Channels

    Once tested, create a script to send all channels through the workflow:

    #!/usr/bin/env python3 import csv import requests from concurrent.futures import ThreadPoolExecutor, as_completed CSV_PATH = "all_slack_channels.csv" WEBHOOK_URL = "https://nucleus.default.com/webhooks/YOUR_ID" MAX_WORKERS = 10 def classify_channel(channel_name): """Return 'external', 'internal', or None (skip).""" if channel_name.startswith("internal-customer-"): return "internal" elif channel_name.startswith("default-"): return "external" return None def send_to_webhook(channel): payload = { "channel_id": channel["id"], "channel_name": channel["name"], "channel_type": channel["type"] } response = requests.post(WEBHOOK_URL, json=payload, timeout=30) return response.ok # Load and filter channels channels = [] with open(CSV_PATH, 'r') as f: for row in csv.DictReader(f): channel_type = classify_channel(row['Channel Name']) if channel_type: channels.append({ "id": row['Channel ID'], "name": row['Channel Name'], "type": channel_type }) print(f"Sending {len(channels)} channels...") # Send in parallel with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor: futures = [executor.submit(send_to_webhook, ch) for ch in channels] for i, future in enumerate(as_completed(futures), 1): if i % 50 == 0: print(f"Progress: {i}/{len(channels)}") print("Done!")

    Run it:

    python3 bulk_send_channels.py

    Step 6: Handle Unmatched Channels

    Some channels won't match automatically due to:

    • Spelling differences between channel name and Account name

    • Channels for Accounts that don't exist in Salesforce

    • Test/internal channels that aren't real customers

    You'll receive Slack notifications for these. Review each one and either:

    • Manually update the Salesforce Account with the channel ID

    • Ignore if it's not a real customer channel

Screenshot 2025-12-31 at 6.15.23 PM.png

Results

Metric

Count

Total channels processed

567

External channels synced

367

Internal channels synced

200

Auto-matched successfully

~540

Required manual matching

~25

Processing time

< 30 seconds


Going Forward

All new channels created are being stored in the CRM:

When a kick off meeting is booked with customers we can automatically send notifications to internal channels and stamp CRM with kick off date.

Many more automated use cases are now unlocked: e.g. Pushing product usage information into internal channels, warning customers depending on their product usage in the external channel, alerts to customer channels for updates depending on their tier, and many more!