Mirror HubSpot contacts into a SQL Server warehouse in real time

The moment a contact is created or updated in HubSpot, the matching row appears in your SQL Server contacts table. No nightly job, no drift.

Deterministic Code
SQL ServerHubSpotOperationsSalesData Sync

Build a code workflow that keeps a SQL Server contacts warehouse in sync with HubSpot in near real time.

Trigger: a webhook from HubSpot fired on the contact.creation and contact.propertyChange events. The payload will include the changed HubSpot contact id (objectId).

Steps:

1) Read the contact id from the webhook payload. HubSpot batches events, so iterate over each event in the payload and run the rest of the workflow per contact id.

2) Call HubSpot's Get Contact operation for that id. Request the full property set we care about: email, firstname, lastname, company, lifecyclestage, lead_status, hubspot_owner_id, createdate, lastmodifieddate. Pass these explicitly via the properties query param so HubSpot returns them even if they are not on the default property list.

3) Use the SQL Server Upsert Row operation to write the contact into a dbo.contacts table in the connected SQL Server database, matched on hubspot_contact_id. Map HubSpot properties to typed columns as follows: hubspot_contact_id (NVARCHAR, primary key) ← id; email ← properties.email; firstname ← properties.firstname; lastname ← properties.lastname; company ← properties.company; lifecyclestage ← properties.lifecyclestage; lead_status ← properties.hs_lead_status; owner_id ← properties.hubspot_owner_id; createdate ← properties.createdate (parse to DATETIME2); lastmodifieddate ← properties.lastmodifieddate (parse to DATETIME2); synced_at ← current UTC time (DATETIME2). Use MERGE semantics so the same path handles creates and updates.

Setup step: include a one-time CREATE TABLE statement that the user runs against their database before turning the workflow on. The table should look like:

CREATE TABLE dbo.contacts ( hubspot_contact_id NVARCHAR(64) NOT NULL PRIMARY KEY, email NVARCHAR(320) NULL, firstname NVARCHAR(255) NULL, lastname NVARCHAR(255) NULL, company NVARCHAR(255) NULL, lifecyclestage NVARCHAR(64) NULL, lead_status NVARCHAR(64) NULL, owner_id NVARCHAR(64) NULL, createdate DATETIME2 NULL, lastmodifieddate DATETIME2 NULL, synced_at DATETIME2 NOT NULL );

Implementation notes: use parameterized queries with @p1, @p2, ... placeholders for every value written to SQL Server, as called out in the SQL Server common docs. Never interpolate HubSpot values directly into the SQL string. If HubSpot returns a 404 for the contact id (deleted before we could fetch it), log and skip that event rather than failing the whole batch. If the webhook payload contains multiple events for the same contact id, deduplicate by contact id before fetching so we only make one Get Contact call per id per webhook delivery.

Integrations: HubSpot (OAuth, crm.objects.contacts.read scope) and SQL Server.

Additional information

What does this prompt do?
  • Listens for new and updated HubSpot contacts and reacts within seconds, not hours.
  • Pulls the latest version of the contact and writes it to your SQL Server contacts table with typed columns for email, name, company, lifecycle stage, lead status, and owner.
  • Handles creates and updates through the same path, matching on the HubSpot contact id so you never end up with duplicate rows.
  • Stamps every row with a synced_at timestamp so your analytics team can see exactly when the warehouse last heard from HubSpot.
What do I need to use this?
  • A HubSpot account where you can install an app and turn on contact creation and update notifications.
  • A SQL Server database your team can write to. Azure SQL, Amazon RDS, Google Cloud SQL, or self-hosted all work.
  • A login for that database with permission to create the contacts table and insert or update rows in it.
How can I customize it?
  • Add or remove HubSpot properties in the column mapping. If you track custom fields like persona, region, or MRR, surface them as their own typed columns.
  • Point at a different table or schema if your warehouse uses something other than dbo.contacts.
  • Layer in a second table for companies or deals using the same pattern so your warehouse mirrors the full CRM, not just contacts.

Frequently asked questions

How quickly do changes show up in SQL Server?
Usually within a few seconds. HubSpot sends a notification the moment a contact changes, the workflow fires immediately, fetches the latest properties, and writes the row.
Will this create duplicate rows if the same contact is updated twice?
No. The workflow matches on the HubSpot contact id, so the second event updates the existing row instead of inserting a new one. Creates and updates flow through the same path.
Do I need to create the warehouse table myself?
The workflow includes a one-time setup step with the table definition. Run it once against your database and the workflow will start filling it in.
Can I track when a contact was deleted in HubSpot?
Not in this version. It mirrors creates and updates. If you need deletes too, you can extend the workflow to listen for the contact deletion event and soft-delete the matching row.
Does this work with HubSpot Free?
Yes. Contact creation and update notifications are available on every HubSpot tier, including Free.

Stop running nightly HubSpot exports.

Connect HubSpot and SQL Server once, and every contact change lands in your warehouse within seconds.