Skip to main content
Most teams need no code. Settings → Integrations → HubSpot → Import from HubSpot pulls contacts, companies, deals, pipelines, custom properties, engagements and opt-outs straight from HubSpot in the background, resumably, with HubSpot ids kept. How it works. This page is for running the same move from code, when you want to transform data on the way or bring attachments across.
HubSpot keeps a record’s history as engagements: notes, emails, calls, meetings and tasks, each with a timestamp, an owner and the records it is associated with, plus attachments in its Files tool. Orbit keeps the same things: notes and tasks, logged activities for emails, calls, meetings and messages, and files on records. This page maps one to the other.

The script

scripts/maintenance/migrate-from-hubspot.ts in the Orbit repository walks a portal’s companies, contacts, deals, engagements and attachments into Orbit through the CRM API, in batches, with a HubSpot private app token and an Orbit API key (the CRM agent preset plus activities:write and files:write). It is safe to re-run: every row carries its HubSpot id as external_id under the source hubspot, so a second pass updates instead of duplicating.
It follows the order in Migrating from another CRM: members, structure, companies, contacts, deals, history, files, do-not-contact. --dry-run reads HubSpot and reports what would be written, --only runs a subset of the phases and --limit caps each phase for a trial run.

Field mapping

What the script sends, and what any other code reading HubSpot’s API should send. Timestamps from HubSpot are Unix milliseconds; Orbit accepts them as they are or as ISO 8601.

Every engagement

Notes

Emails

Calls

Meetings

Tasks

Communications (SMS, WhatsApp, LinkedIn)

Check the result

Open a few contacts in Orbit: the timeline shows the migrated emails, calls, meetings and notes at the dates they happened, each marked with who did it and that it came from HubSpot. GET /api/v1/timeline reads the same feed. If a run went wrong, POST /api/v1/activity-imports/{id}/undo removes everything that activity import created; contacts have their own undo on the contact import.