Skip to content

Richpanel to HubSpot Service Hub Migration: A Technical Guide

Technical guide to migrating from Richpanel to HubSpot Service Hub. Covers API extraction, data model mapping, rate limits, and the Help Desk workspace gotcha.

Rishabh Rishabh · · 20 min read
Richpanel to HubSpot Service Hub Migration: A Technical Guide
TALK TO AN ENGINEER

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

Richpanel to HubSpot Service Hub Migration: A Technical Guide

Info

TL;DR: A Richpanel to HubSpot Service Hub migration shifts your helpdesk from an e-commerce, order-centric conversation platform to a CRM-integrated ticket-and-engagement architecture. Richpanel's core objects — Conversations, Messages, Customers, Orders, Tags, and Teams — must be mapped to HubSpot Tickets, Engagements (emails/notes), Contacts, Custom Properties, and Owner assignments. The primary extraction bottleneck is Richpanel's API rate limit of 100 calls per minute (492 status code on breach); at a default page size of 50 conversations per list call, extracting 50K conversations requires ~101K API calls (~17 hours). On the HubSpot side, tickets created via API don't populate the Help Desk workspace conversation thread — migrated history lives on the ticket Activity Timeline only. Automation rules, self-service portal flows, and widget configurations do not transfer. Realistic timeline: 1–3 weeks for under 50K conversations, 3–5 weeks for larger datasets with heavy attachments and complex order-linked metadata.

The Architectural Shift: E-commerce Helpdesk to CRM

Migrating from Richpanel to HubSpot Service Hub is not a 1:1 data transfer. It is a fundamental shift in how your customer support data is structured.

Richpanel operates as a live chat and help desk software purpose-built for e-commerce. Its architecture assumes an order — usually synced from Shopify, Magento, or WooCommerce — is the central context of a conversation. A customer messages you, and that message is intrinsically linked to their most recent transaction. Everything — chat, email, social — flows into a unified conversation timeline linked directly to order data.

HubSpot Service Hub is a CRM-first platform. Its architecture assumes that a Contact or Company is the central context. Tickets are standalone objects, and the actual back-and-forth messages (emails, notes, calls) are separate "Engagement" objects that must be explicitly associated with the Ticket and the Contact through HubSpot's Associations API.

To successfully migrate, you must extract flat conversation threads from Richpanel and reconstruct them across 3 to 5 separate HubSpot API endpoints. There is no native import path that handles this end-to-end.

Why Teams Migrate from Richpanel to HubSpot Service Hub

Teams leave Richpanel for HubSpot Service Hub for a few specific reasons:

  • CRM consolidation: Teams already running HubSpot for Marketing or Sales want support in the same platform. Similar to the drivers behind Intercom to HubSpot Service Hub migrations, running Richpanel alongside HubSpot CRM means maintaining a separate integration just to keep customer context in sync.
  • Reporting depth: Richpanel's standard reports cover ticket volume, agent productivity, and channel performance, and you can export data for analysis in external tools like Excel or Google Sheets. HubSpot's custom reporting engine with cross-object datasets and attribution reporting gives teams more analytical power without exporting to spreadsheets.
  • Scaling beyond e-commerce: Richpanel works well for specific types of ecommerce brands but has clear limitations as businesses grow. Teams expanding into B2B, SaaS, or multi-vertical support need ticket pipelines, SLA management, and workflow automation that span sales and service — which is HubSpot's core strength.
  • Pricing structure: Richpanel charges one AI agent for $500/mo and $100/seat for the helpdesk. For teams not heavily leveraging AI resolution, HubSpot Service Hub Professional at $100/seat/month with included automation, knowledge base, and SLA tools can be more cost-effective (though you should account for mandatory onboarding fees, as detailed in our HubSpot Service Hub to Help Scout migration guide).
Tip

If your team is primarily a Shopify-native DTC brand with fewer than 10 agents and you don't use HubSpot CRM for anything else, the migration cost may outweigh the benefit. Richpanel's deep Shopify integration and self-service portal are hard to replicate in HubSpot without significant custom work.

Richpanel vs. HubSpot Service Hub: Data Model Mapping

Before writing any extraction logic, define how Richpanel's schema translates to HubSpot's standard objects. This mapping is the foundation of your migration script.

