

How to Share Close Prospects to Slack with n8n
When a Close opportunity updates, n8n posts a formatted Slack message with company details, deal value, and conversation history so your team can collaborate before the next call.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Inside sales teams of 3-20 reps who do pre-call research together and need deal context in Slack without leaving the conversation
Not ideal for
Teams that want two-way sync where Slack replies update Close — that requires a separate reverse workflow and a bot user
Sync type
real-timeUse case type
notificationReal-World Example
A 12-person SaaS sales team uses this to post into #prospect-research every time a Close opportunity moves to 'Discovery Scheduled' status. Before this, reps emailed each other asking 'anyone know anything about Acme Corp?' and got answers — if they got them at all — 2 hours before the call. Now the Slack post goes up the moment the deal updates, includes the last 3 email threads, and the team has context waiting before the rep even opens their calendar.
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 n8n
Copy the pre-built n8n blueprint and paste it straight into n8n. 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 | ||
| Opportunity ID | data.id | |
| Lead ID | data.lead_id | |
| Opportunity Status Label | data.status_label | |
| Deal Value | data.value | |
| Company Name | display_name | |
6 optional fields▸ show
| Company Website | url |
| Primary Contact Name | contacts[0].display_name |
| Primary Contact Title | contacts[0].title |
| Recent Activity Summary | data[].type + data[].date_created + data[].body |
| Assigned Rep Name | data.assigned_to_name |
| Expected Close Date | data.date_won |
Step-by-Step Setup
n8n Dashboard > Workflows > New Workflow
Create a new n8n workflow
Log in to your n8n instance at your self-hosted URL or n8n.cloud. Click the orange 'New Workflow' button in the top right of the Workflows dashboard. Give it a clear name like 'Close → Slack Prospect Research' so it's findable later. You'll land on an empty canvas with a single '+' node in the center.
- 1Click 'New Workflow' in the top-right corner
- 2Click the pencil icon next to 'My Workflow' and rename it to 'Close → Slack Prospect Research'
- 3Press Enter to save the name
Canvas > + Node > Webhook
Add a Webhook trigger node
Click the '+' node on the canvas to open the node picker. Search for 'Webhook' and select it. Set the HTTP Method to POST. n8n will generate a unique webhook URL — copy it now, you'll paste it into Close in the next step. Set Authentication to 'None' for now; Close webhooks don't support custom auth headers on the free tier, but you can add header validation later using n8n's Header Auth option.
- 1Click the '+' node on the canvas
- 2Type 'Webhook' in the search box and select the Webhook node
- 3Set HTTP Method to 'POST'
- 4Copy the 'Test URL' shown in the node panel — you'll use this in Close
Close > Settings > Integrations > Webhooks > Add Webhook
Configure the Close webhook
In Close, go to Settings > Integrations > Webhooks. Click 'Add Webhook'. Paste the n8n Test URL into the Endpoint URL field. Under 'Events', check 'opportunity.updated' — this fires whenever a deal changes status, value, or any field. You can also check 'opportunity.created' if you want new deals to trigger research posts immediately. Click Save.
- 1Navigate to Settings in the Close left sidebar
- 2Click 'Integrations', then select 'Webhooks'
- 3Click 'Add Webhook'
- 4Paste the n8n Test URL into the Endpoint URL field
- 5Check 'opportunity.updated' under Events, then click Save
n8n Canvas > Webhook Node > Test Workflow
Capture a test payload from Close
Back in n8n, click 'Test Workflow' to put the Webhook node into listening mode. In Close, open an existing opportunity and make a small change — change the status or add $1 to the value — then save it. Switch back to n8n within 60 seconds. The Webhook node should show a green checkmark and display the raw JSON payload Close sent. Expand the data to see fields like opportunity_id, status_label, value, and lead_id.
- 1Click 'Test Workflow' at the top of the canvas
- 2Switch to Close and update any field on a test opportunity
- 3Return to n8n and wait for the green checkmark to appear on the Webhook node
- 4Click the Webhook node to inspect the incoming JSON payload
Canvas > + Node > IF
Add an IF node to filter by status
Click '+' after the Webhook node and add an 'IF' node. Set Condition to: Value 1 = the expression '{{ $json.data.status_label }}', Operation = 'Equal', Value 2 = the status name you care about — for example, 'Discovery Scheduled'. This prevents every minor field update from flooding your Slack channel. Connect the 'True' branch to the next node. Ignore the 'False' branch — n8n will stop execution there automatically.
- 1Click '+' after the Webhook node
- 2Search for 'IF' and select the IF node
- 3Click 'Add Condition'
- 4Set Value 1 to '{{ $json.data.status_label }}' using the expression editor
- 5Set Operation to 'Equal' and Value 2 to your target status, e.g. 'Discovery Scheduled'
Canvas > + Node > HTTP Request
Fetch full lead details from Close API
The webhook payload contains an opportunity_id and lead_id but not the full company name, website, or contact details. Add an HTTP Request node to fetch the complete lead record. Set Method to GET, URL to 'https://api.close.com/api/v1/lead/{{ $json.data.lead_id }}/', and under Authentication choose 'Basic Auth' with your Close API key as the username and a blank password. This returns the full lead object with contacts, company details, and activity counts.
- 1Click '+' after the IF node's true branch
- 2Search for 'HTTP Request' and select it
- 3Set Method to 'GET'
- 4Set URL to 'https://api.close.com/api/v1/lead/{{ $json.data.lead_id }}/'
- 5Under Authentication, select 'Basic Auth', enter your Close API key as Username, leave Password blank
Canvas > + Node > HTTP Request (second)
Fetch recent activity from Close API
Add a second HTTP Request node to pull the last 5 activities (emails, calls, notes) for this lead. Set Method to GET and URL to 'https://api.close.com/api/v1/activity/?lead_id={{ $node["HTTP Request"].json["id"] }}&_limit=5'. Use the same Basic Auth credentials. This gives you the conversation history you'll include in the Slack message so your team has real context — not just the deal value.
- 1Click '+' after the first HTTP Request node
- 2Add another HTTP Request node
- 3Set Method to 'GET'
- 4Set URL to 'https://api.close.com/api/v1/activity/?lead_id={{ $node["HTTP Request"].json["id"] }}&_limit=5'
- 5Apply the same Basic Auth credentials as the previous node
Canvas > + Node > Code
Build the Slack message with a Code node
Add a Code node after the second HTTP Request. This is where you format the Slack Block Kit message combining data from the webhook, lead record, and activity history. Use $input.all() to access all previous node outputs by name. The Code node lets you produce a single clean message object with the lead name, deal value, company URL, contact names, and a bulleted activity summary. Paste the code from the Pro Tip section below.
- 1Click '+' after the second HTTP Request node
- 2Search for 'Code' and select the Code node
- 3Set Language to 'JavaScript'
- 4Paste the Pro Tip code into the code editor
- 5Click 'Test Step' to verify the output includes a formatted 'blocks' array
This Code node runs after both Close API calls and formats all the data into a Slack Block Kit message. Paste it into the Code node (step 8) replacing all default content. It reads from the Webhook node, the first HTTP Request (lead details), and the second HTTP Request (activities) by node name.
JavaScript — Code Node// n8n Code Node — Close Prospect Research → Slack Block Kit▸ Show code
// n8n Code Node — Close Prospect Research → Slack Block Kit // Reads from: Webhook node, 'Fetch Lead' HTTP node, 'Fetch Activities' HTTP node const webhookData = $node['Webhook'].json.data;
... expand to see full code
// n8n Code Node — Close Prospect Research → Slack Block Kit
// Reads from: Webhook node, 'Fetch Lead' HTTP node, 'Fetch Activities' HTTP node
const webhookData = $node['Webhook'].json.data;
const lead = $node['Fetch Lead'].json;
const activitiesResponse = $node['Fetch Activities'].json;
const activities = activitiesResponse.data || [];
// Format deal value from cents to dollars
const dealValue = webhookData.value
? '$' + (webhookData.value / 100).toLocaleString('en-US', { minimumFractionDigits: 0 })
: 'Value not set';
// Get primary contact
const primaryContact = lead.contacts && lead.contacts.length > 0
? `${lead.contacts[0].display_name || 'Unknown'}${lead.contacts[0].title ? ', ' + lead.contacts[0].title : ''}`
: 'No contact on record';
// Strip HTML and truncate activity bodies
function cleanBody(text, maxLength = 180) {
if (!text) return 'No content';
const stripped = text.replace(/<[^>]*>/g, '').replace(/\s+/g, ' ').trim();
return stripped.length > maxLength ? stripped.substring(0, maxLength) + '...' : stripped;
}
// Build activity summary lines (last 3 activities)
const activityLines = activities.slice(0, 3).map(act => {
const typeEmoji = act._type === 'Email' ? '📨' : act._type === 'Call' ? '📞' : '📝';
const date = act.date_created ? act.date_created.substring(0, 10) : 'Unknown date';
const preview = cleanBody(act.body || act.note || act.subject || '');
return `${typeEmoji} *${act._type}* (${date}): ${preview}`;
});
const activityText = activityLines.length > 0
? activityLines.join('\n')
: '_No recent activity recorded_';
// Deep link to Close opportunity
const closeUrl = `https://app.close.com/opportunity/${webhookData.id}/`;
// Assemble Block Kit blocks
const blocks = [
{
type: 'header',
text: {
type: 'plain_text',
text: `🔍 Research Request: ${lead.display_name || 'Unknown Company'}`,
emoji: true
}
},
{
type: 'section',
fields: [
{ type: 'mrkdwn', text: `*Status:*\n${webhookData.status_label}` },
{ type: 'mrkdwn', text: `*Deal Value:*\n${dealValue}` },
{ type: 'mrkdwn', text: `*Assigned Rep:*\n${webhookData.assigned_to_name || 'Unassigned'}` },
{ type: 'mrkdwn', text: `*Website:*\n${lead.url ? `<${lead.url}|${lead.url}>` : 'Not on record'}` }
]
},
{
type: 'section',
text: { type: 'mrkdwn', text: `*Primary Contact:*\n${primaryContact}` }
},
{ type: 'divider' },
{
type: 'section',
text: { type: 'mrkdwn', text: `*Recent Activity:*\n${activityText}` }
},
{ type: 'divider' },
{
type: 'section',
text: {
type: 'mrkdwn',
text: '💬 *Drop your research, intel, or talking points as a thread reply below.*'
},
accessory: {
type: 'button',
text: { type: 'plain_text', text: 'Open in Close', emoji: true },
url: closeUrl,
action_id: 'open_close_opportunity'
}
}
];
return [{
json: {
channel: '#prospect-research',
text: `Research request: ${lead.display_name} — ${webhookData.status_label}`,
blocks: blocks
}
}];Canvas > + Node > Slack > Message > Post
Add and configure the Slack node
Add a Slack node after the Code node. For Resource, select 'Message'. For Operation, select 'Post'. Connect your Slack credentials using OAuth2 — click 'Create New Credential' and follow the OAuth flow to authorize your workspace. Set Channel to your target channel name, e.g. '#prospect-research'. For the message content, switch to 'Send Blocks' mode and reference '{{ $json.blocks }}' from the Code node output to send the fully formatted Block Kit message.
- 1Click '+' after the Code node
- 2Search for 'Slack' and select it
- 3Set Resource to 'Message' and Operation to 'Post'
- 4Click 'Create New Credential' and complete the Slack OAuth2 authorization
- 5Set Channel to '#prospect-research' (or your channel name)
- 6Enable 'Blocks' toggle and set value to '{{ $json.blocks }}'
Node Settings > On Error > Continue (for HTTP nodes) | Canvas > Error Branch > Slack
Add error handling with a node fallback
Click on each HTTP Request node and enable the 'Continue on Fail' option in the node settings panel. Then add a second Slack node connected to the error output of your main Slack node — set its channel to '#sales-ops-alerts' and message to 'Close→Slack workflow failed for lead {{ $json.data.lead_id }}. Check n8n execution log.' This way a Close API timeout doesn't silently kill the research post without anyone knowing.
- 1Click each HTTP Request node, open Settings tab, set 'On Error' to 'Continue'
- 2Click the red error dot on the main Slack node and drag to a new Slack node
- 3Configure the error Slack node to post to '#sales-ops-alerts'
- 4Set the error message text using the expression '{{ $json.message }}'
n8n Canvas > Top-right toggle > Active | Close > Settings > Webhooks > Edit
Activate the workflow with the production webhook URL
Go back to your Webhook node and copy the 'Production URL' (different from the Test URL you used earlier). In Close, edit the webhook you created in step 3 and replace the Test URL with this Production URL. Back in n8n, toggle the workflow from 'Inactive' to 'Active' using the switch in the top right of the canvas. The workflow now runs automatically without you clicking 'Test Workflow' each time.
- 1Click the Webhook node and copy the 'Production URL'
- 2In Close, go to Settings > Integrations > Webhooks and click Edit on your webhook
- 3Replace the Test URL with the Production URL and click Save
- 4In n8n, click the Inactive/Active toggle in the top right to activate the workflow
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 n8n for this if your team already self-hosts infrastructure and wants full control over what data gets logged and where. The two-API-call pattern here (one for lead details, one for activity history) works cleanly in n8n because you can reference any previous node's output by name with $node['NodeName'].json — no workarounds needed. You also get the Code node for real formatting logic, which matters when you're building Block Kit messages with conditional fields and stripped HTML. The one scenario where you'd pick a different platform: if your sales ops team has zero JavaScript experience and needs to change the message format themselves without a developer. In that case, Make's visual data mapping UI would let a non-coder update the Slack template by clicking fields instead of editing code.
The cost math is straightforward. This workflow runs 3 node executions per trigger: the IF check, the two HTTP Requests, and the Code + Slack nodes — call it 5 executions total per Close event. At 50 deal updates per month that match your status filter, that's 250 executions monthly. n8n Cloud's Starter plan gives you 2,500 executions per month for $20/month, making this effectively free until you hit ~500 matching deal events per month. Self-hosted n8n has no execution limits — just your server cost. Compare that to Zapier, where this workflow would be a multi-step Zap counting as 4 tasks per run — 50 events would consume 200 tasks, burning through the free 100-task tier in two weeks.
Zapier has one genuine advantage here: its Close integration is pre-built with a 'New Opportunity' trigger that requires zero webhook configuration in Close — just click and authenticate. Setup is 8 minutes versus 20 minutes in n8n. Make's strength is the HTTP module with built-in pagination controls, which matters if you later expand to pulling 50+ activities per lead. Pipedream has a Close npm package and gives you full Node.js with real npm packages, so you could import a Slack Block Kit builder library and skip writing the block structure manually. Power Automate has no maintained Close connector at all — you'd be doing raw HTTP calls anyway, so there's no UI advantage over n8n. n8n is still the right call here because the self-hosted option eliminates per-task pricing entirely, and the Code node handles the HTML stripping and message formatting that would require multiple Zapier Formatter steps or Make modules.
Three things you'll hit after going live. First, Close's webhook delivery is not guaranteed to arrive in under 5 seconds — in practice it's usually 2-8 seconds, but during Close API incidents it can delay 5-10 minutes or retry up to 3 times. Your Slack message might appear late or in triplicate. The duplicate fix in troubleshooting entry 5 handles this. Second, the activity API endpoint returns activities in reverse-chronological order, but the _type field uses inconsistent casing across activity types — sometimes 'Email', sometimes 'EmailThread'. Your Code node regex should normalize this with a toLowerCase() check or it will display raw inconsistent labels. Third, Close deals with contacts that have multiple email addresses return all of them in the contacts[0].emails array — if you try to display contacts[0].emails directly in Slack you'll get '[object Object]'. Always map to contacts[0].emails[0].email for the primary address.
Ideas for what to build next
- →Post a digest of open research requests daily — Add a second scheduled workflow that runs at 8 AM each morning, queries Close for all opportunities in 'Discovery Scheduled' status updated in the last 24 hours, and posts a single digest message to Slack — instead of individual pings throughout the day.
- →Write Slack thread replies back to Close as notes — Build a reverse workflow using Slack's Events API to capture thread replies on the research posts and write them back to the Close lead as notes via POST to api.close.com/api/v1/activity/note/ — so insights don't stay locked in Slack.
- →Add LinkedIn and Clearbit enrichment between Close fetch and Slack post — Insert an HTTP Request node to Clearbit's Enrichment API between the Close lead fetch and the Code node — pass the company domain and append employee count, industry, and funding stage to the Slack message so the team gets enriched data they can't see in Close.
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