Skip to content

LiveAgent to Intercom Migration: The Technical Guide

Technical guide to migrating from LiveAgent to Intercom — covering API constraints, data model mapping, object relationships, rate limits, and validation.

Abdul Abdul · · 34 min read
LiveAgent to Intercom Migration: The 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

LiveAgent to Intercom Migration: The Technical Guide

Migrating from LiveAgent to Intercom means moving from a traditional multi-channel helpdesk built around email-centric ticketing into a conversation-first platform with a fundamentally different data model. LiveAgent treats every interaction — email, chat, call, social message — as a ticket with messages attached. Intercom separates conversations (back-and-forth messaging) from tickets (trackable requests with states and SLAs), and centers everything around a Contact timeline.

This architectural mismatch means a simple CSV export will not work for anything beyond basic contact records. Preserving historical context, attachment integrity, and multi-relational links (Contact → Company → Conversation → Teammate) requires a programmatic, API-led approach.

If you want the short version: LiveAgent's ticket-centric architecture does not map 1:1 to Intercom's conversation and contact model. The hard parts are custom fields, attachments, multi-message thread reconstruction, and LiveAgent's 180-request-per-minute API rate limit on the extraction side. (support.liveagent.com)

Why Companies Migrate from LiveAgent to Intercom

Based on patterns across hundreds of migrations, here are the concrete reasons teams make this move:

  • Conversational support model: Intercom's messenger-first architecture supports in-app messaging, proactive outreach, and AI-powered resolution via Fin — which can autonomously resolve up to 50% of support volume according to Intercom's published benchmarks. LiveAgent has no native equivalent to embedded in-app messaging or AI resolution agents.
  • Product-led growth alignment: Teams building SaaS or subscription products need Intercom's behavioral event tracking, product tours, and event-driven messaging tied directly to their app. LiveAgent lacks native user-event ingestion for triggering contextual messages.
  • Consolidation: Companies already using Intercom for marketing or sales want support on the same platform. Running LiveAgent alongside Intercom means paying for two platforms, maintaining two integrations, and splitting customer context across systems.
  • Automation sophistication: Intercom's visual workflow builder supports branching logic, conditional paths, API webhooks, and Fin AI agent handoffs. LiveAgent's automation is limited to flat trigger-action rules without visual orchestration or AI components.

Core Architecture Differences

The architectural gap matters more than feature checklists. If you skip this model shift, you end up with clean imports and unusable data.

Concept LiveAgent Intercom
Primary object Ticket (email-centric) Conversation / Ticket (two distinct objects)
Customer record Contact + Company (1:1 relationship) Contact (User or Lead) + Company (many-to-many)
Agent grouping Departments Teams
Custom fields Contact fields, Ticket fields Custom Data Attributes (CDAs) — 250 active limit, 255-char text cap, 35-option dropdown cap
Knowledge base KB Articles + Categories Help Center Articles + Collections
Automation Rules (trigger-based, flat) Workflows (visual builder with branching)
Chat history Stored as ticket messages Conversation parts (500 max per conversation)
API architecture REST v3 (key-based auth, 180 req/min) REST v2.11+ (OAuth / token, 10K req/min)
Call recordings Native VoIP with stored recordings No native call recording object

LiveAgent exposes channel-rich ticket history and lets each contact belong to one company. Intercom splits work between conversations and tickets, makes companies visible only after a contact is associated, and uses a simpler operational schema. (support.liveagent.com)

Migration Approaches: Which Method Fits Your Scenario

1. Native CSV Export + Manual Import

How it works: Export contacts and ticket lists from LiveAgent's UI as CSV files. Transform the data in a spreadsheet or script, then use Intercom's API to import contacts. Intercom does not have a CSV import UI for conversations — you still need the API on the import side. (intercom.com)

When to use it: Small datasets under ~5,000 contacts with minimal ticket history you need to preserve.

Pros:

  • No code required for the export step
  • Good for contact-only migrations

Cons:

  • LiveAgent's CSV export captures ticket metadata but not full message threads with attachments (support.liveagent.com)
  • Intercom has no native CSV import for conversations
  • No relationship preservation (contact-to-company links, ticket-to-contact associations)
  • Intercom's CSV importer has a 20 MB limit and can create duplicates if user_id usage is inconsistent
  • Company CSV import is not supported in Intercom

Complexity: Low (export) / Medium (import) · Scalability: Poor beyond a few thousand records

2. API-to-API Migration (Custom Script)

How it works: Write a script that reads from LiveAgent's REST API v3 and writes to Intercom's REST API. Extract tickets, contacts, companies, and tags; transform the data structure; load into Intercom in dependency order.

When to use it: Mid-size to large migrations where you need full message history, attachments, and relationship preservation.

Pros:

  • Full control over data transformation
  • Can preserve message threads, timestamps, and agent attribution
  • Supports delta runs for catching records created during migration

Cons:

  • LiveAgent's cloud API is rate-limited to 180 requests per minute per API key, and GET /tickets is capped at 10,000 results per filtered request — extracting 100K tickets at this rate takes approximately 9.3 hours of pure API time, not counting message extraction (support.liveagent.com)
  • Intercom has no bulk create endpoint for contacts — each contact requires an individual API call
  • Requires solid error handling, retry logic with exponential backoff, and state management with checkpointing
  • Typical engineering effort: 2–4 weeks for one developer, including testing and validation

Complexity: High · Scalability: Good with proper batching and rate-limit management

3. Third-Party Migration Tools

How it works: Services like Help Desk Migration offer automated wizards that connect to both platforms and handle mapping. Current Intercom first-party docs describe people CSV imports, a Zendesk import, and scripted historical migrations — not a LiveAgent-specific one-click importer. (intercom.com)

When to use it: When you want a faster turnaround without writing custom code and your data model is relatively standard.

Pros:

  • Pre-built connectors for both platforms
  • Visual mapping interface
  • Delta migration support

Cons:

  • Limited customization for complex field transformations
  • May not handle all edge cases (inline images, custom objects, call recordings)
  • Per-record pricing can get expensive at scale (typically $2–$10 per 1,000 records depending on provider and complexity tier)
  • Many tools are fine at record creation and weak at replaying thread history with correct chronological ordering

Complexity: Low to Medium · Scalability: Moderate

4. Custom ETL Pipeline

How it works: Build an extract-transform-load pipeline using Python scripts, Node.js workers, or data pipeline frameworks (Airflow, Dagster, Prefect). Extract from LiveAgent API (or database dump), transform in a staging layer (PostgreSQL, SQLite, or flat JSON files), load via Intercom API. LiveAgent can provide a database dump to paying customers leaving the platform, but the dump is raw MySQL tables and LiveAgent still recommends the API for structured extraction. (support.liveagent.com)

