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
Why Make?
Make works for auto-archiving if your team already uses it, though the lack of a built-in wait equivalent means you'll need two separate scenarios instead of one. A Data Store tracks which deals have been warned and when, connecting the warn and close phases. The visual builder makes it easy to adjust thresholds and add filters.
How it works
- Scenario 1 (daily): Searches for stale deals, sends Slack warnings to deal owners, records warned deal IDs and timestamps in a Data Store
- Scenario 2 (daily, offset by a few hours): Reads the Data Store, filters for deals warned 48+ hours ago, re-checks
hs_lastmodifieddate, closes deals that are still stale, removes closed deals from the Data Store
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.
Troubleshooting
Common questions
Why does this need two scenarios?
Make doesn't have a Wait node that pauses mid-execution. The Data Store bridges the two scenarios by tracking which deals were warned and when. Scenario 2 checks the Data Store for deals past the 48-hour grace period.
How many Make credits does this use per month?
Each run of Scenario 1 uses 3 + N credits (N = stale deals found). Scenario 2 uses 3 + M credits (M = warned deals). At typical volumes (5-10 stale deals/week), expect ~200-300 credits/month total.
Can I use a Google Sheet instead of a Data Store?
Yes, but the Data Store is simpler for key-value lookups. If you prefer Google Sheets, add a row when warning and remove it when closing. The Data Store is included on all plans and doesn't require a separate connection.
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.
Looking to scale your AI operations?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.