Auto-archive stale HubSpot deals using Make
Prerequisites
- Make account (Core plan recommended for multiple scenarios)
- HubSpot connection in Make via OAuth (needs
crm.objects.deals.readandcrm.objects.deals.writescopes) - Slack connection in Make
- A Google Sheet or Make Data Store to track warned deals
Overview
Make doesn't have a built-in "wait 48 hours" equivalent like n8n's Wait node. Instead, you'll use two separate scenarios:
- Scenario 1 (daily): Finds stale deals, warns owners in Slack, records the warned deals and timestamp in a Data Store
- Scenario 2 (daily, offset by a few hours): Checks the Data Store for deals warned 48+ hours ago, verifies they're still stale, and closes them
This two-scenario pattern is the standard Make approach for delayed actions.
Scenario 1: Find and warn
Step 1: Create the warning scenario and schedule it
Create a new scenario. Set the schedule:
- Schedule type: Every day
- Time: 07:00
- Timezone: Your team's timezone
Step 2: Search for stale deals
Add an HTTP module (Make an API Call) with the HubSpot connection:
- URL:
https://api.hubapi.com/crm/v3/objects/deals/search - Method: POST
- Body:
{
"filterGroups": [
{
"filters": [
{
"propertyName": "hs_lastmodifieddate",
"operator": "LT",
"value": "{{formatDate(addDays(now; -60); 'X')}}000"
},
{
"propertyName": "dealstage",
"operator": "NOT_IN",
"values": ["closedwon", "closedlost"]
}
]
}
],
"properties": [
"dealname", "amount", "dealstage", "hubspot_owner_id",
"hs_lastmodifieddate"
],
"sorts": [
{ "propertyName": "hs_lastmodifieddate", "direction": "ASCENDING" }
],
"limit": 100
}formatDate(addDays(now; -60); "X") returns a Unix timestamp in seconds. Append 000 to convert to milliseconds for HubSpot's filter.
Step 3: Iterate over results
Add an Iterator module to loop through the results array from the search response. Each deal becomes a separate bundle.
Step 4: Check the Data Store for duplicates
Before warning, check if you've already warned about this deal (to avoid duplicate Slack messages on consecutive runs).
First, create a Data Store called "Stale Deal Warnings" with these fields:
| Field | Type |
|---|---|
deal_id | Text (key) |
deal_name | Text |
warned_at | Date |
owner_id | Text |
Add a Data Store → Search Records module:
- Data store: Stale Deal Warnings
- Filter:
deal_idequals{{id}}(from the Iterator)
Add a Filter module after the search:
- Condition: Number of records equals 0 (only proceed for deals not yet warned)
Step 5: Warn in Slack
Add a Slack → Create a Message module:
- Channel:
#sales-pipeline - Text:
:warning: *Stale Deal Warning*
*{{dealname}}* has had no activity for {{round(dateDifference(now; hs_lastmodifieddate; "d"))}} days.
This deal will be moved to Closed Lost in 48 hours unless someone updates it.
<https://app.hubspot.com/contacts/YOUR_PORTAL_ID/deal/{{id}}|View deal in HubSpot>Step 6: Record the warning
Add a Data Store → Add/Replace a Record module:
- Data store: Stale Deal Warnings
- Key:
{{id}}(the deal ID) - deal_id:
{{id}} - deal_name:
{{dealname}} - warned_at:
{{now}} - owner_id:
{{hubspot_owner_id}}
Step 7: Activate Scenario 1
Test with Run once, then toggle to Active.
Scenario 2: Close expired warnings
Step 1: Create the closing scenario
Create a second scenario. Set the schedule:
- Schedule type: Every day
- Time: 09:00 (runs 2 hours after the warning scenario, but the 48-hour check ensures timing)
Step 2: Search the Data Store for expired warnings
Add a Data Store → Search Records module:
- Data store: Stale Deal Warnings
- Filter:
warned_atless than{{addHours(now; -48)}}
This returns all deals that were warned more than 48 hours ago.
Step 3: Re-check each deal in HubSpot
Add an HTTP module to fetch the deal's current state:
- URL:
https://api.hubapi.com/crm/v3/objects/deals/{{deal_id}} - Method: GET
- Query string:
properties=hs_lastmodifieddate,dealstage
Step 4: Filter out deals that were updated
Add a Filter module:
- Condition:
hs_lastmodifieddateis before{{addHours(now; -48)}}ANDdealstageis notclosedwonorclosedlost
Deals that were updated during the grace period (or already closed manually) skip the close step.
Step 5: Close the deal in HubSpot
Add an HTTP module:
- URL:
https://api.hubapi.com/crm/v3/objects/deals/{{deal_id}} - Method: PATCH
- Body:
{
"properties": {
"dealstage": "closedlost",
"closed_lost_reason": "Stale — auto-archived after 60 days"
}
}Step 6: Notify Slack
Add a Slack → Create a Message module:
- Text:
:file_cabinet: *Deal Auto-Archived*
*{{deal_name}}* was moved to Closed Lost after 60+ days of inactivity. No objection was received during the 48-hour grace period.Step 7: Clean up the Data Store
Add a Data Store → Delete a Record module to remove the warning entry:
- Key:
{{deal_id}}
This keeps the Data Store clean — only active warnings remain.
Deals that were updated during the grace period also need to be removed from the Data Store. Add a second branch after the Filter in Step 4 that catches filtered-out deals (those that were updated) and deletes their Data Store records too. Otherwise, they'll be re-checked every day forever.
Step 8: Activate Scenario 2
Test with Run once, then toggle to Active.
Cost
- Free plan: Scenario 1 uses ~3-5 credits per stale deal (iterator + data store check + Slack + data store write). Scenario 2 uses ~4-5 credits per expired warning. With 10 stale deals per week, expect ~80-100 credits/week (~400/month). Fits the free plan's 1,000 credits.
- Core plan: $29/month for 10,000 credits. Needed if you have high deal volume or add more complex logic.
Need help implementing this?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.