When to use it: Enterprise migrations with complex data transformations, multiple data sources, or regulatory requirements (GDPR, SOC 2).

Pros:

  • Maximum flexibility for data transformation
  • Can incorporate data from multiple systems
  • Staging layer allows validation, PII auditing, and data quality checks before loading
  • Strongest rollback and observability story
  • Supports encryption at rest in the staging layer for compliance

Cons:

  • Highest engineering effort (typically 3–6 weeks for one developer)
  • Requires infrastructure for orchestration, logging, and monitoring

Complexity: High · Scalability: Excellent

5. Middleware Platforms (Zapier, Make)

How it works: Use integration platforms to connect LiveAgent triggers/actions with Intercom actions. Zapier's current Intercom app exposes actions like Create Conversation, Reply to Conversation, Create Ticket, and Create/Update User. (zapier.com)

When to use it: Real-time, forward-looking sync between both platforms during a transition period — not for bulk historical migration.

Pros:

  • No-code setup
  • Good for event-driven sync (new ticket → create conversation)

Cons:

  • Not designed for bulk historical data migration
  • Per-task pricing makes large volumes expensive (Zapier charges per task; 300K tasks at Professional tier costs ~$600/month)
  • Limited error handling and no rollback capability
  • Cannot reconstruct multi-message ticket threads in chronological order

Complexity: Low · Scalability: Poor for migration; acceptable for ongoing sync

Approach Comparison

Method Complexity Best For Full History Relationships Cost
CSV Export Low/Med <5K contacts, no tickets Partial No Free
API-to-API Script High Full migrations with history Yes Yes Dev time (2–4 weeks)
Third-Party Tools Low/Med Standard migrations Yes Partial Per-record ($2–10/1K)
Custom ETL High Enterprise, multi-source Yes Yes Dev time (3–6 weeks) + infrastructure
Middleware (Zapier) Low Ongoing sync only No No Per-task (~$600/mo at scale)

Recommendations by Scenario

  • Small business (<5K tickets, <2K contacts): Third-party migration tool or managed service. The engineering effort of a custom script is not justified at this scale.
  • Mid-market (5K–100K tickets): API-to-API script or managed migration service. You need full thread preservation and custom field mapping. Expect 1–3 days of pure extraction time from LiveAgent at 180 req/min.
  • Enterprise (100K+ tickets): Custom ETL pipeline or managed service with staging validation. LiveAgent's 180 req/min rate limit and 10,000-ticket filter cap mean extraction alone for 500K tickets can take 4–7 days. Factor in GDPR/data residency requirements for the staging layer.
  • Ongoing sync during transition: Middleware platform for new records, with a separate bulk migration for historical data.

When to Use a Managed Migration Service

Building a LiveAgent-to-Intercom migration script sounds straightforward until you hit the edge cases. Here is when the engineering cost of DIY exceeds the cost of a managed service:

  • Your ticket volume exceeds 50K records and you cannot afford a multi-day extraction window with retry logic and checkpointing
  • You have complex custom fields that require transformation (LiveAgent picklists → Intercom CDAs with different value formats and a 35-option limit per dropdown)
  • Attachments and inline images need to be downloaded from LiveAgent's authenticated URLs, re-hosted on publicly accessible storage, and re-linked in Intercom conversations
  • Your team does not have spare engineering bandwidth — a migration script is a 2–4 week project for one developer, with testing
  • You need zero downtime — running both systems in parallel during cutover requires orchestration, deduplication logic, and a defined switchover protocol

The hidden cost of DIY is not the extraction loop. It is duplicate remediation in Intercom (where email uniqueness conflicts silently merge records), relationship rebuilds, notification leakage during historical replay, and edge cases like LiveAgent's mixed note IDs after version 5.62 or Intercom's company visibility rules. Based on our experience, teams that underestimate migration complexity typically spend 40–60% more engineering hours debugging than they originally scoped. (support.liveagent.com)

At ClonePartner, we have completed 1,500+ data migrations across helpdesk, CRM, and SaaS platforms. For LiveAgent migrations, we handle the full pipeline: extraction (API or database dump), transformation (field mapping, data cleaning, relationship reconstruction), and loading into Intercom with full validation. Read more about how we run migrations at ClonePartner.

Pre-Migration Planning

A successful migration is 80% planning and 20% execution. Before touching any data, audit what you have and define what you need.

Data Audit

LiveAgent Object Count It Notes
Tickets Total + by status Include resolved/archived. Note the 10K filter cap — use date windowing if total exceeds this.
Contacts Total + duplicates Check for contacts with no tickets and contacts sharing the same email across channels.
Companies Total Verify contact-company links. Orphaned companies will not surface in Intercom UI.
Tags Total Map to Intercom tags. Identify and consolidate synonymous tags.
Custom fields (Contact) List all with data types Check for fields exceeding 255 characters or picklists with >35 options.
Custom fields (Ticket) List all with data types Map to Intercom CDAs. Count total — must stay under 250 active CDAs.
Knowledge base articles Total + categories Map categories to Intercom collections. Note internal links and embedded images.
Attachments Total count + total size in GB Estimate re-hosting needs. Budget ~1 second per attachment for download/upload.
Agents / Departments Total active + inactive Map to Intercom admins/teams. Decide how to handle inactive agents.
Call recordings Total count + total size These have no Intercom destination — plan external archival.

If the team has been using companies, tags, or ticket states as pseudo-accounts or pseudo-pipelines, document that now instead of pretending there is a clean CRM-style object model.

What to Leave Behind

  • Spam tickets — filter these out before migration
  • Test/internal tickets — unless they contain real customer data
  • Duplicate contacts — merge before migration, not after. Intercom's deduplication behavior on import can silently merge records in unexpected ways.
  • Unused custom fields — Intercom has a soft limit of 250 active CDAs; exceeding this requires contacting Intercom support for a limit increase, and performance may degrade
  • Resolved tickets older than your retention policy — archive to CSV or cloud storage instead of migrating
  • Call recordings — archive to S3, GCS, or Azure Blob Storage; link via custom attribute in Intercom

Data Privacy and Compliance Considerations

Migrating customer data between SaaS platforms has regulatory implications:

  • GDPR (EU): Ensure both LiveAgent and Intercom Data Processing Agreements (DPAs) cover the transfer. If using a staging layer, encrypt PII at rest and in transit. LiveAgent stores data in the region selected at account creation; Intercom offers US, EU, and AU data hosting — verify alignment.
  • Data residency: If your staging layer (local disk, cloud VM, database) stores customer data temporarily, it must comply with the same data residency requirements as your production systems.
  • PII handling: During transformation, minimize PII exposure. Do not log email addresses, phone numbers, or message bodies in plain text to migration logs. Use hashed identifiers in log output.
  • Retention: If you are migrating historical data that customers have requested be deleted under GDPR Article 17, exclude those records from the migration set.
  • DPA with migration vendors: If using a third-party migration tool or managed service, ensure they have a DPA in place covering data processing during the migration.

