Planhat to HubSpot Migration: The Technical Guide
Planhat to HubSpot is a model-mismatch migration. This guide covers data mapping, API extraction, Custom Objects, and what's genuinely lost.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
TL;DR: A Planhat to HubSpot migration is a high-complexity model-translation project, not a lift-and-shift. Planhat is a customer success platform organized around Companies, End Users, Assets, Licenses, NPS, Health Scores, and time-series usage data. HubSpot is a CRM organized around Contacts, Companies, Deals, and Tickets. Direct 1:1 mapping exists only for Companies and End Users → Contacts. Assets, time-series metrics, health score history, and playbook automation must either go into HubSpot Custom Objects (Enterprise-only, max 10 definitions), get flattened into custom properties, or land in a data warehouse. Playbooks (Workflows), Automations, and Health Profile configurations cannot be exported via API — they must be manually documented and rebuilt. Realistic timeline: 1–2 weeks for small datasets, 5–8 weeks when Custom Objects, time-series warehousing, and workflow rebuilds are in scope.
A Planhat to HubSpot migration means translating a customer success data model into a CRM data model. These are different categories of software. Planhat tracks post-sale lifecycle — health scores, usage trends, renewal playbooks, NPS campaigns. HubSpot tracks pipeline, marketing attribution, and deal revenue. The overlap is real (both store companies and contacts), but the divergence is where every migration decision gets made.
The failure mode is predictable. Teams export everything, import it into contacts, companies, deals, and notes, and end up with a CRM full of flattened history that no one can report on, automate against, or trust. A good migration keeps HubSpot operational and keeps analytical history queryable somewhere else.
This guide covers the data model mismatch, Planhat's API and export surface, what HubSpot can absorb natively versus what requires Custom Objects or external storage, and — honestly — what you will lose in the move.
Why Teams Move from Planhat to HubSpot
Most Planhat-to-HubSpot migrations happen for one of three reasons:
- Platform consolidation. The company already runs HubSpot for marketing and sales and wants to eliminate a separate CS tool. One platform, one bill, one admin surface.
- HubSpot Service Hub adoption. Teams that bought Service Hub Enterprise expect it to cover customer success workflows that were previously in Planhat.
- Headcount or budget reduction. Planhat's per-seat pricing gets cut in favor of HubSpot seats the organization already owns.
None of these reasons eliminate the technical complexity. They just explain the business pressure behind it.
Planhat's Data Model: What You're Extracting
Planhat is a company-centric customer success platform where almost all data ultimately relates to the Company model. Understanding what lives in Planhat is the first step before you map anything to HubSpot.
Companies are at the center of Planhat's data structure — almost all data ultimately relates to the Company model, whether that's emails, assets, licenses, or usage metrics.
The core Planhat models you need to extract:
| Planhat Model | What It Represents | API Endpoint | List Limit |
|---|---|---|---|
| Company | Customer accounts (parent-child hierarchy supported) | GET /companies |
5,000/request |
| End User | Contacts and product users combined | GET /endusers |
2,000/request |
| Asset | Sub-entities: departments, products, environments | GET /assets |
2,000/request |
| License | Revenue records (MRR/ARR) | GET /licenses |
2,000/request |
| NPS | Individual survey responses with score, comment, date | GET /nps |
10,000/request |
| Conversation | Emails, tickets, chats | GET /conversations |
2,000/request |
| Note | Internal notes on customer records | GET /notes |
2,000/request |
| Task | Action items assigned to team members | GET /tasks |
2,000/request |
| Opportunity | Upsell/expansion pipeline | GET /opportunities |
2,000/request |
| Issue | Feature requests (many-to-many with Companies) | GET /issues |
2,000/request |
Planhat also stores Projects, Objectives, and Churn records, which may need extraction depending on your scope.
Beyond these structured models, Planhat stores three categories of data that have no direct HubSpot equivalent:
- Health Profiles — a score from 0–10 based on custom criteria, with the score's development over time tracked as Time Series data
- Time Series data — including Default/System Metrics, User Activities, Custom Metrics, and Calculated Metrics, tracked across Companies, End Users, Assets, and Projects
- Workflows (Playbooks) — automated series of steps (tasks and/or emails) that Planhat calls Workflows, previously known as Playbooks, with two types: Projects and Sequences
How Does the Planhat API Handle Data Extraction?
Planhat has a soft limit of 200 API calls per minute to its main API. The hard limit is 150 requests per second with bursts of up to 50 parallel requests. In practice, the soft limit is what you'll design around during extraction.
The API has a limit of 2,000 objects per request for most object types, while Companies are limited to 5,000 objects per request. Paginate with offset and limit query parameters. Loop through each endpoint until the response returns an empty array.
Authentication uses static API Access Tokens generated via Private Apps in Planhat Settings. Once a token is created, it appears once and lasts forever — store it securely.
Planhat also supports xlsx file import/export, where the file import corresponds to a bulkUpsert operation. Excel exports are useful for field discovery, spot checks, and UAT samples, but they flatten relational data — you lose conversation thread history, associative links between End Users and Assets, and historical NPS responses. For a full migration, the API is the only viable extraction path.
Planhat's NPS list endpoint defaults to returning records from the last 360 days only. Set the npsExpiryDay parameter to a high value (e.g., npsExpiryDay=3650) or you will silently lose historical NPS data older than one year.
Key extraction constraints:
- Body size limit: There is a hard limit of 32MB on the body of each post to Planhat, relevant if you're writing back during reconciliation.
- Bulk upsert cap: For all bulk upsert operations, regardless of the model, there is an upper limit of 5,000 items per request.
- No export API for Workflows/Automations: Playbook templates, automation rules, and Health Profile configurations are not exposed via API endpoints. You must document them manually before decommissioning Planhat.
- Nested data in Conversations: Conversations and Notes often contain nested arrays for attachments or inline images. Parse these arrays, download the raw files, and host them temporarily so they can be uploaded to HubSpot's File Manager API.
Planhat to HubSpot Data Mapping
Every Planhat model needs a destination — HubSpot native object, HubSpot Custom Object, or external storage. This is the core decision matrix.
Direct mappings
These Planhat objects have clean equivalents in HubSpot:
| Planhat | HubSpot | Notes |
|---|---|---|
| Company | Company | Map name, externalId, custom fields. Planhat's parent-child orgPath maps to HubSpot's parent company associations. |
| End User | Contact | Map email as primary key. Planhat merges "contacts" and "users" into one model; HubSpot separates them only by lifecycle stage. |
| Opportunity | Deal | Map value, probability, stage. Planhat's opportunity model aligns reasonably with HubSpot's deal pipeline. |
| Note | Note (Engagement) | Create as engagement notes associated to the relevant Company or Contact. |
| Task | Task (Engagement) | Map assignee to HubSpot owner, due date, status. |
Duplicate End Users across companies: Planhat does not enforce email uniqueness across companies — the same person can exist as separate End User records under different companies. HubSpot deduplicates contacts by primary and secondary email. If you do not resolve these duplicates before import, records will collapse or misassociate. Build your identity resolution rules before loading Contacts.
Mappings that require Custom Objects (Enterprise-only)
HubSpot Custom Objects are Enterprise-only across every Hub. An Enterprise-level subscription allows for up to ten custom object definitions with up to 500,000 records each without additional charges. If you're not on Enterprise, these Planhat models have no clean home in HubSpot.
| Planhat | HubSpot Custom Object | Why |
|---|---|---|
| Asset | Custom Object: "Asset" or "Subscription" | Assets represent sub-entities of a Company — departments, shops, locations, data clusters, products, or product environments. HubSpot has no native sub-company entity. Do not map Assets to Deals — Deals are meant for point-in-time pipeline tracking. Dumping active Assets into your Deal pipeline will destroy sales forecasting and conversion rate reporting. |
| License | Custom Object: "License" or Deal line items | License records carry MRR/ARR values and renewal dates. HubSpot Deals can partially absorb this for pipeline visibility, but you lose the many-licenses-per-company structure and full contract lineage. |
| NPS Response | Custom Object: "NPS Response" | NPS records represent individual responses to NPS surveys, typically created automatically during campaigns. A single end user can have multiple records over time. A single custom property cannot represent response history. |
| Issue | Custom Object: "Feature Request" | Issues represent enhancement ideas and feature requests with a many-to-many relationship with Companies — a Company can have many issues, and an issue can belong to many Companies. No standard HubSpot object supports this. |
HubSpot Enterprise unlocks custom associations — the ability to define your own relationships between object types, including labelled associations and many-to-many relationships. You'll need these for Issue-to-Company (many-to-many) and Asset-to-Company mappings.
How should Conversations map from Planhat to HubSpot?
Map Planhat Conversations by type, not as a single notes dump. Planhat Conversations can represent email, chat, ticket, call, or manual note types. If you flatten everything to HubSpot Notes, you lose Conversation Types — Planhat's own integration documentation warns about this explicitly.
A workable pattern:
- Notes and internal account commentary → HubSpot Notes
- Phone-style interactions → HubSpot Calls (Call Types can be configured to preserve type fidelity)
- Support-ticket-style records that still need operational ownership → HubSpot Tickets
- Email history you need on the timeline → HubSpot Emails
- Full transcript archives, attachments, and thread-level fidelity → External archive or warehouse
Always include the original activity date when importing. If you omit it, HubSpot stamps the import time instead, which corrupts your timeline. Store the original Planhat conversation ID and type on the HubSpot record — even as a prefixed line in the note body or a custom property — to make validation and rollback possible.
Data that belongs in a warehouse, not HubSpot
Some Planhat data should not go into HubSpot at all. HubSpot is not a time-series database, and forcing this data in creates maintenance debt without analytical value.
- Time-series usage metrics. Planhat stores daily/weekly/monthly product usage data points per Company, End User, and Asset. HubSpot has no native time-series storage. Snapshot the latest value into a custom property (
last_login_count,usage_score_current), but keep the historical trend line in BigQuery, Snowflake, or Redshift. - Health Score history. Health Profiles calculate a score from 0–10 based on custom criteria, and the score's development over time is tracked as Time Series. Migrate the current health score as a custom Company property in HubSpot. Archive the full history to your warehouse.
- Calculated Metrics. Planhat computes derived metrics using formulas across objects. These calculations don't transfer — you'd need to rebuild them as HubSpot calculated properties (limited to basic arithmetic on the same object) or compute them externally.
- User Activity event streams. Raw event-level data (page views, feature clicks, API calls tracked per user) doesn't belong in a CRM. Export to your warehouse and reference it from HubSpot via an external URL property if needed.
The architecture for health scores specifically:
- Extract historical time-series data from Planhat's
/metricsand health endpoints. - Load into your warehouse (Snowflake, BigQuery, or Redshift) to preserve historical analytics.
- Sync stateful values to HubSpot. Create custom properties on the HubSpot Company record:
Current Health Score(Number),Health Trend(String: Up, Down, Flat),Last Active Date(Date). - Implement Reverse ETL. Use a tool like Census or Hightouch to query the warehouse daily and push the updated
Current Health Scoreinto HubSpot.
This keeps HubSpot fast and uncluttered while your CS team still has visibility into current customer health directly on the CRM record.
What Is Genuinely Lost in a Planhat to HubSpot Migration?
Be explicit with stakeholders about what cannot survive this move:
Health Score engine. Planhat's health scoring system is a configurable computation engine — it pulls from usage data, NPS, support tickets, login frequency, and custom metrics, weighted by rules your CS team defined. HubSpot has no equivalent. You can store the final score as a number property, but the live computation disappears. Rebuilding it requires either HubSpot Operations Hub calculated properties (far more limited), a custom integration that computes health externally and writes it back, or a third-party scoring tool.
Playbooks/Workflows as dynamic automation. Planhat Workflows adjust in response to data while running — groups of steps activate or deactivate as an End User carries out actions within your product. This is dynamic, data-driven sequencing tied to usage signals. HubSpot workflows operate on CRM property changes, not real-time product usage events. You must rebuild every playbook manually, and some will lose their trigger granularity.
Automations with health-score triggers. Planhat Automations work on an If this / Then that logic, for example, "If a Company Health Score climbs above 8 / Then create an Opportunity." Since the health score engine doesn't transfer, automations that depend on it break by definition.
Time-series trend visibility inside the platform. In Planhat, a CSM opens a company profile and sees a usage trend chart. In HubSpot, they'll see a current number in a custom property. The trendline is gone unless you build a dashboard link to an external BI tool or use HubSpot's CRM card extensions to display warehouse data inline.
NPS campaign machinery. Planhat's NPS Survey is wired into customer records, timelines, and workflows — every response can trigger follow-ups, owner changes, or health updates automatically. HubSpot's feedback surveys exist but are a different system with different trigger logic. Historical NPS records can be migrated as Custom Object records, but the campaign automation must be rebuilt.
Conversation type fidelity. If you map all Planhat Conversations to HubSpot Notes, the original type (email, chat, ticket, call) is lost. Planhat's own integration docs warn about this. Map by type to preserve fidelity.
Portal configurations. Planhat Portals let you share data views with customers as external users. HubSpot has no equivalent customer-facing portal for CS metrics.
Per-company person identity. If the same human exists in Planhat under multiple Companies as separate End User records, they may collapse into a single HubSpot Contact during deduplication, losing company-specific context.
Playbook execution history. Planhat tracks exactly when a playbook was triggered and which steps were completed. You can rebuild the automation logic in HubSpot Workflows, but the historical log of past executions cannot be migrated natively.
The goal is zero unplanned loss — not that everything must live inside HubSpot.
Step-by-Step Planhat to HubSpot Migration Process
Step 1: Audit and document Planhat configuration
Before writing any extraction code, document everything that lives in Planhat:
- Export the full list of custom fields across all models (Company, End User, Asset, etc.)
- Screenshot or manually record every Health Profile configuration — the factors, weights, and thresholds
- Document every Workflow (Playbook) template — triggers, steps, conditions, email templates
- List all Automation rules and their trigger conditions
- Record all NPS campaign configurations
- Map parent-child Company hierarchies
None of this configuration is API-exportable. If you decommission Planhat before documenting it, you lose it permanently.
Step 2: Design your HubSpot target schema
Decide what goes where before you extract anything:
- Standard objects: Companies, Contacts, Deals, Notes, Tasks
- Custom Objects (if Enterprise): Assets, Licenses, NPS Responses, Feature Requests
- Custom properties: Current health score, latest NPS score, ARR, renewal date, usage snapshots on Company/Contact records
- Data warehouse: Time-series metrics, health score history, user activity streams, calculated metric history
Create all Custom Objects, custom properties, and association definitions in HubSpot before you begin loading data. HubSpot schema changes after data is loaded are painful — property types can't be changed once records exist.
Create legacy ID fields on every target object. A planhat_id custom property on Companies, Contacts, and each Custom Object makes ID mapping, validation, and rollback dramatically easier.
Step 3: Resolve duplicate End User identities
Query Planhat End Users for cases where the same email appears across multiple companies. Decide your identity rule:
- Merge into one HubSpot Contact with multi-company associations
- Keep the most recent End User record and archive others
- Flag for manual review
This must happen before loading Contacts, not after.
Step 4: Extract data from Planhat via API
Write extraction scripts that paginate through each model:
import requests
import time
BASE_URL = "https://api.planhat.com"
HEADERS = {
"Authorization": "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json"
}
def extract_all(endpoint, limit=2000):
results = []
offset = 0
while True:
resp = requests.get(
f"{BASE_URL}/{endpoint}?limit={limit}&offset={offset}",
headers=HEADERS
)
resp.raise_for_status()
batch = resp.json()
if not batch:
break
results.extend(batch)
offset += limit
time.sleep(0.35) # Stay under 200 calls/minute
return results
companies = extract_all("companies", limit=5000)
endusers = extract_all("endusers")
assets = extract_all("assets")
nps_records = extract_all("nps?npsExpiryDay=3650", limit=10000)Extract in referential order: Companies → End Users → Assets → Licenses → NPS → Conversations → Notes → Tasks → Opportunities → Issues.
Step 5: Transform and map IDs
Build a mapping table that links Planhat _id values to HubSpot record IDs as you create records. Every association in HubSpot requires both record IDs, so you must maintain this lookup throughout the migration.
Key transformations:
- Planhat
orgPath→ HubSpot parent company association - Planhat
cId(company ID) on End Users → HubSpot Contact-to-Company association - Planhat health score (current value) → HubSpot custom number property on Company
- Planhat NPS
score+scoreType+comment→ HubSpot Custom Object record with association to Contact and Company - Planhat Conversation type → appropriate HubSpot engagement type (Note, Call, Email, or Ticket)
Step 6: Load into HubSpot
For HubSpot Enterprise accounts, the daily API limit is 1 million requests per day with a burst limit of 190 requests per 10 seconds. Use HubSpot's batch create endpoints (up to 100 records per batch call) to maximize throughput. Do not create records one by one — creating 50,000 Contacts individually will take hours and risk API throttling.
Load in this order:
- Companies (with custom properties including current health score, ARR,
planhat_id) - Contacts (End Users, with email as dedup key)
- Company-to-Contact associations (using the Associations v4 API)
- Deals (from Opportunities)
- Custom Objects: Assets, Licenses, NPS Responses
- Custom Object associations
- Engagements: Notes, Tasks, Calls, Emails
- Engagement associations
When linking Custom Objects to standard objects using the Associations v4 API, you must query HubSpot for the correct Association Definition IDs:
{
"inputs": [
{
"from": {
"id": "105234"
},
"to": {
"id": "882910"
},
"type": "custom_object_to_company"
}
]
}Step 7: Archive time-series data to your warehouse
Extract time-series data from Planhat's metrics endpoints and load it into BigQuery, Snowflake, or Redshift. A practical schema:
CREATE TABLE planhat_health_scores (
company_external_id VARCHAR,
hubspot_company_id BIGINT,
score DECIMAL(3,1),
recorded_date DATE,
profile_name VARCHAR
);
CREATE TABLE planhat_usage_metrics (
entity_type VARCHAR, -- 'company', 'enduser', 'asset'
entity_external_id VARCHAR,
metric_name VARCHAR,
metric_value DECIMAL,
period_start DATE,
period_end DATE
);Link warehouse records to HubSpot via hubspot_company_id or external ID. Surface the data in HubSpot by adding a custom property with a dashboard URL, or use HubSpot's CRM card extensions to display warehouse data inline. Configure your reverse ETL pipeline (Census, Hightouch, or similar) to sync the Current Health Score to HubSpot Company records on a daily cadence.
Step 8: Rebuild Workflows and Automations in HubSpot
Using your documentation from Step 1, rebuild each Planhat Workflow as a HubSpot workflow. Expect these limitations:
- HubSpot workflows trigger on property changes, form submissions, or date-based conditions — not on real-time usage event streams
- Multi-step sequences with conditional branching exist in HubSpot but use a different logic model
- Workflows that triggered on health score changes now require an external process to update the health score property, which then triggers the HubSpot workflow
Step 9: Validate
Run record-count reconciliation for every object type. Spot-check 5–10% of records manually, focusing on:
- Company hierarchy (parent-child) integrity
- Contact-to-Company associations
- Custom Object associations (Assets to Companies, NPS to Contacts)
- NPS score values and dates
- Note/Task content and timestamps
- Latest health snapshot and last-NPS values compared to Planhat source
For validation patterns and checklists, see our data migration mapping cheat sheet and CRM migration checklist. For building a structured validation process, see How to Build a Data Migration Playbook.
How Long Does a Planhat to HubSpot Migration Take?
| Scope | Timeline | What's Included |
|---|---|---|
| Small (< 5K companies, no Custom Objects) | 1–2 weeks | Companies, Contacts, Notes, Tasks, Deals. Current health score as custom property. |
| Medium (5K–25K companies, Custom Objects) | 3–4 weeks | Above + Assets, Licenses, NPS as Custom Objects. Warehouse setup for time-series. |
| Large (25K+ companies, full workflow rebuild) | 5–8 weeks | Above + full Workflow/Automation rebuild, BI dashboard integration, CRM card extensions. |
The extraction itself is fast — Planhat's API is well-structured and generous on rate limits. The time goes into schema design, Custom Object configuration, HubSpot workflow rebuilds, and validation.
HubSpot Tier Requirements for Planhat Data
Not all Planhat data can land in every HubSpot tier:
- HubSpot Professional: Companies, Contacts, Deals, Notes, Tasks, custom properties. No Custom Objects — Assets, NPS records, Licenses, and Issues cannot be stored as structured data. You'd have to flatten everything into custom properties on Company/Contact records, losing the relational structure.
- HubSpot Enterprise: If your business requires a relationship or process beyond the standard CRM objects, you can create and define a custom object. Enterprise is the minimum tier for a migration that preserves Planhat's asset/license/NPS structure. Budget accordingly.
HubSpot limits custom object associations to 500 per record, which is relevant for high-volume accounts with many Assets or NPS responses per Company.
When Not to Migrate Everything to HubSpot
Some teams would be better served by a hybrid approach:
- Keep Planhat read-only for historical reference while running HubSpot for new activity. This avoids the time-series migration entirely.
- Migrate core records to HubSpot, warehouse everything else. Companies, Contacts, and current-state snapshots go to HubSpot. All historical data goes to your warehouse.
- Use the existing Planhat–HubSpot integration. Planhat's native integration can sync virtually any Planhat object with any HubSpot object, bidirectionally — including custom fields and data types. If you're keeping Planhat temporarily, use the built-in sync to seed HubSpot before decommissioning. The native integration won't export time-series data, health score history, or NPS records into HubSpot, so plan API-based extraction for everything else.
The guiding principle: warehouse first, CRM second. Land the raw Planhat export in a warehouse or staging database before you build the HubSpot load. That gives you replayability, easier validation, and a way to preserve data that should never have lived in a CRM in the first place.
The worst outcome is cramming time-series data into HubSpot custom properties and losing the ability to query, chart, or trend it. Be intentional about what HubSpot is for in your new stack.
Making the Call
A Planhat to HubSpot migration is a model translation project, not a data copy. The records that map cleanly — Companies, Contacts, Deals, Notes — are straightforward. The value of the migration depends on the hard decisions: what to model as Custom Objects, what to warehouse, what to abandon, and what to rebuild from scratch.
Get the schema design right before you extract a single record. Document every Workflow and Automation before you lose access. And be explicit with your CS team about what they'll lose — health score trends in-platform, dynamic playbook triggers, NPS campaign automation — so they can plan workarounds before cutover, not after.
Frequently Asked Questions
- Can you migrate Planhat health scores to HubSpot?
- You can migrate the current health score value as a custom number property on HubSpot Company records. The health score computation engine — weighted factors, thresholds, automatic recalculation based on usage data — does not transfer. Historical health score trends must be archived to a data warehouse. To replicate live scoring in HubSpot, you'd need Operations Hub calculated properties (limited to basic arithmetic) or an external service that computes scores and writes them back via API.
- Does a Planhat to HubSpot migration require HubSpot Enterprise?
- If you need to preserve Planhat's Assets, Licenses, NPS response history, or Issues as structured data, yes — HubSpot Custom Objects require an Enterprise subscription on at least one Hub. Without Enterprise, you're limited to flattening this data into custom properties on standard objects, which loses the relational structure and many-to-one/many-to-many associations.
- What Planhat data is genuinely lost when migrating to HubSpot?
- The biggest losses are: (1) the health score computation engine and live recalculation, (2) time-series usage trend data visible inside the platform, (3) playbook/workflow automation triggered by real-time product usage events, (4) NPS campaign automation wired into health scoring, (5) Planhat Portal configurations, and (6) conversation type fidelity if you flatten to Notes. Raw data can be extracted and archived, but the operational machinery built on top of it must be rebuilt or replaced.
- What are Planhat's API rate limits for data extraction?
- Planhat's main API has a soft limit of 200 calls per minute and a hard limit of 150 requests per second with bursts of up to 50 parallel requests. List endpoints return up to 2,000 records per request (5,000 for Companies, 10,000 for NPS). The NPS endpoint defaults to the last 360 days only — set npsExpiryDay=3650 to get full history.
- What happens if the same Planhat End User exists across multiple companies?
- Planhat does not enforce email uniqueness across companies, so the same person can exist as separate End User records under different companies. HubSpot deduplicates contacts by email, which means unresolved duplicates will collapse into a single Contact or misassociate records. You must build identity resolution rules and decide on a merge strategy before loading Contacts into HubSpot.