Richpanel Object HubSpot Object Notes
Conversation Ticket One conversation = one ticket. Map status to hs_pipeline_stage.
Message (Agent/Customer) Engagement (Email/Note) Customer/agent messages → Email Engagements. Internal comments → Note Engagements.
Customer Contact Map email, phone, name, addresses. De-duplicate against existing HubSpot contacts.
Customer Address Contact properties Richpanel stores billing/shipping separately; HubSpot has a single default address. Use custom properties for shipping.
Order Custom Object or Deal Requires HubSpot Enterprise for Custom Objects. Or store key order data as custom Ticket properties.
Subscription Custom Object or custom properties Same Enterprise requirement for Custom Objects.
Tags Ticket property (Dropdown/Multi-select) HubSpot doesn't have a native tag object on tickets; pre-define dropdown or multi-select properties.
Agent Owner Map Richpanel agent emails to HubSpot user emails.
Team Team Create matching teams in HubSpot before import.
CSAT rating Custom ticket property Richpanel CSAT data needs a custom property in HubSpot.
Attachments File Manager + Engagements Files must be uploaded to HubSpot's File API, then linked to the corresponding Engagement via hs_attachment_ids.
Automation rules Workflows No export. Must be rebuilt manually in Service Hub Professional+.
Self-service portal flows Knowledge Base + Chatflows No export. Requires full manual recreation.
Macros / Canned responses Snippets / Templates No export. Must be manually copied over.

The Order Context Problem

Richpanel syncs order data to provide agents with complete customer purchase history and enables self-service order tracking. It also manages recurring subscription data and links orders to conversations so agents have full context when helping customers.

In HubSpot, this order-to-ticket linkage doesn't exist natively. You have three options:

  1. Custom Objects (Enterprise only): Create an "Order" Custom Object and associate it with Tickets and Contacts. This preserves the relational model but requires HubSpot Enterprise.
  2. HubSpot's native Shopify integration: If you connect Shopify to HubSpot, it syncs orders as Deals. You then need a script to associate historical HubSpot Tickets with the corresponding Deals based on the order ID referenced in the Richpanel export.
  3. Flatten into Ticket properties: Create custom properties on the Ticket object (e.g., richpanel_order_id, richpanel_order_value, richpanel_tracking_url) and stamp the most relevant order data directly onto the ticket. Simpler, but you lose the relational model.

Most teams under 50K tickets pick option 3 for speed and adopt the Custom Object approach later if needed.

How to Extract Data from Richpanel

Richpanel does not offer a one-click "export everything" button that yields complete conversation histories with attachments. You have three extraction paths: the REST API, the Graph API, and a limited CSV export.

REST API (Primary for Message Detail)

The Richpanel API is structured with REST in mind, with predictable resource-oriented URLs, JSON-encoded request/response bodies, and standard HTTP verbs. It covers Conversations (create, update, retrieve support tickets, add messages, assign to agents/teams, manage tags, track status), Customer Profiles, and Teams & Agents.

Key endpoints for extraction:

  • List conversations: GET https://api.richpanel.com/v1/tickets
  • Get single conversation: GET https://api.richpanel.com/v1/tickets/{id}
  • Get conversations by customer: GET https://api.richpanel.com/v1/tickets/{type}/{id} (by email or phone)

Authentication uses an API key passed via the x-richpanel-key header:

curl -X GET "https://api.richpanel.com/v1/tickets/{id}" \
  -H "accept: application/json" \
  -H "x-richpanel-key: YOUR_API_KEY"

Graph API (Bulk Extraction)

The Graph API endpoint is at https://graph.richpanel.com/data-api and supports fetching Conversations and Customers with first, offset, and filter parameters.

The Graph API is better for bulk extraction because it supports pagination with offset-based cursors. Use it to pull conversation lists and total counts, then hit the REST API for full message content per conversation.

Page size and call count: The Richpanel Graph API returns a default of 50 conversations per page. This means a list of 50K conversations requires 1,000 list calls to paginate through, plus 50,000 detail calls to retrieve full message bodies — approximately 51,000 total API calls for conversation metadata alone. Add additional calls for customer profile lookups and attachment downloads.

Rate Limits — The Extraction Bottleneck

Richpanel's Graph API has a rate limit of 100 calls per minute. After crossing usage within a minute, the API responds with a 492 status code. Rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining) are sent on all API responses, and Retry-After headers indicate wait time once exceeded.