Migration Strategy

  • Big bang: Migrate everything at once over a weekend. Works for datasets under ~20K tickets. Risk: if something fails, you are in limbo with partially loaded data in Intercom and a live LiveAgent instance.
  • Phased: Migrate contacts and companies first, then tickets in batches by date range or department. Lower risk, longer timeline (typically 1–2 weeks for mid-size datasets).
  • Incremental: Migrate historical data first, then run a delta sync to catch records created during the migration window. This is the approach Intercom documents in its own historical migration guidance. (intercom.com)

For most teams, we recommend the phased approach with a delta sync. Migrate contacts and companies first (they are the foundation), then tickets, then knowledge base. Run a final delta sync before cutover.

Tip

The lowest-risk migration pattern: load closed history first into a non-live Intercom workspace, run UAT with 2–3 agents, then execute a final delta run for records changed after the cutoff, and switch DNS/routing to Intercom.

Data Model and Object Mapping

This is where the migration gets real. LiveAgent and Intercom have fundamentally different schemas.

Conversation vs. Ticket: The First Design Decision

Intercom has two target objects for LiveAgent tickets. You need to decide before the first load:

  • Use Conversations when the source record is a customer-facing thread (email, chat, social message)
  • Use Tickets when it behaves more like tracked work, a back-office workflow, or a request that progresses through defined states with SLAs

Intercom requires ticket types to exist before you can create ticket records, and ticket types are created via the Intercom admin UI (not the API), so this decision must happen during planning. (intercom.com)

Decision framework:

  • If >80% of your LiveAgent tickets are customer-facing email/chat threads → default to Conversations
  • If you have distinct ticket categories with defined workflows (e.g., refund requests, bug reports) → create those as Intercom Ticket Types
  • If mixed, split by LiveAgent department or tag — map specific departments to Ticket Types and the rest to Conversations

Object-Level Mapping

LiveAgent Object Intercom Object Notes
Contact Contact (role: user) Match on email. Keep identifier strategy consistent to avoid duplicate matching.
Company Company Create via API with a stable company_id. Companies become visible only after a contact is attached. (intercom.com)
Agent Admin Cannot be created via API — must exist in Intercom first. Map inactive agents to a generic "Legacy Agent" admin to preserve attribution without consuming a paid seat.
Department Team Create manually in Intercom before migration.
Ticket Conversation or Ticket See design decision above. Use POST /conversations for conversations, POST /tickets for tickets.
Ticket message Conversation Part Each message becomes a part. Max 500 parts per conversation.
Internal note Conversation Part (note) Use message_type: "note" for internal notes, message_type: "comment" for public replies. Handle both old and new LiveAgent note-type conventions. (support.liveagent.com)
Tag Tag Create via API, then attach to conversations/contacts.
KB Article Article Map categories to Intercom collections. See Knowledge Base Migration section.
Custom contact field Custom Data Attribute Must be created before importing data.
Custom ticket field Conversation Data Attribute Limited to supported types. List attributes expect target list item IDs, not labels. (developers.intercom.com)
Ticket attachment Conversation part attachment Must be re-uploaded; URLs are not transferable.

Field-Level Mapping: Contacts

LiveAgent Field Intercom Field Type Notes
email email string Primary identifier. Lowercase and trim whitespace before import.
firstname + lastname name string Concatenate — Intercom uses a single name field
phone phone string Direct mapping
company_id company.company_id reference Must link after company creation
city custom_attributes.city string No native city field in Intercom
custom fields custom_attributes.* varies Create CDAs first
dateCreated signed_up_at timestamp Convert to Unix epoch
contactid external_id string Preserve for deduplication and audit

Field-Level Mapping: Tickets → Conversations

LiveAgent Field Intercom Field Type Notes
subject source.subject string Only on first message. Intercom's standard Conversations do not use subject lines — the subject is typically prepended to the first message body. Intercom's newer Tickets object does support formal titles via the title field.
status (New/Answered) state (open) enum
status (Postponed) state (snoozed) enum
status (Resolved/Deleted) state (closed) enum
department_id team_assignee_id reference Map department → team via lookup table
agent_id assignee.id reference Agent must exist as admin. Use GET /admins to build ID lookup.
tags tags array Attach after conversation creation
dateCreated created_at timestamp Convert to Unix epoch. Use Intercom's historical import endpoint to set this correctly.
messages [] conversation_parts [] array Each message = one part. Preserve chronological order.

Field-Level Mapping: Tickets → Intercom Tickets

When using Intercom's Ticket object instead of Conversations:

LiveAgent Field Intercom Ticket Field Type Notes
subject title string Direct mapping — Tickets support formal titles
status ticket_state enum Map to: submitted, in_progress, waiting_on_customer, resolved
department_id team_assignee_id reference Same as conversations
agent_id assignee.id reference Same as conversations
ticket type ticket_type_id reference Must pre-create ticket types in Intercom admin UI
custom ticket fields ticket_attributes varies Create as ticket-level CDAs

Handling Custom Fields

LiveAgent supports custom fields on both contacts and tickets. Intercom uses Custom Data Attributes (CDAs) on contacts, companies, and conversations.

Warning

Intercom CDAs have strict limitations: text values are capped at 255 characters, dropdown lists are limited to 35 options per attribute, and the soft limit is 250 active CDAs per workspace. Exceeding 250 requires contacting Intercom support — they can raise the limit, but query performance may degrade. If your LiveAgent instance has long text fields or picklists with many values, you will need to transform the data — use text CDAs instead of dropdowns, truncate with a suffix marker (e.g., [truncated]), or move overflow text into conversation notes. CDAs must be created in Intercom before importing data, or values will be silently discarded with no error returned.

Warning

Company attributes cannot be enforced as required-on-close in Intercom. That toggle applies only to conversation and ticket attributes, so move close-critical data onto those objects instead of company fields. (intercom.com)

Handling Relationships

LiveAgent links contacts to companies and tickets to contacts. In Intercom, this creates a strict dependency chain:

  1. Create companies first — you need the Intercom-generated company_id to link contacts.
  2. Create contacts second — attach to companies using the company ID.
  3. Create conversations last — you need the Intercom contact ID to associate conversations.

This order is non-negotiable. If you try to create conversations before contacts exist, the API will return a 404 or 422 error. If you try to attach a contact to a non-existent company, the attachment silently fails. (intercom.com)

Knowledge Base Migration

Knowledge base migration is often treated as an afterthought, but it has its own set of challenges.

Extraction

LiveAgent's KB articles are organized into Categories. Use the API to extract:

  • Article title, content (HTML), status (published/draft), category
  • Any embedded images (these are typically hosted on LiveAgent's CDN)

Transformation

LiveAgent KB Concept Intercom Help Center Concept Notes
Category Collection 1:1 mapping. Intercom collections can be nested one level deep.
Subcategory Section within Collection If LiveAgent has deeper nesting, flatten to two levels.
Article Article Map to a collection.
Article status (published) Article state (published) Direct mapping.
Internal articles Article state (draft) Keep as draft; do not publish internal docs to the Help Center.

Key Gotchas

  • Embedded images: Images hosted on LiveAgent's CDN must be downloaded and re-uploaded. Use Intercom's article API to upload images, or host them on your own CDN and reference via URL.
  • Internal links: Links between KB articles that reference LiveAgent URLs must be rewritten to point to the new Intercom Help Center URLs. Build a URL mapping table (old article URL → new article URL) and do a find-replace across all article bodies.
  • SEO redirects: If your LiveAgent KB was public-facing, set up 301 redirects from old article URLs to new Intercom Help Center URLs. This preserves search engine ranking and prevents broken links from external sites.
  • Intercom article body format: Intercom's article API accepts HTML, but only a subset of tags. Strip unsupported tags (e.g., <script>, <iframe>, custom data-* attributes) before import.
  • Article author: Intercom requires an author_id (an admin ID) for each article. Map LiveAgent article authors to Intercom admins, or default to a single admin for all migrated articles.

Code Example

def transform_kb_article(la_article, collection_id_map, admin_id):
    return {
        "title": la_article["title"],
        "body": rewrite_internal_links(
            strip_unsupported_html(la_article["content"])
        ),
        "author_id": admin_id,
        "state": "draft",  # Import as draft, review before publishing
        "parent_id": collection_id_map.get(la_article["category_id"]),
        "parent_type": "collection"
    }

Import all articles as drafts first. Review for formatting issues, broken images, and dead links before publishing.

Migration Architecture

Data Flow

LiveAgent API (v3)          Staging Layer          Intercom API (v2.11+)
────────────────           ──────────────         ────────────────────
GET /tickets        →      JSON/DB store    →     POST /companies
GET /tickets/{id}/messages  Transform &     →     POST /contacts
GET /customers              Validate        →     POST /conversations
GET /tags                   PII audit       →     POST /conversations/{id}/reply
GET /companies              Deduplication   →     POST /tags
GET /knowledgebase                          →     POST /articles

LiveAgent API Constraints

  • Rate limit: 180 requests per minute per API key for cloud-hosted accounts (support.liveagent.com)
  • Effective throughput: ~3 requests per second. For ticket extraction with message fetch, expect ~2 tickets per second (1 list call + 1 message call per ticket).
  • Pagination: GET /tickets returns max 1,000 rows per page; use _page and _perPage parameters
  • Result cap: v3 /tickets is capped at 10,000 results per filtered request — use date-windowed batching for larger datasets (support.liveagent.com)
  • API versions: v1 is deprecated; use v3 for all new integrations
  • Authentication: API key passed via apikey header or query parameter
  • No bulk export endpoint: Each ticket's messages require a separate API call (GET /tickets/{ticketId}/messages)
  • Timezone: API timestamps default to the account timezone unless you send a Timezone-Offset header. Always normalize to UTC in your staging layer.
  • Database dump: Available by contacting LiveAgent support — contains raw MySQL database tables, useful for very large datasets where API extraction would take multiple days

Extraction Time Estimates

Dataset Size Tickets Estimated Extraction Time (API) Notes
Small <5K ~1 hour Single-pass, no date windowing needed
Medium 5K–50K 3–8 hours Requires date-windowed batching
Large 50K–200K 1–3 days Consider database dump
Enterprise 200K+ 3–7 days Database dump strongly recommended

Estimates assume average of 5 messages per ticket and 180 req/min rate limit.

Intercom API Constraints

  • Rate limit: 10,000 API calls per minute per app, 25,000 per workspace, distributed in 10-second windows — watch X-RateLimit-Remaining and X-RateLimit-Reset response headers instead of hardcoding sleeps
  • No bulk create for contacts: Each contact must be created individually via POST /contacts
  • Conversation parts limit: 500 parts maximum per conversation
  • Attachment URLs expire after 30 minutes — you must download and re-upload, not just copy URLs
  • CDA limits: 250 active custom data attributes (soft limit), text values max 255 characters, dropdown max 35 options
  • Custom objects: 15 custom objects and 100K records on all plans, but custom objects can only be populated via Data Connectors — not directly via REST API for bulk import
  • API versioning: Set Intercom-Version: 2.11 header on all requests. Older versions may return different response schemas or reject newer parameters. The version header is required.
  • Common error codes: 409 Conflict = duplicate contact (email/external_id already exists), 422 Unprocessable Entity = validation error (missing required field or invalid CDA), 404 Not Found = referenced object does not exist (e.g., contact_id for conversation)
Info

Intercom's 10,000 req/min limit sounds generous, but creating a single conversation with 20 messages requires ~21 API calls (1 to create + 20 reply calls). A 50K-ticket migration with an average of 5 messages per ticket means ~300K API calls on the Intercom side alone — approximately 30 minutes of pure API time at maximum throughput, but realistically 1–2 hours with retries and backoff.

Step-by-Step Migration Process

Step 1: Extract Data from LiveAgent

Use the LiveAgent API v3 to extract all relevant objects. Never query all tickets since day one in one shot — use date-windowed batching to stay within the 10,000-result cap.

import requests
import time
import json
import logging
 
LA_BASE = "https://your-account.liveagent.com/api/v3"
API_KEY = "your-api-key"
HEADERS = {"apikey": API_KEY}
RATE_LIMIT_DELAY = 0.34  # ~180 req/min = 1 req per 0.33s
 
def extract_tickets(date_from, date_to):
    """Extract tickets within a date range. Use 7-day windows for large datasets."""
    tickets = []
    page = 1
    while True:
        resp = requests.get(
            f"{LA_BASE}/tickets",
            headers=HEADERS,
            params={
                "_page": page,
                "_perPage": 1000,
                "date_from": date_from,
                "date_to": date_to
            }
        )
        if resp.status_code == 429:
            logging.warning("Rate limited on LiveAgent API, sleeping 60s")
            time.sleep(60)
            continue
        resp.raise_for_status()
        data = resp.json()
        if not data:
            break
        tickets.extend(data)
        if len(data) >= 10000:
            logging.warning(f"Hit 10K cap for range {date_from}-{date_to}. Narrow the window.")
        page += 1
        time.sleep(RATE_LIMIT_DELAY)
    return tickets
 
def extract_messages(ticket_id):
    """Extract all messages for a single ticket."""
    resp = requests.get(
        f"{LA_BASE}/tickets/{ticket_id}/messages",
        headers=HEADERS
    )
    time.sleep(RATE_LIMIT_DELAY)
    if resp.status_code == 404:
        logging.warning(f"Ticket {ticket_id} messages not found — may be deleted")
        return []
    resp.raise_for_status()
    return resp.json()

Step 2: Transform Data

Map LiveAgent's structure to Intercom's expected format. Normalize statuses, flatten HTML where needed, resolve authors, collapse dead tags, and build source-to-target ID maps.

from dateutil.parser import parse as parse_datetime
 
def transform_contact(la_contact):
    name = f"{la_contact.get('firstname', '')} {la_contact.get('lastname', '')}".strip()
    return {
        "role": "user",
        "email": la_contact.get("email", "").lower().strip(),
        "external_id": str(la_contact["contactid"]),
        "name": name if name else "Unknown",
        "phone": la_contact.get("phone"),
        "signed_up_at": int(parse_datetime(la_contact["dateCreated"]).timestamp()),
        "custom_attributes": {
            "la_contact_id": str(la_contact["contactid"]),
        }
    }
 
def map_ticket_status(la_status):
    """Map LiveAgent status codes to Intercom conversation states."""
    status_map = {
        "N": "open",      # New
        "T": "open",      # Answered (by agent)
        "P": "snoozed",   # Postponed
        "R": "closed",    # Resolved
        "X": "closed",    # Deleted
        "A": "open",      # Answered (by customer)
        "C": "open",      # Chatting
        "B": "open",      # Calling
    }
    return status_map.get(la_status, "open")

Treat LiveAgent note IDs as strings — version 5.62 can return mixed integer and UUID note identifiers in the same ticket history. Cast all IDs to strings in your staging layer. (support.liveagent.com)

Step 3: Prepare Intercom

Before loading operational records, create all target structures:

  • Teams (mapped from departments) — create via Intercom admin UI
  • Custom Data Attributes for all custom fields you plan to migrate — create via API (POST /data_attributes) or admin UI
  • Tag names — create via API (POST /tags)
  • Ticket types (if using Intercom's ticket object) — create via admin UI
  • Help Center collections — create via API (POST /help_center/collections)

Agents must already exist as Intercom admins. You cannot create admins via the API. Use GET /admins to retrieve the admin list and build your LiveAgent agent ID → Intercom admin ID mapping table.

Step 4: Load into Intercom in Dependency Order

Create objects in this sequence: Companies → Contacts → Conversations/Tickets → Tags → Articles.

import requests
import time
import logging
 
IC_TOKEN = "your-intercom-token"
IC_BASE = "https://api.intercom.io"
IC_HEADERS = {
    "Authorization": f"Bearer {IC_TOKEN}",
    "Content-Type": "application/json",
    "Intercom-Version": "2.11"
}
 
def create_contact(contact_data, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.post(
            f"{IC_BASE}/contacts",
            headers=IC_HEADERS,
            json=contact_data
        )
        if resp.status_code == 200:
            return resp.json()
        elif resp.status_code == 409:
            # Duplicate — contact already exists, search and return existing
            logging.info(f"Contact {contact_data.get('email')} already exists, retrieving")
            return search_contact_by_email(contact_data["email"])
        elif resp.status_code == 429:
            wait = int(resp.headers.get("X-RateLimit-Reset", 10))
            logging.warning(f"Rate limited, waiting {wait}s (attempt {attempt+1})")
            time.sleep(wait)
        elif resp.status_code == 422:
            logging.error(f"Validation error for contact: {resp.json()}")
            return None  # Send to dead-letter queue
        else:
            logging.error(f"Unexpected error {resp.status_code}: {resp.text}")
            time.sleep(2 ** attempt)  # Exponential backoff
    return None
 
def create_conversation(contact_id, first_message_body):
    resp = requests.post(
        f"{IC_BASE}/conversations",
        headers=IC_HEADERS,
        json={
            "from": {"type": "user", "id": contact_id},
            "body": first_message_body
        }
    )
    return resp.json()
 
def add_reply(conversation_id, admin_id, body, message_type="comment"):
    resp = requests.post(
        f"{IC_BASE}/conversations/{conversation_id}/reply",
        headers=IC_HEADERS,
        json={
            "message_type": message_type,
            "type": "admin",
            "admin_id": admin_id,
            "body": body
        }
    )
    return resp.json()

Use Intercom's external_id field to enforce uniqueness. If a script fails mid-run, you should be able to restart without creating duplicates. The 409 Conflict response is your signal that a record already exists — handle it by retrieving the existing record and continuing.

Step 5: Rebuild Relationships

  • Attach contacts to companies using POST /contacts/{id}/companies
  • Assign conversations to the correct team/admin using PUT /conversations/{id}
  • Apply tags using POST /conversations/{id}/tags
  • Set conversation state (open/closed/snoozed) using PUT /conversations/{id} — note that closing a conversation may trigger Intercom workflows, so suppress automations during migration

Step 6: Validate and Run Delta Sync

Compare record counts, run field-level spot checks, execute agent UAT, then migrate any records created in LiveAgent during the migration window. See the Validation section below.

Full Script Structure

Here is the high-level structure for a production migration script:

# migration.py - LiveAgent to Intercom Migration
import logging
import json
from collections import defaultdict
 
logging.basicConfig(level=logging.INFO, filename="migration.log")
 
# Dead-letter queue for records that fail after max retries
dead_letter = defaultdict(list)
 
# Checkpoint store — use a file or database for persistence across restarts
checkpoint = {}
 
class LiveAgentExtractor:
    """Handles all reads from LiveAgent API v3"""
    def __init__(self, base_url, api_key): ...
    def get_contacts(self, page=1, per_page=200): ...
    def get_companies(self): ...
    def get_tickets(self, date_from, date_to): ...
    def get_ticket_messages(self, ticket_id): ...
    def get_tags(self): ...
    def get_kb_articles(self): ...
    def get_kb_categories(self): ...
 
class DataTransformer:
    """Maps LiveAgent schema to Intercom schema"""
    def __init__(self, agent_map, department_map, tag_map):
        self.agent_map = agent_map        # LA agent_id → IC admin_id
        self.department_map = department_map  # LA dept_id → IC team_id
        self.tag_map = tag_map            # LA tag_name → IC tag_id
    def transform_contact(self, la_contact): ...
    def transform_company(self, la_company): ...
    def transform_ticket(self, la_ticket, messages): ...
    def transform_kb_article(self, la_article): ...
 
class IntercomLoader:
    """Handles all writes to Intercom API with retry and checkpointing"""
    def __init__(self, access_token, version="2.11"): ...
    def create_contact(self, data): ...
    def create_company(self, data): ...
    def create_conversation(self, contact_id, body): ...
    def add_conversation_reply(self, conv_id, admin_id, body): ...
    def create_ticket(self, contact_id, ticket_type_id, title, body): ...
    def apply_tag(self, object_type, object_id, tag_id): ...
    def create_article(self, data): ...
 
def save_id_mapping(object_type, source_id, target_id):
    """Persist source→target ID mapping for rollback and validation."""
    ...
 
def get_id_mapping(object_type, source_id):
    """Retrieve Intercom ID from LiveAgent ID."""
    ...
 
def main():
    extractor = LiveAgentExtractor(LA_BASE_URL, LA_API_KEY)
    transformer = DataTransformer(AGENT_MAP, DEPT_MAP, TAG_MAP)
    loader = IntercomLoader(IC_ACCESS_TOKEN)
 
    # Phase 1: Companies
    for company in extractor.get_companies():
        if checkpoint.get(f"company_{company['id']}"):
            continue  # Already migrated
        ic_company = transformer.transform_company(company)
        result = loader.create_company(ic_company)
        if result:
            save_id_mapping("company", company["id"], result["id"])
            checkpoint[f"company_{company['id']}"] = True
 
    # Phase 2: Contacts
    for contact in extractor.get_contacts():
        if checkpoint.get(f"contact_{contact['contactid']}"):
            continue
        ic_contact = transformer.transform_contact(contact)
        result = loader.create_contact(ic_contact)
        if result:
            save_id_mapping("contact", contact["contactid"], result["id"])
            checkpoint[f"contact_{contact['contactid']}"] = True
        else:
            dead_letter["contacts"].append(contact)
 
    # Phase 3: Tickets → Conversations
    for ticket in extractor.get_tickets(DATE_FROM, DATE_TO):
        if checkpoint.get(f"ticket_{ticket['id']}"):
            continue
        messages = extractor.get_ticket_messages(ticket["id"])
        ic_conv = transformer.transform_ticket(ticket, messages)
        contact_ic_id = get_id_mapping("contact", ticket["owner_contactid"])
        if not contact_ic_id:
            # Assign to fallback "Archived User" contact
            contact_ic_id = ARCHIVED_USER_IC_ID
        conv = loader.create_conversation(contact_ic_id, ic_conv["first_message"])
        for msg in ic_conv["replies"]:
            loader.add_conversation_reply(conv["id"], msg["admin_id"], msg["body"])
        save_id_mapping("ticket", ticket["id"], conv["id"])
        checkpoint[f"ticket_{ticket['id']}"] = True
 
    # Phase 4: Knowledge Base
    for article in extractor.get_kb_articles():
        ic_article = transformer.transform_kb_article(article)
        loader.create_article(ic_article)
 
    # Output dead-letter records for manual review
    with open("dead_letter.json", "w") as f:
        json.dump(dead_letter, f, indent=2)
 
    logging.info(f"Migration complete. {len(dead_letter['contacts'])} contacts in dead-letter queue.")
 
if __name__ == "__main__":
    main()

This is a structural outline — production code needs retry logic with exponential backoff on 429 responses, checkpointing persisted to disk or database so you can resume after failures, comprehensive error logging with hashed PII, and a dead-letter queue for records that fail repeatedly.

Edge Cases and Challenges

Duplicate Contacts

LiveAgent may have multiple contact records with the same email created from different channels. Intercom enforces email uniqueness and resolves contacts in a strict identifier order: Intercom ID → user_id → email. Inconsistent user_id strategy is the fastest way to create duplicates. Deduplicate before migration — merge contacts in LiveAgent or in your staging layer. When Intercom encounters a duplicate email, it returns 409 Conflict — your script should handle this by retrieving the existing contact and continuing. (intercom.com)

Attachments

Attachments cannot be passed via URL directly if they are behind LiveAgent's authentication wall. You must:

  1. Download each attachment from LiveAgent to a temporary store (local disk or S3 bucket)
  2. Upload to a publicly accessible URL or use Intercom's attachment upload mechanism
  3. Reference the new URL in the conversation part body

Intercom's attachment URLs expire after 30 minutes, so you cannot simply copy URLs between systems. Budget approximately 1 second per attachment for the download/upload cycle. For a migration with 50K attachments, this adds ~14 hours of processing time.

Conversation Parts Limit

Intercom caps conversations at 500 parts. If a LiveAgent ticket has more than 500 messages (rare, but possible in long-running support threads or automated notification threads), you need to either:

  • Truncate: Keep the most recent 500 messages, archive the rest as a note on the conversation
  • Split: Create multiple linked conversations with a note on each referencing the other parts
  • Archive: Store the full thread externally and link via custom attribute

Missing or Deleted Users

If a LiveAgent ticket belongs to a deleted user, the Intercom API will return a 404 or 422 when you try to create the conversation. Intercept these errors and assign the conversation to a fallback "Archived User" contact — create this contact in Intercom before migration starts.

Orphan Companies

Companies with no attached contact may not appear in Intercom's UI list views or search results. They exist in the database and are accessible via API, but raw company count comparisons using the UI can mislead QA. Verify with API queries (GET /companies) against your mapping table, not just UI counts.

Call Recordings and Voicemail

LiveAgent supports VoIP and stores call recordings as ticket attachments or linked files. Intercom has no native call recording object. Archive these externally (S3, Google Cloud Storage, Azure Blob Storage) and link via a custom attribute or conversation note containing the external URL.

Formatting Loss

Initial Intercom conversation creation does not accept HTML bodies in all cases — the POST /conversations endpoint accepts a body field that supports a subset of HTML. Rich email rendering (CSS styles, complex tables, embedded fonts) is best-effort, not guaranteed fidelity. Strip incompatible HTML tags (e.g., <style>, <script>, <table> with complex nesting) to prevent API validation errors. Test with 5–10 representative HTML-heavy tickets before the full run. (developers.intercom.com)

LiveAgent Chat Transcripts

Live chat conversations in LiveAgent are stored as ticket messages and map directly to Intercom conversation parts. Real-time metadata (typing indicators, chat duration, visitor page URL, pre-chat form responses) will be lost. If pre-chat form data is important, extract it as a custom attribute or prepend it to the first conversation message.

Notification Leakage

Test in a non-live workspace or suppress outbound behavior during historical replay. Replaying email-like history carelessly can trigger customer-facing notifications (email, push, in-app) for every imported conversation. In Intercom, you can suppress notifications by using the admin reply endpoint with specific parameters, but verify this in your test workspace first. This is the single most common "catastrophic" migration error — sending thousands of notifications to customers about years-old support tickets.

Mixed Character Encodings

LiveAgent tickets from email channels may contain mixed character encodings (UTF-8, ISO-8859-1, Windows-1252). Normalize all text to UTF-8 in your transformation layer. Characters that cannot be converted should be replaced with the Unicode replacement character (U+FFFD) rather than silently dropped.

Limitations and Constraints

Be honest with stakeholders about what gets lost or changed:

Limitation Impact Workaround
No equivalent to LiveAgent's call center Call data cannot be migrated as-is Archive calls to cloud storage, link via notes
Intercom CDAs limited to 255 chars Long text fields get truncated Use notes for overflow text; add [truncated] marker
Intercom dropdown CDAs max 35 options Large picklists will not fit Use text CDAs instead
No bulk contact import API Import speed depends on rate limits (~10K contacts/hour) Batch with backoff
Custom objects require Data Connectors Cannot bulk-load custom objects via REST API Use Intercom's Data Connector framework
Ticket SLA history not transferable Historical SLA metrics are lost Export SLA reports from LiveAgent before decommissioning
Conversation parts max 500 Very long threads may be truncated Split into multiple conversations
Timestamp control Historical conversations appear by import date unless using historical import endpoints Use Intercom's specific import endpoints with their schema constraints
Forum, suggestion, and channel artifacts Several LiveAgent-specific objects have no clean 1:1 Intercom object Archive externally or redesign
LiveAgent gamification data Agent points, badges, levels have no Intercom equivalent Export for records, cannot migrate
Predefined answers (canned responses) LiveAgent macros do not transfer Recreate manually as Intercom Saved Replies

Validation and Testing

Never execute a production cutover without a sandbox test. Create a free Intercom dev workspace for testing.

Record Count Validation

After migration, compare counts for every object type:

LiveAgent Contacts:      12,456
Intercom Contacts:       12,456  ✓

LiveAgent Companies:        234
Intercom Companies:         234  ✓
  (Verify via API — orphan companies may not appear in UI)

LiveAgent Tickets:       45,678
Intercom Conversations:  45,678  ✓
  (Check dead-letter queue for any failed records)

LiveAgent Tags:              89
Intercom Tags:               89  ✓

LiveAgent KB Articles:      156
Intercom Articles:          156  ✓

Field-Level Validation

Sample 2–5% of records (minimum 50 records per object type) and verify:

  • Contact names, emails, and phone numbers match
  • Custom attribute values transferred correctly (check for truncation at 255 chars)
  • Conversation messages are in correct chronological order
  • Attachments are accessible (not broken links or expired URLs)
  • Tags are correctly applied
  • Agent attribution preserved (correct admin assigned)
  • Conversation states match expected status mapping

Intercom Search and Scroll APIs for Validation

For large-scale validation, use Intercom's Search API (POST /contacts/search) and Scroll API (GET /contacts/scroll) to efficiently query imported data:

  • Search API: Use filters to find records by external_id or custom attributes. Limited to 50 results per page. Use for targeted spot checks.
  • Scroll API: Returns all contacts in paginated batches. Use for full count validation. Note: scroll sessions expire after 1 minute of inactivity.
def validate_contact_count():
    """Compare migrated contact count against source."""
    scroll_param = None
    ic_count = 0
    while True:
        url = f"{IC_BASE}/contacts/scroll"
        if scroll_param:
            url += f"?scroll_param={scroll_param}"
        resp = requests.get(url, headers=IC_HEADERS)
        data = resp.json()
        contacts = data.get("data", [])
        if not contacts:
            break
        ic_count += len(contacts)
        scroll_param = data.get("scroll_param")
    return ic_count

UAT Process

  1. Have 2–3 agents search for known customers in Intercom and verify their history is complete
  2. Open 10 random conversations and confirm message threading is correct and chronological
  3. Verify that workflows/automations in Intercom reference the correct tags and custom attributes
  4. Test that new incoming conversations are routed correctly alongside migrated data
  5. Verify that Fin AI (if enabled) can access and reference migrated Help Center articles
  6. Check that conversation assignment rules work with migrated team mappings

Rollback Planning

Migrations to Intercom are not easily reversible. Intercom does not have a "delete all imported data" button. Your rollback plan should include:

  • Keep LiveAgent active (read-only) for at least 30 days post-migration
  • Maintain a mapping file (LiveAgent ID → Intercom ID) for every record — this is mandatory for rollback
  • If rollback is needed, delete records via Intercom's API using the mapping file — tag all migrated records with a migration_batch_id tag to make bulk identification possible
  • Estimated rollback time: deleting via API is rate-limited to the same 10K req/min. For a 50K-record migration, expect ~5 minutes of pure API time for deletion, plus time for relationship cleanup.
  • Critical: Intercom does not cascade-delete. Deleting a contact does not delete their conversations. You must delete conversations separately.

Post-Migration Tasks

Once the data is in Intercom, the operational work begins.

Rebuild Automations

LiveAgent's rule-based automation does not transfer to Intercom. Recreate:

  • Assignment rules → Intercom Workflows or Assignment Rules
  • SLA rules → Intercom SLA policies (set up before go-live; historical SLA data does not migrate)
  • Auto-responses → Intercom Workflows with auto-reply actions
  • Tag-based routing → Intercom tag-triggered workflows
  • Escalation rules → Intercom Workflows with time-based conditions

Agent Onboarding

Intercom's interface is significantly different from LiveAgent. Budget 2–5 days for:

  • Training agents on the Inbox, conversation handling, and the difference between conversations and tickets
  • Recreating macros/saved replies (these do not migrate — export from LiveAgent and manually recreate)
  • Configuring notification preferences per agent
  • If using Fin AI, pointing it at your newly migrated Help Center articles and verifying it can surface correct answers
  • Setting up keyboard shortcuts and inbox views to match agents' LiveAgent workflows

Monitor for Data Gaps

For the first two weeks after go-live:

  • Watch for contacts appearing as "unknown" (failed contact import — check dead-letter queue)
  • Monitor for conversations with missing messages (truncation or API failures during part creation)
  • Check that tags are applied correctly to migrated records
  • Verify that Intercom's search index has fully processed all imported data (indexing can lag 15–30 minutes for large imports)
  • Track first-reply time and resolution time metrics — establish a baseline in the first week and compare against your LiveAgent benchmarks

Operational Baseline

Expect the following during the first 30 days post-migration:

  • Agent productivity dip of 15–30% in week 1 as agents learn the new interface
  • Search performance: Intercom's search indexes may take up to 24 hours to fully process large imports
  • Fin AI accuracy: If using Fin, it needs time to index Help Center articles. Test resolution accuracy on migrated articles before enabling for customers.
  • Workflow tuning: Expect to adjust routing, assignment, and SLA workflows 3–5 times in the first two weeks as real traffic reveals edge cases

Best Practices

  1. Back up everything before you start. Export a full database dump from LiveAgent and store it independently. This is your safety net. Store it in a separate cloud region from your production systems.
  2. Run a test migration first. Use a dev Intercom workspace (free to create) and migrate a subset of 500–1,000 tickets. Validate before committing to the full run. Test with your most complex tickets (HTML-heavy, multi-attachment, long threads), not just simple ones.
  3. Freeze the source helpdesk. Institute a total freeze on LiveAgent configuration changes (custom fields, departments, tags) one week prior to migration.
  4. Create CDAs in Intercom before importing data. If a custom attribute does not exist when you send data, Intercom will silently discard the value — no error returned.
  5. Preserve source IDs. Store the LiveAgent ticket ID and contact ID as custom attributes in Intercom. This is your only lifeline for cross-referencing data post-migration and for rollback.
  6. Use date-range batching for extraction. LiveAgent's API performs better when you query by date range rather than pulling the entire dataset at once. The 10,000-record cap per filtered request makes this mandatory for datasets exceeding that threshold. Use 7-day windows as a starting point; narrow to 1-day windows if any range returns close to 10K results.
  7. Build idempotent import scripts. If a script fails mid-run, you should be able to restart without creating duplicates. Use Intercom's external_id field to enforce uniqueness. Handle 409 Conflict responses by retrieving the existing record.
  8. Use delta migrations. Run the bulk of your historical data a week before go-live. On go-live weekend, only migrate the delta — tickets created or updated since the bulk run. Use LiveAgent's date_from filter to identify delta records.
  9. Log everything. Every API call, every error, every skipped record. Hash PII in logs (do not log raw email addresses). You will need this for validation and debugging.
  10. Suppress notifications during import. Verify in your test workspace that historical conversation creation does not trigger customer-facing emails or push notifications. This is the highest-impact mistake you can make.

Sample Data Mapping Reference

# LiveAgent Field Intercom Field Transformation
1 contactid external_id Cast to string
2 email email Lowercase, trim whitespace
3 firstname + lastname name Concatenate with space; default to "Unknown" if both empty
4 phone phone Direct copy
5 company.name company.name Direct copy
6 company.id company.company_id Cast to string; use as stable identifier
7 ticket.subject conversation.source.subject Direct copy (first message only); prepend to body for Conversations
8 ticket.status conversation.state Map: N/T/A/C/B→open, P→snoozed, R/X→closed
9 ticket.dateCreated conversation.created_at Convert to Unix timestamp (seconds)
10 ticket.departmentId conversation.team_assignee_id Map via lookup table
11 ticket.agentId conversation.assignee.id Map LiveAgent agent → Intercom admin via lookup table
12 ticket.tags [] conversation.tags [] Match by name, create if missing
13 message.body conversation_part.body HTML preserved where supported; strip unsupported tags
14 message.type (internal) conversation_part.message_type Map to "note"
15 message.type (public) conversation_part.message_type Map to "comment"
16 contact.custom_field_* contact.custom_attributes.* Create CDA first; truncate text >255 chars
17 ticket.custom_field_* conversation.custom_attributes.* Create CDA first; map list values to Intercom list item IDs
18 message.attachment conversation_part attachment URL Download, re-upload, reference new URL

Making the Right Call

Migrating from LiveAgent to Intercom is a one-way architectural shift. You are moving from a ticket-centric system to a conversation-first platform, and the data model differences mean there is no push-button migration.

The critical decisions are:

  • What data to bring — not everything in LiveAgent has a home in Intercom. Call recordings, gamification data, forum posts, and SLA history will not migrate.
  • Conversations vs. tickets — this affects your entire target schema and determines which Intercom API endpoints you use
  • How to handle custom fields — Intercom's CDA limits (250 active, 255-char text, 35-option dropdown) will force prioritization
  • Whether to build or buy — the engineering effort is real (2–6 weeks depending on complexity), but so is the cost of getting it wrong (notification leakage, data loss, duplicate contacts)

By respecting API limits (180 req/min LiveAgent, 10K req/min Intercom), mapping data models accurately, testing in a sandbox workspace, and thoroughly handling edge cases, you ensure your support team can transition to a modern conversational workflow without losing a single piece of customer history.

If you are planning this migration and want to skip the trial-and-error, check out our guides on Intercom migrations and helpdesk migration planning. For a deep look at post-migration QA, see our migration QA checklist.

Frequently Asked Questions

Can I migrate LiveAgent tickets to Intercom with CSV?
Not cleanly. Intercom's CSV importer handles people records only — not company data, conversation threads, or attachments. Full ticket history requires the LiveAgent API for extraction and the Intercom API for import. CSV is only viable for small contact-only migrations where you can start fresh with conversations.
What are the API rate limits for LiveAgent and Intercom?
LiveAgent's cloud API is limited to 180 requests per minute per API key, with a 10,000-record cap per filtered ticket query. Intercom allows 10,000 API calls per minute per app and 25,000 per workspace, distributed in 10-second windows. LiveAgent's lower limit is typically the bottleneck during extraction.
Should LiveAgent tickets become Intercom conversations or tickets?
Customer-facing threads (email, chat) usually map to Intercom conversations. Back-office or tracked work items map better to Intercom tickets, which require pre-created ticket types. This decision must be made before the first load because it affects the entire target schema.
How long does a LiveAgent to Intercom migration take?
Timeline depends on data volume. A small migration (under 5K tickets) can be done in 1–2 days. Mid-size migrations (5K–100K tickets) typically take 3–7 days including testing. Enterprise migrations with 100K+ tickets may take 1–2 weeks due to LiveAgent's API rate limits on extraction.
What LiveAgent data is lost when migrating to Intercom?
Call recordings, voicemail files, SLA history metrics, chat session metadata (typing indicators, visitor page URLs), automation rules, agent gamification data, and forum/suggestion artifacts do not have equivalents in Intercom. These should be archived externally before migration.

More from our Blog

Post-Migration QA: 20 Tests to Run After Your Help Desk Data Migration
Help Desk

Post-Migration QA: 20 Tests to Run After Your Help Desk Data Migration

Ensure your help desk migration is a success with this comprehensive 20-point post-migration QA checklist. This expert guide details the 20 essential tests needed to validate your data integrity, system functionality, user-friendliness, and performance . Learn exactly how to check everything from ticket data, attachments, and knowledge base articles to critical workflows, automations, and integrations before you go live. This process is your final line of defense against lost tickets, broken workflows, and unhappy customers.

Raaj Raaj · · 8 min read