Skip to main content

Migrate from HubSpot to Orbit

“Migrate from HubSpot” spans the same split the Salesforce migration does — a CRM is a system of record, not a send pipe. Pick the row that matches what you actually need: The connector is identical either way. What changes is how long it stays, and what you rebuild natively. The sections below are ordered for a consolidation; sections 1–3 are just as useful for a side-by-side setup, since you run them in both cases anyway.

1. What’s exported from HubSpot — before you change anything

Export from HubSpot while both sides still have full data:
  • Contacts — a CSV of the portal’s contact list, with the properties your segments use (Email, Phone, lifecycle stage, your hubspot:* custom properties). Include hs_lead_status and your marketing-consent field.
  • Companies — the account dimension, mapped into the CDP accounts entity for linked audiences.
  • Deals — history, not a daily workflow in Orbit. Your pipeline view is rebuilt natively only if you need to segment on it; otherwise archive.
  • Lists — static lists export as CSVs directly; active lists export via a filtered view. The distinction matters: a static list is over, an active list moves.
  • Marketing emails and templates — there is no per-template export; rebuild templates in Orbit per the email lifecycle guide.
  • Workflows — HubSpot workflows do not export. Rebuild each in Orbit as a flow, a campaign journey, or a journey from prompt starting from a plain-language description of the goal.
Keep the exported CSVs — they are the audit spine if a row doesn’t reconcile after the relink.

2. Connect HubSpot to Orbit (OAuth, admin-only)

The connection is the Nango OAuth integration. Owner/admin role required — it touches provider credentials.
The response returns an auth_url; redirect the browser to it and complete the OAuth consent. Inbound sync then runs on two paths — a scheduled poller, and real-time via POST /api/v1/integrations/webhooks/hubspot (once you add that URL to your HubSpot App’s webhook subscriptions). Both populate the Orbit contact book. Verify the connection landed:
Link fields populate on each contact — email, phone, first/last name, lifecyclestage, and your hubspot:-namespaced custom attributes. The identifier link is written as attributes.hubspot_id on each contact. Orbit also handles the outbound write-back automatically — a contact change in Orbit enqueues a hubspot-contact-push and the patch only lands in HubSpot if the contact is linked (no link → not_linked + audit, never an exception).

3. Recreate your audiences in Orbit

A HubSpot list is a live object — moving it means recreating it as a native Orbit segment, or pointing a campaign at the list while HubSpot is still live: Rebuild lists before you retire the HubSpot portal — a campaign that points at a HubSpot list works only while the connection is live. While HubSpot stays live, Orbit writes every new message and call back into the contact’s engagement timeline — a HubSpot user opens a Contact and sees Orbit SMS/WhatsApp/voice/email mixed chronologically with the portal’s native touches. Fail-open per the CRM activity logger design — a HubSpot outage never blocks an Orbit send. The provider mapping is: Enable when the two run side-by-side; skip it if you’re cutting HubSpot inside a month.

5. Rebuild the daily workflow in Orbit

HubSpot’s marketing, sales, and service surfaces map to Orbit’s own products: Rebuild gradually — leave HubSpot live while you move one workflow over at a time and harden it. The seven-step cutover runbook applies unchanged; the only HubSpot-specific detail is which lists step 3 and which write-back flag step 6 close out.

6. Reconcile, then cut over

The generic seven-step cutover in Migration playbook hub works as-is; these are the HubSpot-specific checkpoints to hang off it:
  1. Freeze sends in HubSpot — Marketing Hub campaigns, Sales sequences, form-triggered automation; whatever sends. Verify the HubSpot portal’s active sends read empty while Orbit keeps flowing on the split.
  2. Redirect webhooks — verify POST /api/v1/integrations/webhooks/hubspot against your HubSpot App’s signature verification (X-HubSpot-Signature-v3); if your own receiver mirrors Orbit events, replay a message.delivered against the X-Orbit-Signature HMAC.
  3. Swap API keys — cut your own integration (if any) onto an Orbit key; the OAuth connection to HubSpot itself stays until decommission.
  4. Flip sender identity — the production sender moves to Orbit’s numbers; email sender verification moves to Orbit’s domain auth.
  5. Watch the first-hour parity window — delivery-rate parity on the split class before decommission.
  6. Hold the fallback warm — keep the portal connected for one billing cycle if needed; the connector revokes independently from closing the portal.
  7. Decommission — verify no live sends in HubSpot, no webhook subscriptions pointing at Orbit you still need, and your exported CSVs reconcile with what Orbit reports imported. Then close the portal.

7. Operate after the migration

Once cut over, the ongoing surfaces that keep the migration honest:
  • Settings → Migrations — the job history for every import run lives here, with status and rollback. Monitor, cancel, and roll back platform migrations.
  • Audit ledger — every relink, write-back push, rollback, and webhook receipt lands in the audit log; the success and failure markers are crm.contact.pushed_to_hubspot and crm.contact.push_failed_hubspot.
  • Suppression and consent state — HubSpot subscription types and unsubscribe lists must exist in Orbit’s per-channel suppression before decommission. Opt-out lists covers how Orbit enforces it.
  • Sync health — if you left HubSpot connected as a record, GET /api/v1/integrations/{id}/status reports the per-sync last_sync timestamp; Settings → Integrations → HubSpot → Status surfaces the same.
Consolidating off HubSpot entirely, or running both for a season? The solutions team works HubSpot offloads regularly — migrate@devotel.io with your portal shape and traffic mix gets you the same dual-run plan the sections above assume.