Flag HubSpot deals with missing fields and Slack the rep using n8n
Prerequisites
- n8n instance (cloud or self-hosted)
- HubSpot private app token with
crm.objects.deals.readscope - Slack app with Bot Token (
chat:writescope) - n8n credentials for HubSpot and Slack
- A mapping of HubSpot owner IDs to Slack user IDs (Google Sheet or static data)
Step 1: Schedule a daily check
Add a Schedule Trigger node:
- Trigger interval: Days
- Trigger at hour: 7 (run before the team starts their day)
Step 2: Search for deals missing close date
Add an HTTP Request node named "Search Missing Close Date":
- Method: POST
- URL:
https://api.hubapi.com/crm/v3/objects/deals/search - Authentication: HubSpot API credential
- Body:
{
"filterGroups": [
{
"filters": [
{
"propertyName": "closedate",
"operator": "NOT_HAS_PROPERTY"
},
{
"propertyName": "dealstage",
"operator": "NOT_IN",
"values": ["closedwon", "closedlost"]
}
]
}
],
"properties": ["dealname", "amount", "closedate", "dealstage", "hubspot_owner_id"],
"limit": 100
}Step 3: Search for deals missing amount
Add a second HTTP Request node named "Search Missing Amount" with the same structure, but swap the filter:
{
"filterGroups": [
{
"filters": [
{
"propertyName": "amount",
"operator": "NOT_HAS_PROPERTY"
},
{
"propertyName": "dealstage",
"operator": "NOT_IN",
"values": ["closedwon", "closedlost"]
}
]
}
],
"properties": ["dealname", "amount", "closedate", "dealstage", "hubspot_owner_id"],
"limit": 100
}HubSpot's Search API applies AND logic within a filter group. You cannot OR two NOT_HAS_PROPERTY filters in a single group. Running two searches and merging results is the reliable approach.
Step 4: Merge and group by owner
Add a Code node to deduplicate and group deals by owner:
const missingClose = $('Search Missing Close Date').first().json.results || [];
const missingAmount = $('Search Missing Amount').first().json.results || [];
// Deduplicate by deal ID
const seen = new Set();
const allDeals = [];
for (const deal of [...missingClose, ...missingAmount]) {
if (!seen.has(deal.id)) {
seen.add(deal.id);
const props = deal.properties;
const missing = [];
if (!props.closedate) missing.push('close date');
if (!props.amount) missing.push('amount');
allDeals.push({
id: deal.id,
name: props.dealname,
stage: props.dealstage,
ownerId: props.hubspot_owner_id || 'unassigned',
missing,
});
}
}
const byOwner = {};
for (const deal of allDeals) {
if (!byOwner[deal.ownerId]) byOwner[deal.ownerId] = [];
byOwner[deal.ownerId].push(deal);
}
return Object.entries(byOwner).map(([ownerId, deals]) => ({
json: { ownerId, deals, dealCount: deals.length }
}));Step 5: Slack DM each rep
Add a Slack node (executes once per owner from the Code node output):
- Operation: Send a message
- Channel: DM the owner using their Slack user ID from your mapping
- Message Type: Block Kit
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Missing Deal Fields"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "You have *{{ $json.dealCount }}* deals with missing fields:\n\n{{ $json.deals.map(d => `- <https://app.hubspot.com/contacts/YOUR_PORTAL_ID/deal/${d.id}|${d.name}> -- missing *${d.missing.join(', ')}*`).join('\\n') }}"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "Please update these deals today so forecasting stays accurate."
}
]
}
]
}To DM individual reps, you need a mapping of HubSpot owner IDs to Slack user IDs. Store this in a Google Sheet or as static data in the workflow using $getWorkflowStaticData('global'). Without this mapping, post to a shared channel like #sales-pipeline instead.
Step 6: Activate
- Replace
YOUR_PORTAL_IDin the Slack block with your HubSpot portal ID - Click Execute Workflow to test
- Verify Slack DMs contain the right deals and links
- Toggle to Active for daily checks
If no deals are missing fields, the Code node returns an empty array and the Slack node won't execute. No extra filter needed.
Cost
- n8n Cloud: 1 execution/day = ~30/month. Well within the Starter plan's 2,500 executions.
- Self-hosted: Free.
Need help implementing this?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.