Richpanel does not currently offer webhooks for real-time event streaming. This means all delta sync logic must be poll-based, using the updatedAt filter parameter on the Conversations endpoint to retrieve records modified since a given timestamp.

At 100 calls/minute and a page size of 50 conversations per list call, here's the extraction math:

Dataset Size List Calls (50/page) Detail Calls Total Calls Time at Rate Limit
10K conversations 200 10,000 ~10,200 ~1.7 hours
50K conversations 1,000 50,000 ~51,000 ~8.5 hours
100K conversations 2,000 100,000 ~102,000 ~17 hours

Note: These figures assume one detail call per conversation for full message bodies. Attachment downloads and customer profile lookups add additional calls on top.

Always implement exponential backoff in your extraction scripts. Hitting the API too aggressively will result in 492 errors that interrupt your pipeline.

Warning

CSV export limitation: Richpanel allows exporting conversations to CSV via bulk actions. But this export is metadata-level — it includes conversation IDs, statuses, assignees, and timestamps, but typically does not include full message thread content. Always verify your CSV export contains complete message bodies before relying on it as your primary extraction method.

Singer Tap

Richpanel maintains an official Singer tap (tap-richpanel) for extracting data. This is useful if you're already running a Singer/Meltano pipeline, but you'll still need custom transformation logic to reshape the data for HubSpot's schema.

Extracting Users and Messages

Begin by extracting your user base. Query the Richpanel Customers endpoint, handling pagination to pull down the entire list. Store this in a staging database or structured JSON format. You need the Richpanel user_id to map conversations accurately later.

Richpanel groups messages inside conversations. Iterate through the Conversations endpoint to get metadata (status, assignee, tags, creation date). For each conversation, request the associated messages. This is where the 100 calls/minute rate limit becomes the primary bottleneck — if you have 200,000 conversations, you're making at least 200,000 additional API calls just to retrieve the message payloads.

Warning

The multi-store problem: Many Richpanel endpoints require an appClientId parameter — a unique identifier representing a specific store or brand. Find your app client IDs in Richpanel Settings → Connected Apps. If you run multiple stores in Richpanel, you need to extract each store's data separately and decide how to structure them in HubSpot (single portal with brand properties, or separate portals).

How to Load Data into HubSpot Service Hub

Loading data into HubSpot is structurally complex. You cannot simply POST a ticket with an array of messages. HubSpot requires a multi-step relational build for every single conversation. The loading sequence matters because HubSpot requires objects to exist before you can associate them.

Authentication: Private App Tokens (Required)

HubSpot deprecated legacy API key authentication in November 2022. All API requests now require a Private App access token, passed as a Bearer token in the Authorization header:

curl -H "Authorization: Bearer YOUR_PRIVATE_APP_TOKEN" \
     -H "Content-Type: application/json" \
     https://api.hubapi.com/crm/v3/objects/tickets

Create your Private App under HubSpot Settings → Integrations → Private Apps. Scope your token to at minimum: crm.objects.tickets.write, crm.objects.contacts.write, crm.objects.notes.write, crm.objects.emails.write, crm.associations.write, and files.ui_hidden.write for migration use.

Testing environment: HubSpot provides free developer sandbox portals at app.hubspot.com under developer accounts. Always test your migration script against a sandbox portal before running against production. Sandbox portals are isolated — changes do not affect your production HubSpot account.

Step 1: Upsert Contacts

Use the HubSpot Contacts API (/crm/v3/objects/contacts) to create or update contacts. Use the customer's email address as the unique identifier. De-duplicate against existing HubSpot contacts — if your CRM already has contacts, importing Richpanel customers without de-duplication will create duplicates.

Capture the HubSpot contact_id returned by the API and map it against the Richpanel user_id in your staging database. You will need this for associations.

Step 2: Create Custom Properties and Pipeline Stages

Before creating tickets, set up custom properties in HubSpot for any Richpanel-specific fields: order ID, CSAT score, channel source, Richpanel conversation ID (for cross-referencing and rollback). Create ticket pipelines and stages that map to your Richpanel conversation statuses (Open, Pending, Resolved, Closed).

Why store richpanel_conversation_id: If a batch of tickets fails mid-migration, you need a way to identify which Richpanel conversations were successfully loaded and which weren't. Storing richpanel_conversation_id as a custom property on every HubSpot ticket allows you to query HubSpot for existing records before re-running a failed batch — preventing duplicates without a full re-extraction from Richpanel.

