Flag HubSpot deals with missing fields and Slack the rep using Zapier
Prerequisites
- Zapier Professional plan (required for Schedule trigger + Webhooks + Code steps)
- HubSpot private app token with
crm.objects.deals.readscope - Slack workspace connected to Zapier
- A mapping of HubSpot owner IDs to Slack user IDs
Step 1: Schedule a daily trigger
Create a new Zap with Schedule by Zapier:
- Frequency: Every Day
- Time: 7:00 AM
Step 2: Search for deals missing close date
Add a Webhooks by Zapier -> Custom Request step:
- Method: POST
- URL:
https://api.hubapi.com/crm/v3/objects/deals/search - Headers:
Authorization: Bearer YOUR_TOKEN,Content-Type: application/json - Data:
{
"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 another Webhooks by Zapier -> Custom Request step with the same structure, swapping 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 uses AND logic within a filter group. You cannot OR two NOT_HAS_PROPERTY filters together. Two separate requests merged in the next step is the cleanest approach.
Step 4: Merge and group with Code by Zapier
Add a Code by Zapier step (JavaScript). Pass both webhook responses as input data:
const closeResp = JSON.parse(inputData.missingCloseRaw);
const amountResp = JSON.parse(inputData.missingAmountRaw);
const seen = new Set();
const allDeals = [];
for (const deal of [...(closeResp.results || []), ...(amountResp.results || [])]) {
if (seen.has(deal.id)) continue;
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,
ownerId: props.hubspot_owner_id || "unassigned",
missing: missing.join(", "),
});
}
if (allDeals.length === 0) {
return { count: 0, message: "" };
}
// Group by owner
const byOwner = {};
for (const deal of allDeals) {
if (!byOwner[deal.ownerId]) byOwner[deal.ownerId] = [];
byOwner[deal.ownerId].push(deal);
}
// Format one message per owner
const ownerMessages = Object.entries(byOwner).map(([ownerId, deals]) => {
const lines = deals.map(d =>
`- <https://app.hubspot.com/contacts/YOUR_PORTAL_ID/deal/${d.id}|${d.name}> -- missing *${d.missing}*`
).join("\n");
return `${ownerId}:::${deals.length}:::${lines}`;
});
return { count: allDeals.length, owners: ownerMessages.join("|||") };Code by Zapier can only return simple key-value pairs, not arrays. The script above encodes owner groups as a delimited string. Parse it in a downstream Looping step or use multiple Slack steps.
Step 5: Filter empty results
Add a Filter step:
- Only continue if:
countis greater than0
Step 6: Send Slack messages per owner
Add a Looping by Zapier step to iterate over the |||-separated owner messages, then inside the loop add a Slack -> Send Direct Message step:
- User: Map the HubSpot owner ID to the Slack user ID
- Message:
*Missing Deal Fields*
You have deals with incomplete data:
{{lines from code output}}
Please update these deals today so forecasting stays accurate.If owner-to-Slack mapping is too complex for your setup, replace the loop with a single Slack -> Send Channel Message step posting the full list to #sales-pipeline.
Step 7: Test and publish
- Test each step individually
- Verify the Slack DM formatting and links
- Turn the Zap on
Cost
- Professional plan: $29.99/mo. Uses ~5-6 tasks per daily run (schedule + 2 webhooks + code + filter + Slack) = ~180 tasks/month.
Need help implementing this?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.