Monthly HubSpot contact refresh with Lusha and a Sheets audit log

On the 1st of every month, refresh stale or incomplete HubSpot contacts with Lusha, write the fresh data back, and log every change to a Google Sheet.

Deterministic Code
HubSpotLushaGoogle SheetsSalesOperationsData SyncLead Enrichment
PromptCreate

Build a code workflow that runs on the 1st of every month at 2am and refreshes stale or incomplete HubSpot contacts with Lusha, logging every batch to a Google Sheet. There are no LLM steps. Everything is deterministic: search, batch enrich, batch upsert, append row.

Trigger: cron, 1st of each month at 2am in the user's timezone.

Step 1. HubSpot Search Contacts. Use a filter group that matches contacts where email is empty OR phone is empty OR lastmodifieddate is older than 6 months ago. Page through results 100 at a time using the cursor returned in paging.next.after. Request the properties: email, firstname, lastname, phone, mobilephone, jobtitle, company, website, linkedinbio (or whatever the org's LinkedIn URL property is called, fall back to no LinkedIn if unset), lastmodifieddate.

Step 2. For each page of up to 100 contacts, call Lusha Enrich People (Bulk). Build one contact object per HubSpot record using the best identifier available, in this priority order: (a) existing email, (b) full name plus company domain derived from the website or email domain, (c) full name plus LinkedIn URL. Skip any HubSpot record that has none of those. Lusha's bulk endpoint caps at 100 per request, which matches the HubSpot page size exactly, so one HubSpot page maps to one Lusha bulk call.

Step 3. From the Lusha response, build a HubSpot Batch Upsert Contacts payload matched on the email property. For each Lusha hit, write back: email (the Lusha-verified one), mobilephone (Lusha mobile), jobtitle, company. Skip the upsert entry for any contact Lusha did not return data for. Keep a running count for the batch: processed, updated, not_found, credits_used (sum of isCreditCharged === true across the response objects).

Step 4. After each batch (immediately after the upsert), call Google Sheets Append Values on the configured audit-log spreadsheet and tab. Append one row with these columns in order: run_timestamp (ISO 8601), batch_index (1-based), contacts_processed, contacts_updated, contacts_not_found, credits_consumed. Use valueInputOption USER_ENTERED so the timestamp parses as a date in the sheet.

Loop until HubSpot search returns no paging.next. Respect rate limits: HubSpot Search is 4 requests per second per token, and Lusha enrichment is 25 requests per second. Add a short pause between batches if needed. On a 429 from either side, honor Retry-After and continue.

Setup inputs the workflow should ask for: the Google Sheets spreadsheet ID, the tab name for the audit log, and the staleness threshold in months (default 6). Everything else uses the defaults above.

What does this prompt do?

  • Finds HubSpot contacts that are missing an email or phone, or that have not been updated in the last 6 months.
  • Sends those contacts to Lusha in batches and pulls back fresh email, mobile phone, job title, and company.
  • Writes the fresh data back to the matching HubSpot contacts so your CRM stays clean without anyone clicking refresh.
  • Appends one summary row to a Google Sheet after every batch with the run time, how many contacts were processed, how many were updated, how many Lusha did not find, and how many credits were used.

What do I need to use this?

  • A HubSpot account where you can connect contacts read and write access.
  • A Lusha account with API access on a paid plan.
  • A Google Sheet you want to use as the audit log, plus a Google account that can write to it.

How can I customize it?

  • Change the schedule. Monthly at 2am is the default, but weekly or quarterly works just as well.
  • Tighten or loosen the filter. The default targets contacts missing email or phone, or not updated in 6 months. You can swap in your own staleness window or property checks.
  • Change which fields get written back. Default is email, mobile phone, job title, and company. Add or drop any HubSpot property you want kept fresh.
  • Point the audit log at a different sheet or tab, or add extra columns like the Lusha run ID or the person responsible.

FAQs

How often does it run?
Once a month, at 2am on the 1st. You can change this to weekly, quarterly, or any other schedule during setup.
Will it re-enrich contacts that already look complete?
No. The workflow only sends contacts to Lusha that are missing an email or phone, or that have not been updated in the last 6 months. Records with current data are left alone, which saves Lusha credits.
What gets written back to HubSpot?
Fresh email, mobile phone, job title, and company name are written back to the matching contact, matched on email. You can add or remove fields when you set up the workflow.
How will I know what was changed?
Every batch appends one row to your Google Sheet audit log with the run timestamp, how many contacts were processed, how many were updated, how many Lusha could not find, and how many credits were consumed.
Will this work on the HubSpot Free plan?
Yes for the HubSpot side. You can read and write contacts on any HubSpot tier. The blocker is Lusha, which requires a paid plan to issue API keys.
What happens if Lusha can't find a contact?
That contact is skipped and counted in the not found column of the audit log. Nothing in HubSpot is changed for them, and the rest of the batch continues normally.

Related templates

Review desk for portal forms your team still fills in by hand

Stage a batch of filings overnight, then approve each completed form from a screenshot before anything is ever submitted.

Kernel
Google Sheets
Slack Bot
App
Client-by-client cold email pipeline review for agencies

Pick a client and a date range to see sent, replies, meetings booked and the real deal value your cold email produced, campaign by campaign.

Instantly
HubSpot
Slack Bot
App
Partner tier review board for quarterly promotion calls

Work every partner tier decision from one board, with the revenue and commission numbers, clear promotion thresholds, and AI review briefs.

Introw
HubSpot
Slack
App
Reconcile partner commissions between HubSpot and Introw

Open one board at month end to find every closed deal missing a commission, every commission with no deal behind it, and every amount that does not add up.

Introw
HubSpot
Slack
App
Audit what Intercom's Fin AI actually resolved before you pay

Review every conversation Fin closed as resolved, judge which ones actually stuck, and see what the gap is worth against your bill.

Intercom
Google Sheets
Slack Bot
App
Returns and warranty claim desk that follows your policy

Work every return, damage and warranty claim in one queue, with the order, the delivery date and a policy-backed recommendation already on screen.

Kustomer
Shopify
Google Sheets
App

Stop letting your CRM rot one stale record at a time.

Connect HubSpot, Lusha, and Google Sheets once. Geni keeps your contacts fresh and writes a paper trail every month.