Field length limits: HubSpot text properties have a maximum of 65,536 characters. textarea properties support up to 65,536 characters as well, but single-line text fields are capped at 255 characters. Long email bodies in Engagements that exceed field limits will be silently truncated. Store message bodies in textarea or html_text fields, not single-line text properties.

Step 3: Create Tickets

Use the Tickets API (/crm/v3/objects/tickets) to create the ticket container.

You must map the Richpanel status (e.g., Open, Pending, Resolved) to HubSpot's specific hs_pipeline_stage internal IDs. Do not pass the string "Closed" — you must pass the exact alphanumeric ID of the pipeline stage in your specific HubSpot portal. Passing status strings instead of stage IDs will fail silently or error.

To create new tickets, make a POST request to the tickets endpoint. Include ticket data in a properties object. You can also add an associations object to associate your new ticket with existing records (contacts, companies) or activities (meetings, notes).

When creating a new ticket, include subject (the ticket's name), hs_pipeline_stage (the ticket's status), and hs_pipeline if you have multiple pipelines.

// Example HubSpot Ticket Payload
{
  "properties": {
    "hs_pipeline": "0",
    "hs_pipeline_stage": "4",
    "subject": "Where is my order?",
    "content": "Original ticket created in Richpanel.",
    "createdate": "2023-10-15T14:30:00Z",
    "richpanel_order_id": "RP-12345",
    "richpanel_conversation_id": "conv_abc123"
  }
}

Step 4: Handle Attachments via the File API

Before you can create the messages (Engagements), handle any file attachments (images, PDFs, receipts) included in the Richpanel messages:

  1. Download the file from the Richpanel URL to your local server.
  2. Upload the file to the HubSpot File Manager API (/filemanager/api/v3/files/upload).
  3. Set the folderPath to something hidden (e.g., migration_attachments) so it doesn't clutter the marketing team's file manager.
  4. Capture the returned HubSpot file_id.

Step 5: Create Engagements (The Messages)

For every message in the Richpanel conversation, create an Engagement in HubSpot.

Use /crm/v3/objects/emails for customer/agent replies and /crm/v3/objects/notes for internal agent whispers. When creating the Engagement, pass the file_id from Step 4 into the hs_attachment_ids property. Set hs_timestamp to the original Richpanel message creation time to preserve chronological ordering.

HTML vs. plain text fidelity: Richpanel stores many message bodies as HTML (inline styling, image tags, anchor elements). HubSpot Email Engagements accept HTML in the hs_email_html property and plain text in hs_email_text. If you push raw HTML into hs_email_text, the angle brackets will display as literal characters in the HubSpot UI. Always map Richpanel HTML message bodies to hs_email_html and strip or convert a plain-text version for hs_email_text. For Note Engagements, the hs_note_body property accepts basic HTML, but complex inline styles may be stripped by HubSpot's sanitizer.

Step 6: The Associations API

This is the most critical step. At this point, you have a Contact, a Ticket, and several Engagements floating independently in HubSpot. You must link them together using the Associations API (/crm/v3/associations/{fromObjectType}/{toObjectType}/batch).

The Associations API requires specific associationTypeId values — you cannot pass string labels. Key type IDs for migration:

Association associationTypeId
Contact → Ticket 16
Ticket → Contact 15
Email Engagement → Ticket 210
Ticket → Email Engagement 211
Email Engagement → Contact 198
Note Engagement → Ticket 214
Note Engagement → Contact 202

For a single migrated ticket, you must execute:

  • Associate Contact → Ticket (typeId: 16)
  • Associate Email Engagement 1 → Ticket (typeId: 210)
  • Associate Email Engagement 1 → Contact (typeId: 198)
  • Associate Email Engagement 2 → Ticket (typeId: 210)
  • Associate Email Engagement 2 → Contact (typeId: 198)

If you skip associating the Engagements to the Contact, the ticket thread will appear on the Ticket record, but it will not show up on the customer's centralized CRM timeline.

Warning

Association type IDs can vary by portal configuration and HubSpot updates. Validate the IDs above against your specific portal using GET /crm/v4/associations/{fromObjectType}/{toObjectType}/labels before running at scale. Using a wrong associationTypeId produces a 400 error rather than a silent failure, so these are detectable.

Batch Endpoints and HubSpot Rate Limits

