Skip to main content
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 and gives the agent a plan it can follow end to end.
1

Connect both sides

Connect Orbit to your assistant (how) and approve crm:write, contacts:write, companies:write, deals:write, tasks:write, notes:write, activities:write and files:write. Then connect HubSpot’s MCP server next to it (it reads contacts, companies, deals and engagements), or export from HubSpot and attach the files.
2

Invite your team

HubSpot owners become Orbit members by matching email. Invite everyone first; whoever is not a member keeps their name on the records they wrote.
3

Set up the structure

Pipelines, stages and custom fields come first (Build your CRM). Ask the agent to show the mapping before it writes anything.
4

Run the migration

Records first, history second, files last, in the prompt below. Every row carries its HubSpot id, so the agent can stop and resume, and a second run updates instead of duplicating.

The prompt

“Migrate our HubSpot portal into Orbit. Use hubspot as the external_source everywhere and pass each HubSpot object id as the external_id.
  1. Companies: create_company for each HubSpot company with its name, domain, industry, size, owner (match by email to our members) and createdate as created_at.
  2. Contacts: import_contacts in batches of 500 with email, names, phone, job title, company, owner, createdate as created_at, and the HubSpot id as external_id.
  3. Deals: create_deal for each deal in the matching pipeline and stage, with amount, close date, owner and createdate; then add_deal_contact for its associated contacts (use contact_external_id).
  4. History: import_activities in batches of 500, one row per engagement, attached with contact_external_id / company_external_id / deal_external_id. Notes become note, calls call, meetings meeting, emails email, tasks task. Keep hs_timestamp as the time and the owner’s email as actor_email.
  5. Files: for every attachment, get its signed download URL from HubSpot and call import_file_from_url with the same record links and the HubSpot file id as external_id.
After each step, compare counts with HubSpot and list anything that did not import with the reason.”

Field mapping

The agent needs this when it reads engagements through HubSpot’s API or MCP server. 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)

Large portals

A chat assistant handles a few thousand engagements; a portal with a hundred thousand emails and calls is a script’s job. scripts/maintenance/migrate-from-hubspot.ts in the Orbit repository does exactly the plan above against the CRM API with a HubSpot private app token and an Orbit API key (the CRM agent preset), in batches, and is safe to re-run. Point a coding agent at it, or run it yourself:

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_timeline reads the same feed for the agent. If a run went wrong, undo_activity_import removes everything that run created, records included only if they were created by that run (contacts stay; use the contact import’s own undo for those).