Skip to main content

Tejas Mondeeri

·10 min read

An In-Depth Guide to Migrating from Zendesk Sell to HubSpot

This guide provides an in-depth approach for migrating data from Zendesk Sell to HubSpot CRM. This process relies heavily on the RESTful APIs of both platforms, emphasizing object mapping, sequential migration, and robust handling of associated data and rate limits.

ClonePartner Zendesk Sell to Hubspot

Moving from Zendesk Sell to HubSpot is more than a simple export and import. Zendesk Sell organizes its data with key nuances you'll want to preserve. This guide walks through how to map each concept one-to-one, handle all the nuances, and execute a zero-downtime cutover with reconciliation and deltas.

Complexity score: 4/5

Phase 1: Pre-Migration Planning, Mapping, and Setup

A successful migration requires understanding the inherent differences in how Zendesk Sell and HubSpot CRM structure their data, particularly around core objects and their relationships.

1.1 Data Model Comparison and Mapping

Zendesk Sell Object (Source)

HubSpot CRM Object (Target)

Key Mapping Notes

Contact (is_organization: true)

Company

Map Zendesk name to HubSpot name and/or domain. Domain is the recommended primary unique identifier in HubSpot.

Contact (is_organization: false)

Contact

Map Zendesk first_name, last_name, and email to HubSpot contact properties. Email is the recommended primary unique identifier.

Lead

Lead

Requires association with an existing Contact (Person).

Deal

Deal

Map pipeline, stages, and financial data.

Pipelines & Stages

Pipelines & Stages (e.g., for Deals)

Map likelihoods/probabilities for stages.

Product

Product

Requires name, price, hs_sku.

Order & Line Item

Order & Line Item

Zendesk Line Items link products to an Order, which is associated with a Deal. HubSpot Line Items are created and linked directly to the Deal or Order.

Call

Call (Activity)

Must be logged with an hs_timestamp.

Text Message

Communication (Activity)

Logged using hs_communication_channel_type (SMS, WHATS_APP, LINKEDIN_MESSAGE) and hs_timestamp.

Note

Note (Activity)

Requires hs_timestamp.

Task

Task (Activity)

Requires hs_timestamp. Must be associated with a Contact, Deal, or Lead.

Custom Fields

Custom Properties

Must be created in HubSpot prior to data import.

1.2 Setting Up API Access

Your migration application requires valid authentication for both platforms.

Zendesk Sell Authentication

Authentication for the Sell Core API must include a valid Access Token. This token is typically generated as a Personal Access Token in the Sell account settings and must be securely stored. All API requests use the Authorization: Bearer $ACCESS_TOKEN header.

HubSpot CRM Authentication

HubSpot APIs typically use OAuth 2.0 or Private Apps (static auth tokens) for secure access.

  1. Generate Initial Tokens: If using OAuth, acquire the initial Access Token and Refresh Token by making a URL-form encoded POST request to /oauth/v1/token, supplying the client_id, client_secret, redirect_uri, and the authorization code.
  2. Token Refreshment: Access Tokens are short-lived (lifetime defined by expires_in). Use the Refresh Token to obtain a new Access Token via a POST request to /oauth/v1/token with grant_type=refresh_token, client_id, client_secret, and refresh_token.

1.3 Rate Limit Management (Crucial for Bulk Migration)

HubSpot imposes strict rate limits, which must be handled using batch processing and throttling to avoid 429 Too Many Requests errors.

  • Standard Limits: Depending on the HubSpot subscription tier, the limit can range from 100 to 190 requests per 10 seconds per app (for Professional/Enterprise tiers, it may be 150 requests/10 seconds for association APIs). Daily limits also apply (e.g., 625,000 to 1,000,000 requests per day for Professional/Enterprise).
  • Batch APIs: Utilize HubSpot's batch endpoints for creation, reading, and updating whenever possible. For example, batch operations for contacts are limited to 100 records per request.
    • Example Batch Create: POST /crm/v3/objects/{objectType}/batch/create
    • Example Batch Update: POST /crm/v3/objects/{objectType}/batch/update
    • Example Batch Upsert: POST /crm/v3/objects/{objectType}/batch/upsert

1.4 ID Mapping Strategy

During migration, every Zendesk object ID must be mapped and linked to its corresponding newly created HubSpot Record ID (hs_object_id). This ID map is crucial for establishing cross-object associations (e.g., linking a Zendesk Deal ID to the correct HubSpot Contact and Company IDs).

Phase 2: The Migration Process

Execute the migration sequentially, ensuring foundational data structures and linking entities are created before dependent records are migrated.

Step 1: Migrate Users (Owners)
  1. Fetch Zendesk Users: Retrieve all users using GET /v2/users. Note the Zendesk User ID (id) for mapping purposes.
  2. Map to HubSpot Owners: While direct creation via API is limited, ensure corresponding users exist in HubSpot and map the Zendesk User ID to the HubSpot User/Owner ID. This ID will be used to populate the hubspot_owner_id property on contacts, companies, and deals.