Use batch endpoints wherever possible. A batch read of 100 contacts costs 1 API request, not 100. Refactor any loop that reads single records. The same principle applies to batch create — POST /crm/v3/objects/tickets/batch/create accepts up to 100 tickets per call.

HubSpot Pro and Enterprise accounts have 100 requests per 10 seconds and 250,000 requests per day, with separate limits on Search API (4 requests per second).

HubSpot uses a token bucket model for rate limiting — imagine a bucket holding 100 tokens (for a Starter account). Every request removes one token. The bucket refills at roughly 10 tokens per second. When the bucket is empty, you get a 429.

For a migration loading 50K tickets with associated engagements (~150K total API calls including associations), expect roughly 4–6 hours of loading time at a sustained rate with proper backoff logic.

HubSpot CSV Import (Limited Alternative)

HubSpot's import tool lets you add objects like contacts, companies, deals, and tickets by uploading a spreadsheet and mapping its columns to HubSpot properties to create new records, update existing ones, and define relationships.

This works for Contacts and basic Ticket records but does not support importing Engagements (emails, notes) or creating Conversation threads. If you need message history on tickets, you must use the API.

The Help Desk Workspace Gotcha

This is the single most common surprise in HubSpot Service Hub migrations (a structural quirk we also highlight in our Help Scout to HubSpot Service Hub migration guide).

Creating a ticket via the API works — it creates a Contact record and a Ticket with relevant properties and associations. However, it doesn't display the Ticket Details in the Help Desk conversation thread. The ticket is added to the Help Desk queue, but the original message is ignored, and agents have no context.

When you associate an Email engagement with a Ticket, you see no Conversations associated with that Ticket in the Help Desk view. However, you should see that associated Email when viewing the Ticket's Activities timeline.

In practice, this means:

  • Migrated tickets appear in Help Desk but with empty conversation threads
  • Message history is visible on the Ticket record's Activity Timeline — agents can see it, but not from the Help Desk workspace's conversation pane
  • Only tickets created through HubSpot's native channels (connected inbox, chat, forms) automatically generate conversation threads
Danger

This is a platform limitation, not a migration bug. HubSpot distinguishes between "Engagement" objects (API-created emails and notes) and "Conversation" objects (native channel messages). There is currently no public API to create Conversation thread objects. Your migrated ticket history will live on the Activity Timeline, not in the conversation pane. Set agent expectations before cutover.

Preserving Historical Timestamps

A common failure mode in helpdesk migrations is losing the original timestamp of a ticket. If you do not explicitly set the creation dates, HubSpot will stamp every migrated ticket and message with today's date.

To prevent this, pass the original Richpanel timestamp into the createdate property during the initial POST request. For engagements, set hs_timestamp to the original Richpanel message creation time. HubSpot accepts ISO 8601 formatted datetime strings (e.g., 2023-10-15T14:30:00Z) or UNIX timestamps in milliseconds.

Important: If you update a ticket after initial creation — for example, to add a custom property you forgot — HubSpot may overwrite hs_lastmodifieddate but will not overwrite createdate if it was explicitly set on creation. Always set createdate in the original POST body, not in a subsequent PATCH. Verify this behavior in a sandbox portal before running at scale.

Error Taxonomy: How Failures Manifest

Not all HubSpot API failures are equal. Understanding how different error types surface prevents hours of debugging:

Error Type HTTP Status Cause Detection
Invalid pipeline stage string 400 Passing "Closed" instead of stage ID Returns error body with invalidInput
Wrong associationTypeId 400 Using string labels or incorrect numeric ID Returns INVALID_ASSOCIATION_TYPE error
Rate limit exceeded 429 Exceeding 100 req/10 sec Retry-After header present
Missing required property 400 No subject or hs_pipeline_stage Returns MISSING_REQUIRED_FIELD
Duplicate contact on create 409 Contact with email already exists Use upsert endpoint to prevent
HTML in plain-text field Silent truncation or garbled display hs_email_html content placed in hs_email_text Visual inspection of migrated records
File attachment not linked 200 (silent) File uploaded but hs_attachment_ids not set Engagement exists with no attachment
Field length exceeded Silent truncation Text > 65,536 chars in textarea field Compare character counts pre/post

The most dangerous failure modes are the silent ones — where HubSpot returns 200 OK but the data is incomplete. HTML-in-plain-text, unlinked attachments, and truncated long-form message bodies all return 200 responses. These require sample auditing, not just status code checking.

