Skip to content

Freshservice to LiveChat Migration: The Technical Guide

A technical guide to migrating data from Freshservice to LiveChat, covering API constraints, data model mapping, ITSM-to-chat gaps, and step-by-step methods.

Roopi Roopi · · 29 min read
Freshservice to LiveChat 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

Freshservice to LiveChat Migration: The Technical Guide

Migrating from Freshservice to LiveChat is a data-model conversion, not a data copy. Freshservice is a full IT service management (ITSM) platform built around structured service workflows — tickets, problems, changes, assets, service catalogs, and knowledge base articles. LiveChat is a real-time chat platform built for customer engagement, organized around customers, chats, threads, events, groups, and tags.

There is no one-to-one mapping between these systems. If you attempt a direct export-import, you will lose threaded context, break historical reporting, and strand ITSM-specific data that has no destination in LiveChat.

This guide covers the technical constraints, viable migration approaches, data model gaps, step-by-step execution, and the edge cases that break most migrations.

Why Teams Move from Freshservice to LiveChat

Freshservice is Freshworks' ITSM platform built for internal IT operations — incident management, change management, asset tracking, and service catalogs.

LiveChat is a customer-facing live chat platform built by Text (formerly LiveChat Software). It is designed for real-time customer engagement, sales conversations, and front-line support.

Common reasons teams make this shift:

  • Channel pivot: The team is moving from ticket-based IT support to real-time, chat-first customer engagement — typically during a business model shift toward e-commerce or SaaS.
  • Cost reduction: Freshservice's ITSM feature set (asset management, CMDB, change management) is overkill for teams that only need chat and basic ticketing.
  • Platform consolidation: The team is standardizing on the Text platform ecosystem (LiveChat + HelpDesk + ChatBot + Knowledge Base) and wants all customer interactions in one vendor stack.
  • Simplicity: LiveChat's learning curve is significantly lower than Freshservice. Teams without dedicated IT admins often prefer the simpler interface.
Warning

LiveChat's native ticketing system has been sunsetted. If you need ticket management alongside chat, you will need HelpDesk (a separate Text platform product) integrated with LiveChat. If your end state still requires long-lived tickets, async case work, and knowledge workflows, design your migration target as LiveChat + HelpDesk — not LiveChat alone. See the HelpDesk integration section below for detailed mapping guidance.

Core Data Model Differences

This section determines whether your migration succeeds or fails. If you don't understand the architectural gap, your mapping will break.

Concept Freshservice LiveChat
Primary unit of work Ticket (incident, service request) Chat (containing threads and events)
Customer identity Requester Customer
Support agent Agent Agent
Team grouping Agent Groups / Departments Groups
Conversation history Ticket conversations (replies, notes) Threads → Events (messages)
Categorization Categories, subcategories, item categories Tags
IT assets Assets (CMDB) No equivalent
Change management Changes No equivalent
Problem management Problems No equivalent
Release management Releases No equivalent
Knowledge base Knowledge Base articles Requires separate Knowledge Base product
Custom objects Custom Objects Properties (limited key-value pairs)
Service catalog Service Items No equivalent
SLA management SLA Policies No native SLA engine

The LiveChat data model is intentionally lean. Each chat is divided into threads, and every thread contains events (messages). A chat represents a whole conversation history with a customer, while threads represent separate conversation sessions. In LiveChat archives, one chat can appear multiple times because the archive view is thread-based. This is a fundamentally different structure from Freshservice's ticket-centric model, and it is why a direct 1:1 object copy produces bad results.

The primary architectural challenge is schema flattening. Freshservice relies on deep hierarchical relationships (Department → Requester → Ticket → Asset → Change). LiveChat uses a flat schema (Group → Customer → Chat/Thread/Event). You must flatten the Freshservice hierarchy without losing historical context.

Common Migration Failure Modes

Before choosing an approach, understand what actually breaks. These are ranked by frequency based on the patterns we see most often:

  1. Author attribution loss (most common): Freshservice conversation from_email values don't resolve to existing LiveChat agent or customer IDs. LiveChat attributes these messages to the API service account, destroying the conversation history's authorship. Fix: Build a complete email-to-LiveChat-ID lookup table before loading any events. Validate every author ID resolves before pushing.

  2. Conversation ordering corruption: Freshservice conversations include replies, notes, and forwards with independent timestamps. When flattened into LiveChat thread events, interleaved private notes (which have no LiveChat equivalent) create gaps that shift the apparent conversation flow. Fix: Separate public and private conversations before transformation. Load public conversations as thread events; route private notes to HelpDesk or archive them.

  3. Pagination data loss: Engineers hit the Freshservice 500-page wall without realizing it, silently losing all tickets beyond record 50,000. No error is returned — the API simply returns empty results. Fix: Implement updated_since date-range windowing from the start, not as a workaround after data loss.

  4. Attachment link rot: Freshservice attachment URLs are temporary authenticated S3 links. Engineers store the URLs instead of downloading the files. By the time they load into LiveChat, the links are dead. Fix: Download every attachment during the extraction phase and store locally or in your own S3 bucket.

  5. Duplicate customer records: Freshservice allows multiple requester records with the same email (created via different channels — portal, email, phone). Loading all of them into LiveChat creates duplicate customers since LiveChat uses email as the primary identifier. Fix: Deduplicate requesters by email before loading. Merge metadata from duplicate records into a single customer profile.

  6. HTML rendering in chat events: Using description (HTML) instead of description_text (plain text) from Freshservice pushes raw HTML tags into LiveChat message bodies, making them unreadable. Fix: Always use description_text and body_text fields. If you must preserve formatting, strip HTML to markdown or plain text before loading.

  7. Rate limit cascade failures: Freshservice rate limits are account-wide. A parallel integration (webhook, scheduled report, other API consumer) consumes part of the budget, causing the migration script to hit 429 errors at lower-than-expected throughput. Fix: Pause or disable other Freshservice API consumers during migration windows. Monitor X-RateLimit-Remaining headers proactively.

  8. Missing group assignments: Freshservice department/group IDs don't map to LiveChat group IDs. Chats created without a valid group assignment end up unrouted. Fix: Create all LiveChat groups before migration. Build a Freshservice group ID → LiveChat group ID lookup table and validate it against every record.