Step 2: Migrate Pipelines and Stages

HubSpot supports pipelines for various objects, including Deals, Orders, and Leads.

  1. Fetch Zendesk Pipelines: Retrieve pipeline definitions using GET /v2/pipelines.
  2. Create HubSpot Pipelines: Create pipelines in HubSpot using POST /crm/v3/pipelines/{objectType}. For deals (CRM migration), use objectType=deals. Map the old pipeline ID to the new HubSpot Pipeline ID.
  3. Fetch Zendesk Stages: Retrieve stage definitions using GET /v2/stages, filtering by pipeline ID (pipeline_id). Note the stage name, position, category, and likelihood.
  4. Create HubSpot Stages: For each stage, create it in HubSpot using POST /crm/v3/pipelines/{objectType}/{pipelineId}/stages.
    • Crucial Mapping: For Deal stages, the metadata object is required and must include the probability field (ranging 0.0 to 1.0), reflecting the Zendesk likelihood field.
Step 3: Recreate Custom Fields (Properties)

Custom fields from Zendesk Sell must be pre-defined as Custom Properties in HubSpot.

  1. Fetch Zendesk Custom Field Definitions: Retrieve definitions for relevant resource types (contact, lead, deal) using GET /v2/:resource_type/custom_fields. Note the field name and type (e.g., string, number, list, address).
  2. Create HubSpot Custom Properties: Use the HubSpot Properties API to recreate these fields, matching data types where possible. Custom properties are created via a POST request to /crm/v3/properties/{objectTypeId} (e.g., /crm/v3/properties/0-1 for contacts).
  3. Map Field Keys: Map the original Zendesk custom field names to the new HubSpot internal property names (e.g., p_portalId_customfieldname).
Step 4: Migrate Organizations and Persons (Zendesk Contacts)

Use the Zendesk is_organization flag to split contacts into HubSpot Companies and Contacts.

  1. Migrate Companies (Organizations):
    • Filter and fetch Zendesk Contacts where is_organization is true using GET /v2/contacts.
    • Create HubSpot Company records using POST /crm/v3/objects/companies/batch/create (or upsert by domain: POST /crm/v3/objects/companies/batch/upsert). Store ID mappings.
  2. Migrate Contacts (Persons):
    • Filter and fetch Zendesk Contacts where is_organization is false using GET /v2/contacts.
    • Create HubSpot Contact records using POST /crm/v3/objects/contacts/batch/create (or upsert by email: POST /crm/v3/objects/contacts/batch/upsert?idProperty=email). Store ID mappings.
  3. Re-establish Contact-to-Company Association:
    • For each migrated HubSpot Contact, check the original Zendesk Contact's contact_id (which links to the organization/company).
    • Use the stored ID mappings to link the HubSpot Contact ID to the corresponding HubSpot Company ID using the Associations API (/crm/v3/objects/{contactId}/associations/{toObjectType}/{toObjectId}/{associationTypeId}). Use the default association ID for Contact to Company (279) or Company to Contact (280).
Step 5: Migrate Leads
  1. Fetch Zendesk Leads: Retrieve all leads using GET /v2/leads.
  2. Create HubSpot Leads: Create HubSpot Lead records using POST /crm/v3/objects/leads/batch/create or individually using POST /crm/v3/objects/leads.
    • Mandatory Properties: HubSpot Leads require hs_lead_name and must be associated with an existing contact (person) at creation.
    • Association: Use the mapped Contact IDs for association. Use association Type ID 578 for Lead to Primary Contact.
Step 6: Migrate Deals
  1. Fetch Zendesk Deals: Retrieve all deals using GET /v2/deals.
  2. Create HubSpot Deals: Use POST /crm/v3/objects/deals/batch/create or individual create calls (/crm/v3/objects/deals).
    • Mandatory Properties: Include dealname, dealstage, and pipeline using the mapped internal IDs from Step 2.
    • Ownership & Values: Populate hubspot_owner_id using the User ID map, and map Zendesk value (which can be string or number) to the HubSpot amount property.
    • Loss/Unqualified Reasons: Fetch reason text from Zendesk (GET /v2/loss_reasons/:id or /v2/deal_unqualified_reasons/:id). Store this text in a custom HubSpot Deal property or as a Note associated with the deal, as HubSpot does not use explicit Loss Reason objects.
  3. Re-establish Deal Associations: Associate the new HubSpot Deal ID with the corresponding Contact (Person) and Company (Organization) IDs using the Associations API:
    • Deal to Contact: Use Type ID 3.
    • Deal to Company: Use Type ID 5 (Primary) or 341 (Unlabeled).