What Doesn't Transfer (and Must Be Rebuilt)

Data migrates; logic does not. Automation rules, self-service portal flows, and widget configurations do not transfer — they require manual recreation on whatever platform you move to.

Here's the full list of Richpanel features with no migration path:

  • Self-service portal flows: Richpanel's UI-driven self-service (order tracking, returns, cancellations) has no HubSpot equivalent. Build this with HubSpot's Knowledge Base, Chatflows, or a custom portal.
  • Automation rules: Richpanel's auto-assignment, auto-tagging, and routing rules must be rebuilt as HubSpot Workflows (requires Service Hub Professional or Enterprise).
  • Macros and canned responses: Must be manually copied and recreated as HubSpot Snippets or Templates.
  • CSAT survey configuration: Rebuild in HubSpot's Customer Feedback tool.
  • SLA policies: Recreate in HubSpot's SLA settings (available on Professional+).
  • Richpanel AI agent SOPs: These don't transfer. If you're using HubSpot's Breeze AI, you'll need to retrain it on your knowledge base and response patterns.
  • Custom agent views: Filtered views in Richpanel must be rebuilt as saved Ticket Views in HubSpot.
  • Shopify deep integration: Richpanel's native order actions (refund, cancel, exchange from within the helpdesk) don't exist in HubSpot out of the box. You'll need the HubSpot-Shopify integration plus potentially custom workflows.

The Delta Sync Strategy (Zero Downtime)

Migrating 100,000+ tickets takes time. Because API rate limits restrict how fast you can push data into HubSpot, a full migration might take several days to process. During this time, your support team must continue working in Richpanel.

Because Richpanel does not support webhooks for real-time event streaming, all delta capture must be poll-based. Use the updatedAt filter on the Richpanel Conversations endpoint with a timestamp corresponding to when your last extraction completed. This identifies new and modified conversations since your previous run.

To achieve zero downtime, execute a phased delta sync:

  1. The Historical Load: Extract and load all tickets closed prior to your migration start date. This moves ~90% of your data without impacting active operations.
  2. The Active Load: Move all "Open" and "Pending" tickets over a weekend. Instruct your agents to log out of Richpanel on Friday and log into HubSpot on Monday.
  3. The Delta Catch-up: Run a final script that queries Richpanel for any tickets created or updated during the weekend cutover window (using updatedAt filter), and upsert those changes into HubSpot using richpanel_conversation_id to match against existing records.
  4. Channel redirect: Redirect incoming channels (email, chat, social) to HubSpot. Disable Richpanel's active channels to prevent split-brain (tickets landing in both systems).
  5. Agent briefing: Brief agents on where to find migrated history (Activity Timeline, not Help Desk conversation pane).

This phased approach ensures data integrity without forcing your support team to halt operations.

Validating the Migration

Never assume the API calls succeeded just because you received a 200 OK response. You must validate the data payload.

  • Count check: Total tickets in HubSpot should match total conversations in Richpanel.
  • Sample audit: Pick 50–100 random tickets and programmatically verify that the number of messages in Richpanel matches the number of Engagements associated with that ticket in HubSpot.
  • Association check: Every ticket should be associated with a Contact. Every Engagement should be associated with both its parent Ticket and the Contact. Use GET /crm/v3/associations/ticket/contact/batch/read to verify at scale.
  • Attachment check: Manually inspect 10–20 attachment-heavy tickets in the HubSpot UI to ensure files open correctly and HTML formatting is preserved.
  • HTML fidelity check: Open 10–20 tickets that contained HTML-formatted messages in Richpanel and confirm the formatting renders correctly in HubSpot — not as raw angle brackets.
  • Owner check: Confirm agent/owner assignments are correct.
  • Timestamp check: Verify that ticket creation dates and message timestamps reflect the original Richpanel dates, not the migration date.
  • Truncation check: For any conversation with unusually long messages (customer emails, order notes), compare character counts between Richpanel source and HubSpot destination to detect silent truncation.

Common Failure Modes

1. Relying on CSV export for message content. Richpanel's CSV export is useful for metadata but unreliable for full message bodies. Always extract via API.