Migration Approaches

There is no first-party Freshservice-to-LiveChat migration wizard. You have six viable paths.

1. CSV-Based Export/Import

How it works: Export ticket-level data from Freshservice list views or the Analytics module as CSV. Transform the CSV to match LiveChat's expected format. Use LiveChat's APIs to load the data programmatically.

When to use: Small datasets (<1,000 tickets), one-time archival migrations where transcript fidelity is not a hard requirement.

Pros:

  • Low technical barrier
  • No API rate limit concerns on the extraction side
  • Fast and cheap

Cons:

  • Standard Freshservice CSV exports do not include conversations or internal notes — only ticket-level metadata. Freshservice list exports cap at 10,000 tickets per export.
  • No way to bulk-import chats into LiveChat via CSV natively
  • Relationships between requesters, tickets, and assets are lost
  • Manual data transformation is error-prone at scale

Complexity: Low (extraction) / Medium (transformation and import)

2. Freshservice Full Data Export

How it works: Use Freshservice's Admin → Data Export feature to generate a complete account backup. This produces a downloadable archive containing tickets, requesters, conversations, and other objects in structured format.

When to use: As a safety archive before any migration, or as a primary extraction method for large datasets where API-based extraction would take too long.

Pros:

  • Captures the full dataset including conversations and attachments
  • No API rate limit consumption
  • Useful as a backup regardless of migration approach

Cons:

  • Export format may require significant transformation to match LiveChat's expected structure
  • Export generation can take hours for large accounts
  • Does not support incremental exports — it is a full snapshot
  • Still requires API-based loading into LiveChat

Complexity: Low (extraction) / Medium (transformation and import)

3. API-Based Migration

How it works: Use the Freshservice REST API v2 to extract tickets, conversations, requesters, and other objects programmatically. Transform the data in-flight. Use the LiveChat Configuration API (v3.5+) and Agent Chat API to create the corresponding records.

When to use: Medium to large datasets where conversation history must be preserved. Teams with developer bandwidth.

Pros:

  • Full control over extraction, transformation, and loading
  • Conversations and notes are preserved
  • Handles custom field mapping
  • Scriptable, repeatable, testable

Cons:

  • Freshservice rate limits vary by plan (see table below)
  • LiveChat enforces approximately 1,000 requests per 10-minute window per license
  • Deep pagination is capped at page 500 in Freshservice — large datasets require date-range windowing with updated_since filters
  • LiveChat has no bulk import API; records must be created individually
  • Multi-agent history recreation is inherently lossy — LiveChat's initial chat user list is limited to one customer and up to four additional agents

Complexity: High

4. Third-Party Migration Tools

How it works: Platforms like Help Desk Migration offer pre-built connectors for Freshservice and LiveChat. You select source and target, map fields through a UI, run a test migration, then execute the full migration.

When to use: Non-technical teams, straightforward migrations without heavy custom field logic, mid-size datasets.

Pros:

  • No code required
  • Pre-built field mapping for common objects
  • Test migration capability
  • Preserves basic relationships (tickets, requesters, agents, groups, tags)

Cons:

  • Limited control over transformation logic
  • May not handle Freshservice custom objects or ITSM-specific data (assets, changes, problems)
  • Pricing scales with record count (typically $1–$5 per 100 records depending on volume tier — verify current pricing with the vendor)
  • Black-box — hard to debug failures

Complexity: Low

5. Custom ETL Pipeline

How it works: Build a dedicated Extract-Transform-Load pipeline using Python, Node.js, or a data orchestration tool (Airflow, Prefect). Extract from the Freshservice API, stage in an intermediate data store (PostgreSQL, SQLite, or flat files), transform with custom business logic, and load into LiveChat via API.

When to use: Enterprise-scale migrations, complex transformation requirements, ongoing sync needs, teams with dedicated engineering resources.

Pros:

  • Maximum flexibility
  • Handles edge cases (multi-workspace Freshservice setups, custom object flattening)
  • Intermediate staging enables validation before loading
  • Supports incremental runs and rollback

Cons:

  • Highest engineering investment
  • Must build rate-limit handling, retry logic, and error logging from scratch
  • Maintenance burden if used for ongoing sync

Complexity: High

6. Middleware Platforms (Zapier, Make) and Webhooks

How it works: Use integration platforms to connect Freshservice triggers to LiveChat actions. Configure workflows that fire when specific Freshservice events occur and create corresponding records in LiveChat. Alternatively, configure Freshservice webhooks to push ticket events to a custom endpoint that transforms and loads data into LiveChat in near real-time.

When to use: Ongoing sync of new records after cutover — not historical migration. The webhook approach is particularly useful for teams that need real-time forwarding of new Freshservice tickets to LiveChat during a transition period.

Pros:

  • No-code setup (Zapier/Make); low-code for webhooks
  • Good for ongoing forward sync of new records
  • Visual workflow builder (Zapier/Make)
  • Freshservice webhooks support ticket creation, update, and note events

Cons:

  • Not designed for bulk historical migration
  • Per-task pricing becomes expensive at scale (Zapier: $0.01–$0.03 per task depending on plan)
  • Limited error handling and retry logic
  • Cannot reconstruct complex ticket conversation threads
  • Webhook approach requires a custom receiving endpoint with transformation logic

Complexity: Low (Zapier/Make) / Medium (webhooks)

Migration Approach Comparison