Step 7: Migrate Products and Line Items

This process involves moving the catalog first, then recreating the association to deals via line items.

  1. Migrate Products:
    • Fetch Zendesk Products using GET /v2/products. Note properties like name, sku, price, and prices array (for currency data).
    • Create HubSpot Products using POST crm/v3/objects/products. Map name, sku, and pricing information. Store Product ID mappings.
  2. Migrate Orders and Line Items:
    • Fetch Zendesk Orders associated with deals using GET /v2/orders?deal_id={dealId}. Create corresponding HubSpot Orders (POST crm/v3/objects/order) and map the IDs.
    • For each Zendesk Order, fetch associated Line Items (GET /v2/orders/:order_id/line_items). Note the product_id, quantity, and value.
    • Create HubSpot Line Items (POST /crm/v3/objects/line_items). The request must include the new Line Item properties (name, quantity, price).
    • Crucial Association: In the Line Item creation payload, associate the new Line Item with the corresponding HubSpot Deal ID and/or Order ID.
      • Line Item to Deal associationTypeId: 20.
      • Line Item to Order associationTypeId: 514.
    • Note: Ensure Line Items are created as instances linked to a single parent object to prevent data loss or corruption.
Step 8: Migrate Activities (Notes, Calls, Communications/Text Messages)

Activities (Engagements) must be associated with the corresponding HubSpot records using the mapped IDs.

  1. Notes:
    • Fetch Zendesk Notes (GET /v2/notes), noting the content, created_at, resource_type, and resource_id.
    • Create HubSpot Notes (POST /crm/v3/objects/0-46). The body must include the note content and hs_timestamp.
    • Associate the new Note ID with the corresponding HubSpot Contact, Company, or Deal ID.
  2. Calls:
    • Fetch Zendesk Calls (GET /v2/calls), noting details like summary, duration, phone_number, and associated IDs.
    • Create HubSpot Calls (POST /crm/v3/objects/0-48). The call record requires hs_timestamp. Map the call metadata and association information.
  3. Text Messages (Communications):
    • Fetch Zendesk Text Messages (GET /v2/text_messages).
    • Create HubSpot Communications (POST /crm/v3/objects/communications). Set properties like hs_communication_channel_type (e.g., "SMS"), hs_communication_body (content), and hs_timestamp.
    • Associate the communication with the relevant Contact or Deal using the appropriate Type IDs (e.g., Company to Communication: 87, Contact to Communication: 81).
Step 9: Migrate Documents and Files
  1. Retrieve File URLs: Fetch document metadata from Zendesk (GET /v2/documents) to retrieve the expiring download_url for each file.
  2. Download and Upload: Download the file content using the temporary URL. Upload the file content to HubSpot CMS using the HubSpot CMS APIs.

Phase 3: Post-Migration & Best Practices

3.1 Data Validation and Reconciliation

After migrating data in batches, perform crucial verification steps:

  • Count Verification: Compare the total count of key entities (Contacts/Persons, Companies/Organizations, Deals, Line Items) between Zendesk Sell and HubSpot.
  • Spot Checks: Perform manual spot checks on complex records (e.g., deals associated with multiple contacts, several activities, and products) to ensure all links and property values were correctly transferred and mapped.
  • Association Integrity: Verify crucial relationships using the HubSpot Associations API. For example, check a sample of Contact records to ensure they are correctly associated with their primary Company.

3.2 Handling Deltas and Cutover

For a zero-downtime migration, a final delta synchronization is often necessary.

  1. Initial Freeze: Coordinate a period where sales activity is temporarily paused in Zendesk Sell.
  2. Delta Sync: Use the updated_at timestamps recorded during the initial bulk export from Zendesk Sell (available on almost all Zendesk objects) to fetch only records updated since that time.
  3. Upsert to HubSpot: Use HubSpot's batch upsert endpoints (POST /crm/v3/objects/{objectType}/batch/upsert) for Contacts, Companies, and Deals using unique identifiers (like email or domain) to efficiently update existing records or create new ones in one call.

3.3 Leveraging Batch Operations and Throttling

To optimize transfer speed while respecting HubSpot's API limits (e.g., 100-190 requests per 10 seconds):

  • Chunking: Break large transfers into small batches (max 100 inputs for standard batch operations).
  • Throttling: Implement rate-limiting logic that monitors API usage headers and throttles requests immediately upon receiving a 429 error, waiting before retrying.
  • Caching: When repeatedly querying HubSpot for read-only data (like Pipeline IDs or Owner IDs), cache the results locally to reduce API call volume.
  • Webhooks: For ongoing data synchronization post-migration, leverage HubSpot's Webhooks feature to receive real-time notifications about data changes instead of continuous polling, which does not count toward standard API limits if triggered via workflows (HubSpot Marketing Enterprise required).

Further Resources: