

How to Send Daily Close Pipeline Updates to Slack with n8n
Every morning at a set time, n8n pulls pipeline metrics, overdue tasks, and upcoming activities from Close CRM and posts a formatted summary to your team's Slack channel.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Sales managers at 5-30 person inside sales teams who want reps to see pipeline health and task deadlines without logging into Close every morning.
Not ideal for
Teams that need real-time deal alerts as they happen — use a webhook-triggered workflow for that instead.
Sync type
scheduledUse case type
reportingReal-World Example
A 12-person SaaS sales team sends a 9 AM summary to #pipeline-daily showing each rep's open opportunities, overdue calls, and deals closing this week. Before this workflow, managers ran the same Close search manually each morning, copy-pasted numbers into Slack, and still missed overdue tasks half the time. Now the message is waiting in Slack before standup starts.
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 Value | value | |
| Opportunity Status Label | status_label | |
| Assigned User ID | user_id | |
| Lead Name | lead_name | |
| Task Due Date | due_date | |
| Task Assigned To | assigned_to | |
| User Display Name | display_name | |
| Opportunity Count per Rep | ||
2 optional fields▸ show
| Expected Close Date | date_won |
| Task Text | text |
Step-by-Step Setup
n8n Canvas > + Node > Schedule Trigger
Create a new n8n workflow with a Schedule trigger
Open n8n and click the orange 'New Workflow' button in the top right. In the canvas that appears, click the '+' node and search for 'Schedule Trigger'. This node controls when your pipeline summary fires — you will set it to run once per day. Click on the Schedule Trigger node to open its settings panel on the right.
- 1Click 'New Workflow' in the top right of the n8n dashboard
- 2Click the '+' icon in the center of the blank canvas
- 3Type 'Schedule' in the search bar and select 'Schedule Trigger'
- 4In the right panel, set 'Trigger Interval' to 'Days'
- 5Set 'Hour' to 8 and 'Minute' to 0 to fire at 8:00 AM server time
n8n Sidebar > Settings > Credentials > New Credential > Close.io API
Add your Close API credentials to n8n
Before you can pull data from Close, n8n needs your API key. Go to Settings > Credentials in the n8n sidebar. Click 'New Credential', search for 'Close.io', and paste in your Close API key. Close generates API keys per user — log into Close, go to Settings > API Keys, and create a new key with read access.
- 1Open the left sidebar in n8n and click 'Settings'
- 2Click 'Credentials' then 'New Credential'
- 3Search for 'Close.io' and select the Close.io API credential type
- 4Paste your Close API key into the 'API Key' field
- 5Click 'Save' and confirm the green 'Connection tested successfully' message appears
n8n Canvas > + Node > HTTP Request
Add an HTTP Request node to pull open opportunities from Close
n8n has a native Close.io node, but it has limited query support for pipeline reporting. Use the HTTP Request node instead — it gives you access to Close's full search API. Add an HTTP Request node connected to the Schedule Trigger. Set the method to GET and the URL to Close's opportunity search endpoint. You will filter for open opportunities in the current period.
- 1Click the '+' button to the right of the Schedule Trigger node
- 2Search for 'HTTP Request' and select it
- 3Set 'Method' to GET
- 4Set 'URL' to https://api.close.com/api/v1/opportunity/?status_type=active&_order_by=date_updated&_limit=100
- 5Under 'Authentication', select 'Basic Auth', enter your Close API key as the username, and leave the password blank
- 6Click 'Execute Node' to test — you should see raw JSON with opportunity records
n8n Canvas > + Node (from Schedule Trigger) > HTTP Request
Add a second HTTP Request node to pull overdue tasks
Connect a second HTTP Request node to the Schedule Trigger in parallel — this one fetches tasks that are past due. In Close, tasks are queried via the task endpoint with a date filter. You want tasks where the due date is before today and the status is not complete. This gives you the overdue activity count per rep.
- 1Click the Schedule Trigger node, then click the '+' icon that appears below it to add a parallel branch
- 2Add a second HTTP Request node
- 3Set 'Method' to GET
- 4Set 'URL' to https://api.close.com/api/v1/task/?is_complete=false&_due_date__lt={{ $now.toISO().slice(0,10) }}&_limit=200
- 5Apply the same Basic Auth credentials as the previous node
- 6Click 'Execute Node' — you should see overdue task records with fields including assigned_to, due_date, lead_name, and text
n8n Canvas > + Node (from Schedule Trigger) > HTTP Request
Add an HTTP Request node to fetch Close users for name resolution
To show rep names in Slack instead of user IDs, you need a list of Close users and their IDs. Add a third HTTP Request node, also connected to the Schedule Trigger in parallel. This call returns your organization's users with their id and display_name fields. The Code node merges this list with the task and opportunity data.
- 1Add a third HTTP Request node from the Schedule Trigger
- 2Set 'Method' to GET
- 3Set 'URL' to https://api.close.com/api/v1/me/ — first confirm your own user, then use https://api.close.com/api/v1/organization/ to get the org ID
- 4For full user list, set URL to https://api.close.com/api/v1/user/?_limit=100
- 5Apply the same Basic Auth credentials
- 6Execute the node and confirm you see user objects with id and display_name fields
n8n Canvas > + Node > Merge > Mode: Merge by Position
Add a Merge node to combine all three API responses
Now that you have three parallel data streams — opportunities, tasks, and users — you need to combine them before processing. Add a Merge node to the canvas. Connect all three HTTP Request nodes into the Merge node. Set the Merge mode to 'Merge by Position' — this passes all three datasets through as separate input arrays that the Code node can reference by index.
- 1Click the '+' on any empty canvas area and search for 'Merge'
- 2Drag the output of the Opportunities HTTP Request node to the first input of the Merge node
- 3Drag the output of the Tasks HTTP Request node to the second input
- 4Drag the output of the Users HTTP Request node to the third input
- 5Set 'Mode' to 'Merge by Position'
- 6Click 'Execute Node' — confirm the output shows three separate items
n8n Canvas > + Node > Code > Mode: Run Once for All Items
Add a Code node to build the Slack message
This is the core of the workflow. Add a Code node connected to the Merge node. Set it to 'Run Once for All Items' mode. The code extracts opportunity totals by rep, counts overdue tasks per rep, resolves user IDs to names, and assembles a formatted Slack Block Kit message. Paste the code from the Pro Tip section below into the code editor. After pasting, click 'Execute Node' to preview the message output.
- 1Add a Code node connected to the Merge node
- 2In the right panel, change 'Mode' to 'Run Once for All Items'
- 3Delete the default placeholder code
- 4Paste the full code from the Pro Tip section into the editor
- 5Click 'Execute Node' and inspect the output — it should show a blocks array with formatted Slack sections
Paste this into the Code node set to 'Run Once for All Items' mode. It reads all three Merge inputs, builds a rep lookup map from Close user IDs, aggregates opportunity values and counts per rep, counts overdue tasks per rep, and returns a Slack Block Kit blocks array ready to pass directly to the Slack node's Blocks field.
JavaScript — Code Node// n8n Code Node — Run Once for All Items▸ Show code
// n8n Code Node — Run Once for All Items // Expects Merge node inputs: [0] opportunities, [1] tasks, [2] users const allItems = $input.all();
... expand to see full code
// n8n Code Node — Run Once for All Items
// Expects Merge node inputs: [0] opportunities, [1] tasks, [2] users
const allItems = $input.all();
// Extract raw data arrays from each Merge input
const opportunities = allItems[0]?.json?.data || [];
const tasks = allItems[1]?.json?.data || [];
const users = allItems[2]?.json?.data || [];
// Build user ID -> display name lookup map
const userMap = {};
for (const user of users) {
userMap[user.id] = user.display_name || 'Unknown Rep';
}
// Aggregate opportunities per rep
const repPipeline = {};
for (const opp of opportunities) {
const repId = opp.user_id;
const repName = userMap[repId] || repId;
if (!repPipeline[repId]) {
repPipeline[repId] = { name: repName, oppCount: 0, totalValue: 0, overdueTasks: [], closingThisWeek: 0 };
}
repPipeline[repId].oppCount += 1;
repPipeline[repId].totalValue += opp.value || 0;
// Flag deals closing within 7 days
if (opp.date_won) {
const closeDate = new Date(opp.date_won);
const today = new Date();
const diffDays = (closeDate - today) / (1000 * 60 * 60 * 24);
if (diffDays >= 0 && diffDays <= 7) {
repPipeline[repId].closingThisWeek += 1;
}
}
}
// Aggregate overdue tasks per rep
const today = new Date();
for (const task of tasks) {
const repId = task.assigned_to;
const repName = userMap[repId] || repId;
if (!repPipeline[repId]) {
repPipeline[repId] = { name: repName, oppCount: 0, totalValue: 0, overdueTasks: [], closingThisWeek: 0 };
}
const taskDue = new Date(task.due_date);
if (taskDue < today) {
repPipeline[repId].overdueTasks.push(`${task.text || 'Task'} (${task.lead_name || 'Unknown Lead'})`);
}
}
// Format currency
const fmt = (val) => '$' + val.toLocaleString('en-US', { maximumFractionDigits: 0 });
// Build Slack Block Kit blocks array
const blocks = [];
// Header block
blocks.push({
type: 'header',
text: { type: 'plain_text', text: `📊 Pipeline Summary — ${today.toDateString()}`, emoji: true }
});
blocks.push({ type: 'divider' });
// One section per rep (cap at 12 reps to stay under 50-block limit)
const reps = Object.values(repPipeline).slice(0, 12);
for (const rep of reps) {
const overdueIcon = rep.overdueTasks.length > 0 ? ':red_circle:' : ':white_check_mark:';
const closingNote = rep.closingThisWeek > 0 ? ` | :fire: ${rep.closingThisWeek} closing this week` : '';
blocks.push({
type: 'section',
text: {
type: 'mrkdwn',
text: `*${rep.name}* — ${rep.oppCount} open deals | ${fmt(rep.totalValue)} pipeline${closingNote} | ${overdueIcon} ${rep.overdueTasks.length} overdue task(s)`
}
});
if (rep.overdueTasks.length > 0) {
blocks.push({
type: 'context',
elements: [{
type: 'mrkdwn',
text: `Overdue: ${rep.overdueTasks.slice(0, 3).join(' · ')}${rep.overdueTasks.length > 3 ? ` +${rep.overdueTasks.length - 3} more` : ''}`
}]
});
}
}
blocks.push({ type: 'divider' });
blocks.push({
type: 'context',
elements: [{ type: 'mrkdwn', text: 'Pulled from Close CRM · Updates daily at 8 AM' }]
});
return [{ json: { blocks } }];channel: {{channel}}
ts: {{ts}}
n8n Sidebar > Settings > Credentials > New Credential > Slack API
Add your Slack credentials to n8n
Go to Settings > Credentials in the n8n sidebar and create a new Slack credential. n8n supports both OAuth2 and Bot Token authentication for Slack. Use a Bot Token — create a Slack app at api.slack.com/apps, add the chat:write scope, install the app to your workspace, and copy the Bot User OAuth Token. Paste it into the Slack credential field in n8n.
- 1Go to api.slack.com/apps and click 'Create New App' > 'From scratch'
- 2Name it 'Pipeline Bot' and select your workspace
- 3Under 'OAuth & Permissions', add the bot scope chat:write
- 4Click 'Install to Workspace', authorize, and copy the 'Bot User OAuth Token' (starts with xoxb-)
- 5In n8n, go to Settings > Credentials > New Credential > Slack API and paste the token
- 6Invite the bot to your target Slack channel with /invite @Pipeline Bot
n8n Canvas > + Node > Slack > Message > Send
Add a Slack node to post the pipeline summary
Add a Slack node connected to the Code node. Set the operation to 'Message > Send'. Enter the channel ID (not the channel name — use the ID from the channel's Slack URL or right-click the channel in Slack > Copy Link). Set the 'Blocks' field to use the expression {{ $json.blocks }} from the Code node output. Leave the 'Text' field as a plain fallback like 'Daily pipeline update'.
- 1Add a Slack node connected to the Code node
- 2Select your Slack credential from the dropdown
- 3Set 'Resource' to 'Message' and 'Operation' to 'Send'
- 4In the 'Channel' field, paste your channel ID (e.g. C04XXXXXXX)
- 5Toggle on 'Blocks' and set the value to the expression {{ JSON.stringify($json.blocks) }}
- 6Set 'Text' to 'Daily pipeline update — see blocks for details'
- 7Click 'Execute Node' to send a test message
n8n Canvas > Right-click node > Add Error Output > Connect to Slack Error Node
Add error handling with a Slack fallback node
Add a second Slack node connected to any step that could fail — the HTTP Request nodes are the most common failure points. Set this node's channel to your internal #ops-alerts channel and configure it to send a plain text error message. In n8n, right-click any node, select 'Add Error Output', and connect that error output to the fallback Slack node.
- 1Right-click the first HTTP Request node and select 'Add Error Output'
- 2Connect the red error output handle to a new Slack node
- 3Configure the Slack node to post to #ops-alerts
- 4Set the message text to 'Pipeline workflow failed at Close API pull — check n8n execution log'
- 5Repeat for the second and third HTTP Request nodes
n8n Canvas > Activate toggle (top right) > Execute Workflow (toolbar)
Activate the workflow and verify the first scheduled run
Click the toggle in the top right of the n8n canvas to activate the workflow. The toggle turns green and the workflow is now live. To verify without waiting until 8 AM, manually trigger it by clicking 'Execute Workflow' in the top toolbar — this fires all nodes immediately regardless of the schedule. Check your Slack channel for the message and the n8n Executions tab for a green success status.
- 1Click the gray toggle in the top right — it should turn green and show 'Active'
- 2Click 'Execute Workflow' in the toolbar to run it immediately for testing
- 3Open your Slack channel and confirm the pipeline summary message arrived
- 4Click 'Executions' in the left sidebar to confirm the run shows a green checkmark
- 5Check the scheduled trigger settings one more time to confirm the 8 AM daily schedule is correct
Scaling Beyond More than 100 open opportunities or 200 overdue tasks+ Records
If your volume exceeds More than 100 open opportunities or 200 overdue tasks records, apply these adjustments.
Implement pagination for the opportunities endpoint
Close's API returns a maximum of 100 records per request and includes a has_more field in the response. Add a loop in n8n using a Loop Over Items node: check has_more, increment the _skip parameter by 100, and repeat until has_more is false. Merge all pages before passing to the Code node.
Filter API results server-side before processing
Instead of pulling all opportunities and filtering in the Code node, add query parameters to narrow the Close API call — for example, filter by date_updated in the last 30 days, or by specific user IDs for the team you're reporting on. Pulling 500 records to display 80 wastes execution time and risks hitting Close's rate limit of 40 requests per second.
Split large rep lists into multiple Slack messages
Slack enforces a 50-block limit per message. At 4 blocks per rep (section + context + divider + spacing), you hit the limit at 12 reps. If your team has 20+ reps, split the repPipeline object into chunks of 10 in the Code node and send each chunk as a separate Slack message using multiple Slack nodes chained in sequence.
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 you are self-hosting and want to pay nothing in per-task fees for a workflow that runs 365 times per year. The scheduled trigger, three API calls, a Code node, and a Slack post costs exactly $0 on self-hosted n8n regardless of how many reps are in your team. The second reason to pick n8n is the Code node — building a user ID lookup map, grouping opportunities by rep, and formatting Block Kit JSON is straightforward JavaScript that runs in under 2 seconds. The one scenario where you'd pick something else: if your team is non-technical and the person maintaining this workflow will never touch code, use Zapier's multi-step Zap with Formatter steps instead. It's slower and more expensive, but the UI is more forgiving.
At one execution per day with five HTTP requests per run, this workflow makes roughly 150 API calls per month to Close and 30 Slack API calls. Close has no published rate limit for read requests at this volume — you won't come close to any ceiling. On n8n Cloud's Starter plan at $20/month, this workflow consumes roughly 31 executions per month (one per day). That's well within the 2,500 included executions. Self-hosted n8n costs nothing in platform fees — just your server, which at $5-10/month on a small VPS handles dozens of workflows. Zapier would run this same workflow for $73/month on the Professional plan because three API calls plus one Slack step = four tasks per Zap run, times 31 runs = 124 tasks/month, which exceeds the free tier's 100 task limit.
Make's scenario builder handles this use case well with its HTTP modules and built-in iterator — the scheduled trigger fires cleanly and aggregator modules replace some of what the n8n Code node does manually. Make's free tier includes 1,000 operations/month, and this workflow uses about 6 operations per run, so 186/month — comfortably free. Zapier has no native Close integration as of early 2024, so you'd use Webhooks by Zapier to call the Close API directly, which requires a paid plan. Power Automate has no Close connector and the HTTP action for premium connectors costs extra on top of the per-user license — wrong tool here. Pipedream handles this cleanly with its native Close and Slack actions and includes 10,000 invocations/month free, making it the strongest free-tier competitor to n8n for this use case. n8n wins if you are already self-hosting it; Pipedream wins if you want the fastest setup with zero infrastructure.
Three things you will hit after setup. First, Close's opportunity API uses value in cents for some account configurations and dollars for others depending on account age — if your Slack message shows '$18500000' instead of '$18,500', divide value by 100 in the Code node. Second, the Schedule Trigger in n8n does not back-fill missed executions. If your server is down at 8 AM, the run is skipped entirely — no retry, no catch-up. Add a manual 'Execute Workflow' button shortcut to your browser bookmarks for these situations. Third, Slack's Block Kit context blocks have a 3,000 character limit per element. If a rep has many overdue tasks with long descriptions, the context block text can exceed this and the Slack API returns a 'invalid_blocks' error with no further detail. The Code node caps overdue task display at three items to avoid this — if you remove that cap, you will eventually hit it.
Ideas for what to build next
- →Add a weekly digest with won/lost deal totals — Fork the same workflow with a weekly Schedule Trigger and add a second HTTP Request node querying Close's opportunity endpoint filtered by status_type=won and date_won in the past 7 days. Post this summary to a #wins channel every Friday at 4 PM.
- →Send individual rep summaries as Slack DMs — Instead of posting to a shared channel, use Close's user email addresses to look up each rep's Slack user ID via the Slack users.lookupByEmail API endpoint, then send each rep a personalized DM with only their own deals and tasks.
- →Trigger a Close task when a rep doesn't respond to overdue items — Add a follow-up branch: if a rep has 3+ overdue tasks for two consecutive days, use the Close task API to automatically create a follow-up task assigned to the sales manager. This creates an escalation loop without requiring manual oversight.
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