Approach Best For Historical Data Conversations Custom Fields Scale Complexity
CSV Export/Import Quick archival Partial Limited Small Low
Full Data Export Safety archive + large extraction Large Low-Medium
API-Based Full migration Medium-Large High
Third-Party Tools Non-technical teams Partial Limited Medium Low
Custom ETL Enterprise Large High
Middleware/Webhooks Ongoing sync only Limited Small Low-Medium

Which Approach Fits Your Team?

  • Small business, <1K tickets: Third-party migration tool or CSV export with manual cleanup.
  • Mid-market, 1K–50K tickets, need conversation history: API-based migration with a Python or Node.js script.
  • Enterprise, 50K+ tickets, multi-workspace Freshservice: Custom ETL pipeline or a managed migration service.
  • Ongoing sync (not migration): Zapier, Make, or Freshservice webhooks for new records, with an API-based backfill for historical data.
  • Low engineering bandwidth: Third-party tool or managed migration service. Do not build a bespoke pipeline unless LiveChat is part of a larger platform move.

Pre-Migration Planning

Do not write code until you have audited your Freshservice environment.

Data Audit Checklist

Inventory what you actually have in Freshservice before you map anything:

  • Tickets: Total count, breakdown by status (open, pending, resolved, closed)
  • Conversations: Reply count per ticket, internal notes vs. public replies
  • Requesters: Total count, active vs. inactive, duplicates (by email)
  • Agents: Active agents, groups, roles
  • Assets: Total assets, asset types, asset-to-ticket associations
  • Problems / Changes / Releases: Count and whether they are still relevant
  • Knowledge Base: Article count, folder structure, embedded media
  • Custom Fields: Field types, picklist values, dependencies
  • Custom Objects: Schemas, relationships to tickets
  • Attachments: Total size, file types, count of files >10MB (LiveChat's per-file limit)
  • Tags / Categories: Full taxonomy
  • Active API consumers: Other integrations, webhooks, or scheduled jobs consuming Freshservice API quota

Identify What Not to Migrate

Not everything in Freshservice belongs in LiveChat. Be deliberate about what you leave behind:

  • Closed tickets older than 12–24 months: Archive to cold storage (AWS S3, data warehouse) instead of importing into LiveChat.
  • Assets and CMDB data: LiveChat has no asset management. Export to a spreadsheet or dedicated CMDB tool.
  • Change and problem records: These are ITSM constructs with no chat equivalent. Archive separately.
  • SLA configurations and workflow automations: Must be rebuilt manually in LiveChat (or HelpDesk).
  • Audit trails and time tracking logs: Not importable into LiveChat.

Migration Strategy

Strategy When to Use Risk
Big bang Small dataset, simple mapping, short cutover window acceptable Higher risk if something fails mid-migration
Phased Large dataset, multiple Freshservice workspaces, team needs gradual onboarding Lower risk, longer timeline
Incremental Ongoing sync required, can't afford downtime Requires continuous pipeline maintenance

For most Freshservice-to-LiveChat migrations, a phased approach works best:

  1. Initial full sync: Move recent active tickets and customer data.
  2. UAT & testing: Validate the data in LiveChat.
  3. Backfill: Import remaining historical data.
  4. Delta sync (cutover): Move any records created during the testing phase just before go-live. A delta sync captures only the records created or updated since your last extraction, using updated_since filters on the Freshservice API.

Data Model and Object Mapping

Every Freshservice object needs a destination — or an explicit decision to archive or discard. Do not let stakeholders assume that every source object has a native home in LiveChat.

Object-Level Mapping

Freshservice Object LiveChat Equivalent Notes
Ticket Chat + Thread(s) Each ticket becomes a chat. Conversations become thread events.
Requester Customer Map email, name, phone. Custom requester fields → customer properties.
Agent Agent Recreate agents manually or via Configuration API.
Agent Group / Department Group 1:1 mapping.
Ticket Tags Tags Direct mapping.
Ticket Priority Tag (e.g., priority:high) LiveChat has no native priority field on chats.
Ticket Status Tag (e.g., status:resolved) + thread state LiveChat threads are active or inactive. Map statuses to tags.
Ticket Category Tag Flatten category hierarchy into prefixed tags (e.g., cat:hardware, subcat:laptop).
Conversations (replies) Thread events (messages) Preserve sender, timestamp, and body.
Internal Notes System messages or HelpDesk private notes LiveChat standard chat events have no private flag. Use HelpDesk if you need internal notes.
Attachments File events in threads Must be re-uploaded; Freshservice attachment URLs are temporary.
Assets ❌ No equivalent Archive to CSV or external CMDB.
Problems ❌ No equivalent Archive separately.
Changes ❌ No equivalent Archive separately.
Releases ❌ No equivalent Archive separately.
Knowledge Base ❌ (Separate product) Requires Text platform's Knowledge Base product.
Custom Objects Properties (key-value) Flatten custom object fields into customer or chat properties. Complex relationships will be lost.

Handling CRM-Adjacent Objects

If you integrated Freshservice with a CRM (like Freshsales) or used custom objects to mimic CRM behavior:

  • Accounts / Companies: Freshservice's closest native analog is Departments/Companies. LiveChat has no first-class company record. Map company data to customer properties, session_fields, or link to an external CRM ID.
  • Leads / Opportunities: These are not native objects in LiveChat. Keep the system of record in a CRM and surface the external ID or stage inside LiveChat as tags (e.g., status:qualified_lead).
  • Activities (tasks, notes, time entries): No direct LiveChat activity model. Convert to transcript blocks, agent-only summaries, or archive separately.

Handling Relationships

Freshservice supports multi-level relationships: a requester belongs to a department, a ticket is linked to an asset, assets link to changes. LiveChat has a flat relationship model: customers have chats, chats have threads, threads have events.

Strategy: Preserve the most important association (requester → ticket → conversation) and flatten or archive the rest. Store asset IDs and change references as chat properties or tags so the data is queryable, even if it is not structurally linked.

HelpDesk Integration Architecture

The blog recommends LiveChat + HelpDesk multiple times. Here is the concrete architecture for that joint migration target.

HelpDesk (by Text) is a separate ticketing product that integrates natively with LiveChat. When both are connected, LiveChat handles real-time chat while HelpDesk manages asynchronous tickets, email-based cases, and internal workflows.

When You Need HelpDesk

You need HelpDesk alongside LiveChat if any of these apply:

  • You require internal/private notes on customer interactions
  • You need SLA timers and automated escalation
  • You have email-based support workflows that must continue
  • You need ticket statuses beyond active/inactive (e.g., pending, on-hold, escalated)
  • You require assignment-based routing and ticket queues

Joint Migration Mapping

When migrating to LiveChat + HelpDesk, the mapping changes:

Freshservice Object Destination Notes
Ticket (chat-originated) LiveChat Chat + HelpDesk Ticket Chat handles the real-time record; HelpDesk ticket handles async follow-up
Ticket (email-originated) HelpDesk Ticket only No LiveChat chat needed
Internal Notes HelpDesk private notes HelpDesk supports internal notes natively
SLA Policies HelpDesk SLA rules HelpDesk offers basic SLA: first response time, resolution time
Ticket Status HelpDesk ticket status HelpDesk supports: new, open, pending, on-hold, solved, closed
Canned Responses HelpDesk canned responses + LiveChat canned responses Split by channel

HelpDesk API Details

HelpDesk uses its own API (separate from LiveChat's). Key endpoints for migration loading:

  • Create ticket: POST /v1/tickets — accepts subject, requester email, status, priority, tags, and custom fields
  • Add message to ticket: POST /v1/tickets/{id}/messages — supports both public and private messages
  • Authentication: API key-based (different from LiveChat's OAuth)
  • Rate limits: 200 requests per minute per API key

The joint architecture means you run two parallel load processes: one into LiveChat (for chat-based records and customer profiles) and one into HelpDesk (for ticket records, internal notes, and SLA-managed cases). Both share the same customer identity via email matching.

Migration Architecture

┌─────────────────┐     ┌──────────────────┐     ┌───────────────┐
│   Freshservice   │────▶│   Staging Layer   │────▶│   LiveChat     │
│   REST API v2    │     │   (PostgreSQL /   │     │   Config API   │
│                  │     │    JSON files)     │     │   v3.5+        │
│  - /tickets      │     │                    │     │   Agent Chat   │
│  - /conversations│     │  Transform:        │     │   API          │
│  - /requesters   │     │  - Map objects     │     │                │
│  - /agents       │     │  - Flatten ITSM    │     │  - Customers   │
│  - /assets       │     │  - Clean HTML      │     │  - Chats       │
│                  │     │  - Resolve IDs     │     │  - Threads     │
│                  │     │  - Dedup emails    │     │  - Events      │
│  Also:           │     │  - Download        │     │                │
│  Admin → Data    │     │    attachments     │     │  + HelpDesk    │
│  Export (backup) │     │                    │     │    API v1       │
└─────────────────┘     └──────────────────┘     └───────────────┘

Freshservice API Extraction

API Version: Freshservice REST API v2. This is the current stable version. The v1 API was deprecated and removed; all endpoints referenced in this guide are v2-specific. Freshservice's v2 API introduced pagination changes (the 500-page cap) and restructured conversation endpoints compared to v1.

Authentication: Basic Auth — use your Freshservice API key as the username with any string (e.g., X) as the password.

Rate limits by plan:

Freshservice Plan Rate Limit Effective Extraction Speed (with conversations)
Starter 100 req/min ~80 tickets/min (1 ticket + 1 conversation call each)
Growth 200 req/min ~160 tickets/min
Pro 400 req/min ~320 tickets/min
Enterprise 500 req/min ~400 tickets/min

These limits are account-wide, regardless of agent count or IP addresses. Even failed requests count toward the limit.

Extraction time estimates (assuming each ticket requires 2 API calls — one for the ticket, one for full conversations):

Dataset Size Starter Plan Growth Plan Pro Plan Enterprise Plan
1,000 tickets ~13 min ~7 min ~4 min ~3 min
10,000 tickets ~125 min (~2 hrs) ~63 min ~32 min ~25 min
50,000 tickets ~625 min (~10 hrs) ~313 min (~5 hrs) ~157 min (~2.5 hrs) ~125 min (~2 hrs)
100,000 tickets ~1,250 min (~21 hrs) ~625 min (~10 hrs) ~313 min (~5 hrs) ~250 min (~4 hrs)

These are theoretical maximums assuming zero retries and sustained throughput. Real-world extraction typically runs 20–30% slower due to rate limit headroom, retries, and network latency.

Pagination: Max 100 records per page using page and per_page query parameters. Deep pagination is capped at page 500 — for datasets larger than 50,000 tickets, use updated_since date-range filters to window your queries. The API returns an empty result set (not an error) when you exceed page 500, which makes this a silent data loss risk.

Conversations endpoint: The include=conversations query parameter on the tickets endpoint returns only up to 10 conversations per ticket and consumes extra API credits. For production migrations, call /api/v2/tickets/{id}/conversations directly to get the full thread.

LiveChat API Loading

API Version: LiveChat API v3.5 is the current stable version used throughout this guide. LiveChat has versioned its API through 3.1, 3.2, 3.3, 3.4, and 3.5 with breaking changes between major versions. Check the LiveChat API changelog before starting to confirm v3.5 is still current and review any deprecation notices.

Authentication: OAuth 2.1 with Personal Access Tokens (PAT) or full authorization code flow.

Required OAuth scopes for migration:

  • customers.write — create and update customer records
  • chats.write — create chats and threads
  • agents.read — resolve agent IDs for author attribution
  • properties.write — set custom properties on chats and customers
  • tags.write — apply tags to chats

If loading into HelpDesk as well, you'll need HelpDesk API key access (separate from LiveChat OAuth).

Rate limits: Approximately 1,000 requests per 10-minute window per license, shared across all tokens and integrations on that license. HTTP 429 responses include Retry-After headers.

Load time estimates:

Dataset Size Estimated Load Time (LiveChat only)
1,000 chats ~10 min
10,000 chats ~100 min (~1.7 hrs)
50,000 chats ~500 min (~8.3 hrs)
100,000 chats ~1,000 min (~16.7 hrs)

These assume ~1 customer creation + ~1 chat creation per record at sustained throughput. Records with many conversation events require additional API calls per event, extending load time proportionally.

Key APIs:

  • Configuration API: Create and manage agents, groups, properties, tags, and customers.
  • Agent Chat API: Create chats, send events (messages), manage threads.

Important constraints:

  • LiveChat has no bulk import API — records must be created individually.
  • The initial chat user list is limited to one customer and up to four additional agents, making multi-agent history recreation inherently lossy. If a Freshservice ticket involved more than four agents, only the first four can be associated with the LiveChat chat natively. Attribute remaining agents' messages via tags (e.g., agent:jane.doe) on individual events.
  • LiveChat pagination tokens (page_id) expire after one month, so long-running verification jobs should checkpoint aggressively.
Warning

LiveChat's API expects specific JSON structures for thread events. If you push a Freshservice reply without the correct author ID mapped to an existing LiveChat agent or customer, LiveChat will attribute the message to the API service account — ruining historical context. Build and validate your author ID lookup table before loading any events.

Step-by-Step Migration Process

Step 1: Extract Data from Freshservice

Pull tickets, conversations, requesters, and agents. Before starting API extraction, generate a full data export via Admin → Data Export as a safety archive.

import requests
import time
import json
 
FS_DOMAIN = "yourcompany.freshservice.com"
API_KEY = "your_api_key"
 
def get_tickets(page=1, per_page=100, updated_since=None):
    url = f"https://{FS_DOMAIN}/api/v2/tickets"
    params = {"page": page, "per_page": per_page}
    if updated_since:
        params["updated_since"] = updated_since
    
    response = requests.get(url, auth=(API_KEY, "X"), params=params)
    
    # Handle rate limits proactively
    remaining = int(response.headers.get("X-RateLimit-Remaining", 1))
    if remaining < 5:
        time.sleep(60)
    
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", 60))
        time.sleep(retry_after)
        return get_tickets(page, per_page, updated_since)
    
    response.raise_for_status()
    return response.json().get("tickets", [])
 
def get_conversations(ticket_id):
    """Fetch full conversation thread — do not rely on include=conversations."""
    url = f"https://{FS_DOMAIN}/api/v2/tickets/{ticket_id}/conversations"
    response = requests.get(url, auth=(API_KEY, "X"))
    
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", 60))
        time.sleep(retry_after)
        return get_conversations(ticket_id)
    
    return response.json().get("conversations", [])
 
def extract_all_tickets(updated_since="2022-01-01T00:00:00Z"):
    """Extract all tickets using date-range windowing to avoid the 500-page cap."""
    all_tickets = []
    page = 1
    while True:
        tickets = get_tickets(page=page, updated_since=updated_since)
        if not tickets:
            break
        all_tickets.extend(tickets)
        if page >= 500:
            # Hit pagination cap — narrow the date window
            last_updated = tickets[-1]["updated_at"]
            return all_tickets + extract_all_tickets(updated_since=last_updated)
        page += 1
    return all_tickets

Step 2: Transform Data

Map Freshservice tickets to LiveChat chat structures. Clean HTML, convert statuses to tags, and flatten custom fields to properties.

from html import unescape
import re
 
def strip_html(html_text):
    """Convert HTML to plain text. Use description_text when available."""
    if not html_text:
        return ""
    text = re.sub(r'<br\s*/?>', '\n', html_text)
    text = re.sub(r'<[^>]+>', '', text)
    return unescape(text).strip()
 
def transform_ticket_to_chat(ticket, conversations, agent_email_to_id, customer_email_to_id):
    """Transform a Freshservice ticket into a LiveChat chat structure.
    
    agent_email_to_id: dict mapping Freshservice agent emails to LiveChat agent IDs
    customer_email_to_id: dict mapping requester emails to LiveChat customer IDs
    """
    
    STATUS_MAP = {2: "open", 3: "pending", 4: "resolved", 5: "closed"}
    PRIORITY_MAP = {1: "low", 2: "medium", 3: "high", 4: "urgent"}
    SOURCE_MAP = {1: "email", 2: "portal", 3: "phone", 7: "chat", 9: "feedback_widget"}
    
    requester_email = ticket.get("requester", {}).get("email", "unknown@archived.local")
    
    customer = {
        "name": ticket.get("requester", {}).get("name", "Unknown"),
        "email": requester_email,
        "livechat_id": customer_email_to_id.get(requester_email),
    }
    
    # Build thread events from conversations
    events = []
    # First event: ticket subject + description
    events.append({
        "type": "message",
        "text": f"[{ticket['subject']}]\n\n{ticket.get('description_text', strip_html(ticket.get('description', '')))}",
        "author_id": customer["livechat_id"],
        "created_at": ticket["created_at"],
    })
    
    public_conversations = [c for c in conversations if not c.get("private", False)]
    private_conversations = [c for c in conversations if c.get("private", False)]
    
    for conv in public_conversations:
        from_email = conv.get("from_email", "unknown")
        # Resolve author to LiveChat ID
        author_id = agent_email_to_id.get(from_email) or customer_email_to_id.get(from_email)
        if not author_id:
            # Log warning — this will cause attribution to API service account
            print(f"WARNING: Cannot resolve author {from_email} for ticket {ticket['id']}")
        
        events.append({
            "type": "message",
            "text": conv.get("body_text", strip_html(conv.get("body", ""))),
            "author_id": author_id,
            "created_at": conv.get("created_at"),
        })
    
    # Build tags from Freshservice metadata
    tags = list(ticket.get("tags", []))
    tags.append(f"status:{STATUS_MAP.get(ticket.get('status'), 'unknown')}")
    tags.append(f"priority:{PRIORITY_MAP.get(ticket.get('priority'), 'unknown')}")
    source = SOURCE_MAP.get(ticket.get("source"), "unknown")
    tags.append(f"source_channel:{source}")
    tags.append("source:freshservice")
    
    # Flatten custom fields to properties
    properties = {
        "freshservice_ticket_id": str(ticket["id"]),
        "original_created_at": ticket["created_at"],
    }
    for key, value in ticket.get("custom_fields", {}).items():
        if value is not None:
            properties[f"cf_{key}"] = str(value)
    
    return {
        "customer": customer,
        "events": events,
        "private_notes": private_conversations,  # Route to HelpDesk if available
        "tags": tags,
        "properties": properties,
    }

Always use description_text instead of description when extracting ticket bodies. Freshservice stores description as HTML and description_text as plain text. Pushing raw HTML into LiveChat text events causes rendering issues.

Step 3: Load into LiveChat

Create customers first, then create chats and thread events. Capture the returned LiveChat Customer ID and use it when creating the associated Chat.

import requests
import time
 
LC_TOKEN = "your_livechat_personal_access_token"
LC_BASE = "https://api.livechatinc.com/v3.5"
 
def create_customer(customer_data):
    url = f"{LC_BASE}/configuration/action/create_customer"
    headers = {
        "Authorization": f"Bearer {LC_TOKEN}",
        "Content-Type": "application/json",
    }
    payload = {
        "name": customer_data["name"],
        "email": customer_data["email"],
    }
    response = requests.post(url, headers=headers, json=payload)
    
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", 10))
        time.sleep(retry_after)
        return create_customer(customer_data)
    
    if response.status_code == 409:
        # Customer already exists — retrieve existing record
        return get_customer_by_email(customer_data["email"])
    
    response.raise_for_status()
    return response.json()
 
def create_chat_with_events(chat_data, group_id, agent_ids):
    """Create a chat and populate it with thread events."""
    url = f"{LC_BASE}/agent/action/start_chat"
    headers = {
        "Authorization": f"Bearer {LC_TOKEN}",
        "Content-Type": "application/json",
    }
    
    # LiveChat limits initial users to 1 customer + up to 4 agents
    limited_agents = agent_ids[:4]
    if len(agent_ids) > 4:
        print(f"WARNING: Chat has {len(agent_ids)} agents, truncating to 4")
    
    payload = {
        "chat": {
            "users": [
                {"id": chat_data["customer"]["livechat_id"], "type": "customer"}
            ] + [{"id": aid, "type": "agent"} for aid in limited_agents],
            "thread": {
                "events": [
                    {
                        "type": "message",
                        "text": event["text"],
                        "author_id": event["author_id"],
                        "created_at": event["created_at"],
                    }
                    for event in chat_data["events"]
                    if event["author_id"]  # Skip events with unresolved authors
                ],
                "tags": chat_data["tags"],
            },
        },
        "group_id": group_id,
    }
    
    response = requests.post(url, headers=headers, json=payload)
    
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", 10))
        time.sleep(retry_after)
        return create_chat_with_events(chat_data, group_id, agent_ids)
    
    response.raise_for_status()
    return response.json()

Ensure every ticket is assigned to the correct Group and Agent based on your mapping sheet.

Step 4: Validate

Do not assume a 200 OK response means the data is correctly formatted in the target system.

  • Record counts: Compare total tickets extracted from Freshservice against total chats created in LiveChat. Tolerance: 0% for customers, 0% for chats, <1% for individual events (some events may be skipped due to unresolvable authors).
  • Conversation integrity: Sample 5–10% of records (minimum 50 records). Verify conversation content, timestamps, and customer associations. Compare the first and last message text of each sampled ticket against the corresponding LiveChat chat.
  • Author attribution: For each sampled record, verify that messages are attributed to the correct agent or customer — not the API service account.
  • Tag accuracy: Confirm Freshservice statuses and priorities appear correctly as LiveChat tags.
  • Orphaned records: Check for customers without chats and chats without events.
  • Attachment spot-check: Open 10–20 attachments in LiveChat and confirm they render correctly. Verify no expired S3 URLs remain in message bodies.
  • Property validation: Confirm custom properties (e.g., freshservice_ticket_id) are queryable.
  • Chronological order: Verify that thread events within a chat appear in the correct timestamp sequence.

Edge Cases and Challenges

Attachments: Freshservice returns attachments as temporary Amazon S3 URLs that require authentication. You must download each file during extraction, then upload it to LiveChat as a file event. LiveChat enforces a 10MB per file limit — the API returns an entity_too_large error for anything larger. Temporary upload URLs expire after 24 hours unless used. Budget for storage and transfer time. For files exceeding 10MB, either compress them, host them externally and link in the message body, or archive them separately with a reference tag.

Inline images: Images embedded directly in Freshservice ticket bodies often rely on authenticated Freshservice sessions to render. You must parse the HTML, download each image, re-upload it to LiveChat, and rewrite the <img> src tag in the ticket body (or convert to a file event attachment).

Duplicate requesters: Freshservice may have multiple requester records with the same email (created via different channels). Deduplicate before loading into LiveChat, which uses email as the primary customer identifier. Merge metadata (phone numbers, custom fields) from duplicate records into a single canonical customer profile.

Suspended or deleted users: Freshservice retains tickets for deleted users. LiveChat requires a valid email for customer creation. Create a dummy "Archived User" (e.g., archived@yourdomain.local) in LiveChat to attribute these orphaned tickets, and tag them with requester:deleted for identification.

Multi-workspace Freshservice: If your Freshservice instance has multiple IT workspaces, each workspace may have its own ticket numbering, custom fields, and object schemas. You need to iterate over workspaces and merge or segregate data based on your LiveChat group structure. Ticket ID collisions are possible across workspaces — prefix the freshservice_ticket_id property with the workspace identifier.

Internal notes: Freshservice distinguishes between public replies and private notes. LiveChat's standard chat events have no private flag. If you need private notes preserved, you will need HelpDesk integration, which does support internal notes on tickets. See the HelpDesk integration section for details.

Deep pagination wall: Freshservice blocks pagination beyond page 500. For datasets larger than 50,000 tickets, use updated_since date-range windowing to retrieve records in chunks. The API returns empty results (not an error) past page 500 — always validate your total extracted count against Freshservice's ticket count before proceeding to transformation.

Timestamp drift: Original message chronology may drift when you flatten tickets into chat threads. Thread events are ordered by creation, and the target system may not perfectly replicate the original sequence if events are created out of order via the API. Load events in strict chronological order within each thread to minimize drift.

Custom field type mismatches: Freshservice supports typed custom fields (date, dropdown, checkbox, decimal). LiveChat properties are string-only key-value pairs. All custom field values must be cast to strings, which means you lose type validation. Document the original field types in your mapping table for downstream consumers.

Limitations and Constraints

What LiveChat Cannot Store (That Freshservice Can)

  • Assets / CMDB: No concept of hardware or software inventory.
  • Change management records: No structured change request workflow.
  • Problem management: No root cause analysis records.
  • SLA policies: No built-in SLA engine (HelpDesk has basic SLA features: first response time and resolution time targets).
  • Service catalog / Service items: No request catalog.
  • Approval workflows: No multi-level approval chains.
  • Time tracking: No native time logging on chats.
  • Custom status workflows: Freshservice allows custom statuses. LiveChat threads are either active or inactive. Map custom statuses to tags.
  • Private/internal notes: No private flag on chat events. Requires HelpDesk for internal notes.

API Constraints Summary

Platform API Version Rate Limit Pagination Limit Bulk API Auth Method
Freshservice REST API v2 100–500 req/min (plan-dependent, account-wide) 100/page, 500 pages max No Basic Auth (API key)
LiveChat v3.5 ~1,000 req/10 min (per license) Cursor-based, tokens expire after 1 month No OAuth 2.1 (PAT or auth code)
HelpDesk v1 200 req/min (per API key) Offset-based No API key

Both Freshservice and LiveChat lack bulk import APIs, meaning each record must be created individually.

Validation and Testing

Pre-Go-Live Checklist

  1. Record count comparison: Total tickets in Freshservice vs. total chats in LiveChat. Zero tolerance for discrepancy.
  2. Conversation integrity: Sample 50–100 tickets and verify all public conversation messages appear as thread events with correct timestamps and correct author attribution.
  3. Customer deduplication: Confirm no duplicate customer records in LiveChat (query by email).
  4. Tag accuracy: Verify status and priority tags mapped correctly across a random sample.
  5. Attachment spot-check: Open 10–20 attachments in LiveChat and confirm they are accessible and render correctly.
  6. Agent assignment: Verify agents are correctly associated with migrated chats and messages are attributed to the right agent.
  7. Property validation: Confirm custom properties (e.g., freshservice_ticket_id) are queryable and correct.
  8. Group routing: Verify migrated chats are assigned to the correct LiveChat groups.
  9. Private notes (if using HelpDesk): Confirm internal notes appear as private notes in HelpDesk tickets, not as public messages.

Rollback Plan

LiveChat does not have a "delete all migrated records" button. Before running the production migration:

  • Test in a separate LiveChat trial account first. Never migrate directly to production.
  • Maintain a mapping log (Freshservice ticket ID → LiveChat chat ID → LiveChat customer ID) so you can identify and clean up migrated records if needed.
  • Keep Freshservice in read-only mode during migration — not decommissioned. You need a fallback.
  • Tag all migrated records with source:freshservice so they can be identified and bulk-deleted via API if needed.

Post-Migration Tasks

Rebuild automations: Freshservice workflow automations, SLA policies, and canned responses do not transfer. Recreate auto-routing rules in LiveChat using groups and routing settings. If using HelpDesk, configure automated workflows, ticket assignment rules, and SLA timers there.

Update integrations: Point any external integrations (Shopify, Jira, Salesforce) to LiveChat's webhook endpoints. Update monitoring and reporting systems.

Agent training: LiveChat's interface is fundamentally different from Freshservice. Budget 1–2 days for agent onboarding, especially if agents are accustomed to Freshservice's ticket queue view. Ensure agents understand the difference between LiveChat's real-time chat interface and the asynchronous ticketing interface in HelpDesk.

Archive ITSM data: Export assets, changes, problems, and releases from Freshservice to CSV or a data warehouse. This data has no home in LiveChat but may be needed for compliance or audit purposes. Maintain the archive for your organization's required retention period.

Monitor for data gaps: Run weekly spot-checks for the first month. Look for missing conversations, incorrectly tagged chats, and customer records that did not link properly. Compare total record counts weekly.

Best Practices

  • Back up everything before migration. Export all Freshservice data via Admin → Data Export and keep CSV exports as a safety archive. This is your insurance policy.
  • Run a test migration first. Migrate 100–500 records into a LiveChat trial account. Validate the output before committing to the full dataset.
  • Build lookup tables before loading. Create email-to-LiveChat-ID mappings for all agents and customers before pushing any events. Unresolvable author IDs are the most common source of data corruption.
  • Use date-range windowing for extraction. Avoid hitting Freshservice's 500-page pagination limit by filtering with updated_since parameters from the start.
  • Tag migrated records. Add a source:freshservice tag to every migrated chat so you can distinguish imported data from native LiveChat data.
  • Implement exponential backoff. Capture 429 errors and use the Retry-After header to pause execution automatically. Start with the header value, then double on consecutive failures.
  • Log every API call. Maintain a migration log with request/response pairs, including HTTP status codes and response bodies. When something fails, you need this to diagnose and resume.
  • Pause other API consumers during migration. Freshservice rate limits are account-wide. Disable webhooks, scheduled reports, and other integrations that consume API quota during extraction windows.
  • Lock Freshservice during final sync. Make Freshservice read-only during the final delta sync to prevent data drift.
  • Don't migrate what you don't need. Closed tickets older than 2 years, spam tickets, and test records should be archived, not migrated.

For more guidance on planning what to bring and what to leave behind, see our Help Desk Data Migration Playbook.

Sample Data Mapping Table

# Freshservice Field Type LiveChat Target Transformation
1 ticket.id Integer Chat property fs_ticket_id Cast to string
2 ticket.subject String First thread event text (prefix) Prepend to description
3 ticket.description_text Text First thread event body Direct (use description_text, not description)
4 ticket.status Integer Tag Map: 2→open, 3→pending, 4→resolved, 5→closed
5 ticket.priority Integer Tag Map: 1→low, 2→medium, 3→high, 4→urgent
6 ticket.source Integer Tag Map: 1→email, 2→portal, 3→phone, 7→chat, 9→feedback_widget
7 ticket.created_at ISO 8601 Thread created_at Direct (timezone-aware)
8 ticket.tags Array Tags Direct
9 requester.email String Customer email Direct (deduplication key)
10 requester.name String Customer name Direct
11 requester.phone String Customer phone Direct
12 conversation.body_text Text Thread event body Strip HTML if using body field
13 conversation.from_email String Event author_id Resolve to LiveChat agent or customer ID via lookup table
14 conversation.created_at ISO 8601 Event timestamp Direct
15 conversation.private Boolean HelpDesk private note Route to HelpDesk API; do not load as LiveChat event
16 ticket.custom_fields.* Various Chat/customer properties Flatten; cast all values to string; prefix with cf_
17 department String Group Map via lookup table (Freshservice dept ID → LiveChat group ID)
18 asset_id Integer Customer property Append as text reference; no structural link in LiveChat

Making the Right Call

Migrating from Freshservice to LiveChat is not a standard helpdesk-to-helpdesk move. It is a platform category shift — from ITSM to real-time chat — and you need to treat it accordingly. A significant portion of your Freshservice data (assets, changes, problems, releases) has no destination in LiveChat and must be archived separately.

The migration is viable if you are clear about what you are optimizing for: faster customer engagement over structured IT service management. If you still need long-lived case management, internal notes, and SLA-managed workflows, design for LiveChat plus HelpDesk — not LiveChat alone — and map both targets explicitly.

Plan for the data model gaps, build a staging layer for transformation, respect both platforms' API limits, and validate at every step. The most common failures — author attribution loss, pagination data loss, and attachment link rot — are all preventable with the right extraction and validation checks.

For related migration guidance, see our LiveChat to Help Scout Migration guide and our post-migration QA checklist.

Frequently Asked Questions

Can I migrate Freshservice tickets to LiveChat?
Yes, but with significant caveats. Freshservice tickets map to LiveChat chats containing threads and events. Ticket metadata like priority and status must be converted to tags, since LiveChat has no native priority or multi-status fields. Conversations become thread events. ITSM-specific data like assets, changes, and problems has no LiveChat equivalent and must be archived separately. LiveChat's native ticketing has been sunsetted, so if you need async ticket management alongside chat, plan for HelpDesk integration.
What are the Freshservice API rate limits for data migration?
Freshservice rate limits vary by plan: Starter gets 100 requests/minute, Growth gets 200, Pro gets 400, and Enterprise gets 500. These are account-wide limits — even failed requests count. Freshservice also offers a partner-oriented migration process that can raise limits to 700 requests/minute for approved windows. Deep pagination is capped at page 500, so large datasets require date-range windowing with the updated_since parameter.
Does LiveChat have a bulk import API for migration?
No. LiveChat does not offer a bulk import API. Records must be created individually via the Configuration API (for customers, agents, groups) and Agent Chat API (for chats and events). The rate limit is approximately 1,000 requests per 10-minute window per license, which means large migrations require hours of sustained API calls.
What Freshservice data cannot be migrated to LiveChat?
LiveChat has no equivalent for Freshservice assets/CMDB, change management records, problem management records, releases, service catalog items, SLA policies, approval workflows, or time tracking. This data must be archived to CSV, a data warehouse, or a separate tool. Knowledge base articles require the separate Text platform Knowledge Base product.
How long does a Freshservice to LiveChat migration take?
It depends on volume. A small migration (under 1,000 tickets) can be done in a day. For 10,000–50,000 tickets with conversations, expect 3–5 days including extraction, transformation, loading, and validation. Enterprise migrations (50K+ tickets) may take 1–2 weeks. API rate limits on both platforms are the primary bottleneck.

More from our Blog

Help Desk Data Migration Playbook: What Data to Move and What to Leave Behind
Help Desk

Help Desk Data Migration Playbook: What Data to Move and What to Leave Behind

This definitive playbook answers the single most critical question: "What data do we actually need to move?". This strategic guide helps you declutter and decide what's precious and what's junk. We provide a clear breakdown of the non-negotiable Tier 1 data, like tickets , knowledge bases , and user profiles, versus the Tier 2 data that provides rich context, like automations and organizations. Use this as your strategic checklist to avoid common mistakes and ensure a flawless, functional new help desk.

Raaj Raaj · · 7 min read
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