2. Not accounting for the 100 calls/minute rate limit and page size. At 100 calls/min and 50 conversations per page, a 50K conversation extraction requires ~51K API calls (~8.5 hours for list + detail calls combined, before attachments). Plan for this. Don't schedule extraction during business hours if your team is still actively using Richpanel.

3. Expecting migrated tickets to work like native Help Desk tickets. They won't. The Help Desk conversation pane will be empty. Train agents before cutover.

4. Skipping de-duplication. If your HubSpot CRM already has contacts, importing Richpanel customers without de-duplication will create duplicates. Always match on email before creating new contact records.

5. Forgetting the multi-store problem. If you run multiple stores in Richpanel, each with its own appClientId, you need to extract each store's data separately and decide how to structure them in HubSpot.

6. Using wrong or hardcoded associationTypeId values. The Associations API returns a 400 error for invalid type IDs, but using a valid-but-wrong type ID (one that exists but maps to the wrong relationship) will silently create incorrect associations. Always validate type IDs for your specific portal using the labels endpoint before bulk runs.

7. Pushing HTML message bodies into plain-text fields. This produces garbled output (raw HTML tags) in the HubSpot UI and returns 200 OK — it won't surface in your error logs. Always map Richpanel HTML bodies to hs_email_html, not hs_email_text.

8. Using legacy API key authentication. HubSpot deprecated API keys in November 2022. Scripts using hapikey=YOUR_KEY query parameters will fail. Use Private App Bearer tokens.

Timeline and Resource Planning

Scenario Dataset Size Team Timeline
Small DTC brand <10K conversations, no orders migration 1 engineer 1–2 weeks
Mid-size e-commerce 10K–50K conversations, order data 1–2 engineers 2–3 weeks
Multi-store operation 50K+ conversations, multiple brands, attachments 2+ engineers 3–5 weeks

Most of the time is spent on extraction (40%), transformation and edge-case handling (30%), and validation (20%). The actual HubSpot loading is fast — typically under a day for most datasets.

Plan 1–3 weeks for a complete migration, with most of that time spent on workflow reconstruction rather than data transfer.

If you're also rebuilding self-service flows, automation rules, and knowledge base content, add another 1–2 weeks to the timeline.

When to Self-Serve vs. When to Get Help

Self-serve if:

  • Under 10K conversations
  • No attachment-heavy tickets
  • No order/subscription data to migrate
  • You have an engineer comfortable with REST APIs and HubSpot's CRM API
  • You accept that migrated history lives on the Activity Timeline only

Get help if:

  • Over 50K conversations
  • Multi-store Richpanel setup
  • Complex order data that needs Custom Objects
  • You need attachment migration with full fidelity
  • You can't afford to lose any conversation history
  • You don't have engineering bandwidth for a 2–3 week project

We've handled migrations from Richpanel and other e-commerce helpdesks at ClonePartner — our Richpanel alternatives guide covers the broader landscape if you're still evaluating. For teams that have already decided on HubSpot, our HubSpot Service Hub migration checklist covers the destination-side setup in detail.

Frequently Asked Questions

Can I migrate Richpanel conversation history to HubSpot Service Hub?
Yes, but with a limitation. Conversation messages are migrated as HubSpot Engagement objects (emails and notes) and appear on the ticket's Activity Timeline. They do not appear in the Help Desk workspace's conversation thread pane — that only shows messages from HubSpot's native channels.
How long does a Richpanel to HubSpot migration take?
1–3 weeks for teams with under 50K conversations, 3–5 weeks for larger multi-store setups. Richpanel's API rate limit of 100 calls per minute is the main extraction bottleneck. Workflow and automation reconstruction adds 1–2 weeks on top.
Can I migrate Shopify order history from Richpanel to HubSpot?
Yes, but it requires mapping. You can use HubSpot's native Shopify integration to sync orders as Deals, create Custom Objects (Enterprise only), or map specific order data to custom Ticket properties during the migration.
Do Richpanel automation rules transfer to HubSpot?
No. Richpanel automation rules, self-service portal flows, macros, and widget configurations have no export mechanism. They must be manually rebuilt as HubSpot Workflows, Snippets, Knowledge Base articles, and Chatflows.
How do I keep ticket timestamps accurate during the migration?
You must explicitly pass the original Richpanel timestamps into the createdate or hs_createdate properties when making POST requests to HubSpot's APIs. For engagements, use hs_timestamp. Otherwise, HubSpot defaults to the date of the API call.

More from our Blog