Skip to content

Freshservice to Gladly Migration: A Technical Guide

Technical guide to migrating from Freshservice to Gladly. Covers data model differences, API rate limits, entity mapping, import constraints, and what you cannot migrate.

Raaj Raaj · · 22 min read
Freshservice to Gladly Migration: A Technical Guide
TALK TO AN ENGINEER

Planning a migration?

Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.

Schedule a free call
  • 1,500+ migrations completed
  • Zero downtime guaranteed
  • Transparent, fixed pricing
  • Project success responsibility
  • Post-migration support included

What Is a Freshservice to Gladly Migration?

A Freshservice to Gladly migration extracts requesters, tickets, conversations (replies and notes), agents, groups, and knowledge base articles from Freshservice's ITSM model and loads them into Gladly as Customers, Conversation Items, Agents, Teams, Topics, and Answers.

This is not a standard helpdesk-to-helpdesk migration. It is a cross-category data model translation. Freshservice stores tickets — incidents, service requests, problems, and changes — linked to assets and a configuration database, all built around the ITIL framework. Gladly organizes work around people, where each customer has one persistent Conversation that runs for the life of the relationship, with every interaction across every channel landing on that single timeline.

The gap between these two systems is larger than a typical Zendesk-to-Gladly or Freshdesk-to-Gladly move. You are not just remapping ticket fields — you are discarding an entire ITSM layer that has no target in Gladly. Freshservice's ITSM capabilities (asset management, CMDB, change management, approval workflows) are purpose-built features with no Gladly equivalents. The migration scope is fundamentally a question of what customer-facing subset of your Freshservice data belongs in a CX platform — and that subset is almost always smaller than teams expect.

Info

TL;DR — Freshservice to Gladly Migration

Migrating from Freshservice to Gladly is a cross-category migration — you are moving data from an ITIL-aligned IT service management (ITSM) platform to a person-centric, ticketless customer service platform. The data models share almost nothing. Freshservice stores tickets, assets, problems, changes, a CMDB, and a service catalog. Gladly stores Customers with lifelong Conversation Timelines, Conversation Items (individual interactions on the timeline), Topics, and Answers — no ticket numbers, no asset tracking. Most Freshservice ITSM entities (assets, problems, changes, releases, SLA policies, workflow automations) have no equivalent in Gladly and cannot be migrated. Gladly's documented historical import is text-only: it does not support attachments, images, recordings, metrics, or routing assignments, and imported data is not searchable or reportable — it is reference-only on the customer profile. Freshservice API rate limits range from 100 to 500 requests per minute depending on plan. Gladly's default rate limit is 10 API calls per second. Budget 2–4 weeks for a mid-size instance.

Targets Freshservice API v2 and Gladly REST API.

Warning

Before you commit: If your Freshservice instance contains a mix of internal IT tickets and external customer tickets, only the external customer-facing subset should move to Gladly. Internal ITSM data (incident management for employees, asset tracking, change requests) does not belong in Gladly and will create noise on agent timelines if imported.

Freshservice vs. Gladly: What Each Platform Actually Does

The structural difference between these two platforms determines what migration is possible. This comparison uses platform-specific terminology.

Dimension Freshservice Gladly
Data model Ticket-centric (each interaction = new Ticket ID) Person-centric (all interactions = one lifelong timeline per customer)
Primary object Ticket (Incident, Service Request, Problem, Change) Customer profile with Conversation Timeline
Thread grouping Per-ticket thread Conversation (configurable time window, default 24 hours)
Agent routing Routes to ticket queue Routes to customer, not ticket
Channels Email, portal, phone, chat Email, voice, SMS, chat, social — all unified on one timeline
ITIL support Full ITIL framework (incident, problem, change, release) None
Asset management Full CMDB None
Automation Workflow Automator, Supervisor, Dispatch'r, Observer Rules engine
Knowledge base Categories > Folders > Articles Answers (channel-aware: email, messaging, public, internal variants)
Reporting Analytics with SLA metrics, ticket volume, CSAT Gladly Insight (conversation-level, not ticket-level)
API REST API v2, Basic Auth REST API, OAuth2

Gladly specifically does not have ticket numbers, ticket-level SLA timers, asset associations, approval workflows, or ITIL change management. These are not feature gaps — they are intentional design choices for a B2C customer service platform. Forcing ITSM data into Gladly does not recreate ITSM functionality; it creates cluttered timelines and orphaned data.

Data Model Gap: ITSM Tickets vs. Person-Centric Timelines

Freshservice: Ticket-Centric

Freshservice uses discrete objects for every issue. If Jane Doe emails support three times about three different issues, Freshservice creates three separate Ticket IDs. Each ticket has its own status, priority, SLA timer, and thread of replies and private notes. Requesters, agents, and groups relate to tickets as foreign-key associations.

Gladly: Person-Centric

Gladly has no concept of a "ticket number." When Jane Doe contacts support, Gladly routes the customer, not the ticket. All interactions — phone calls, SMS, emails, and chats — are appended to Jane Doe's single lifelong Conversation Timeline as Conversation Items. A Conversation in Gladly is a time-bounded grouping of Conversation Items (24-hour window by default, configurable per brand). A Conversation Item is a single discrete interaction: one email, one call, one chat message. The distinction between these two terms matters throughout the migration.

This means that three separate Freshservice tickets from the same requester must all be folded into a single Gladly Customer profile, with each ticket becoming one or more Conversation Items on that customer's timeline.

Entity Mapping

Freshservice Entity Gladly Equivalent Migration Path
Ticket (Incident/Service Request) Conversation Items on Customer Timeline Map each ticket → Conversation Items under the requester's Customer profile
Requester Customer Map 1:1 by email address
Agent Agent Create or map manually
Group Team / Inbox Manual setup in Gladly
Conversation reply (public) Conversation Item Flatten into timeline items
Internal note Conversation Item (agent-visible only) Import decision required — see Step 4
Custom Fields Custom Attributes Map selectively; Gladly supports fewer field types
Knowledge Base Article Answer Recreate in channel-aware format; one article often becomes multiple Answer variants
Tags Topics Map selectively — intent tags only
Asset ❌ No equivalent Not migratable — archive separately
Problem ❌ No equivalent Not migratable — export to data warehouse
Change ❌ No equivalent Not migratable — export to data warehouse
Release ❌ No equivalent Not migratable
Service Catalog ❌ No equivalent Redesign as Answers or Sidekick flows
CMDB / Configuration Items ❌ No equivalent Not migratable
SLA Policies ❌ No equivalent Rebuild as Gladly Rules from scratch
Workflow Automator Rules ❌ No equivalent Rebuild as Gladly Rules from scratch
Approval Workflows ❌ No equivalent Not migratable
Custom Dashboards / Analytics ❌ No equivalent Rebuild in Gladly Insight

What Cannot Be Migrated

These Freshservice features have no target in Gladly:

  • Assets and CMDB — Gladly has no asset management. Archive this data separately (S3, data warehouse) or retain Freshservice access for IT teams.
  • Problems, Changes, and Releases — ITIL constructs with no Gladly equivalent. Export to Snowflake, Redshift, or BigQuery for historical access.
  • Service Catalog — Gladly has no service request workflow. Redesign relevant items as Gladly Answers, self-service content, or Sidekick (Gladly's AI agent) flows.
  • SLA Policies — Freshservice SLA timers operate at the ticket level with escalation chains. Gladly's SLA targets operate differently at the conversation level. Do not attempt to transfer these — rebuild from scratch as Gladly Rules.
  • Workflow Automator, Supervisor, Dispatch'r, and Observer rules — Freshservice's event- and time-based automations do not have a structural equivalent in Gladly's Rules engine. Redefine automation logic from first principles.
  • Approval Workflows — Freshservice's multi-level approval chains have no Gladly equivalent.
  • Attachments, images, and recordings in Historical Import — Gladly's documented historical import does not support images, recordings, attachments, metrics, or routing/conversation assignments. (help.gladly.com)
  • Custom Dashboards and Analytics — Freshservice Analytics reports cannot be exported to Gladly. Recreate reporting views in Gladly Insight. Note that Gladly Insight reports at the conversation level, not the ticket level — your historical Freshservice metrics (MTTR, ticket volume by category, SLA compliance) will not have direct equivalents.

Timeline Scale: When Does the Person-Centric Model Break Down?

A Freshservice requester who submitted 200 tickets over 5 years will have all 200 tickets — potentially thousands of individual Conversation Items — loaded onto a single Gladly timeline. This is the structural risk of migrating to a person-centric model from a ticket-centric one.

At scale, this creates practical usability problems:

  • Agents scrolling through hundreds of historical items to find recent context
  • Timeline loading time increasing with item density
  • Legitimate current interactions visually buried beneath years of imported history

Mitigations:

  • Import only the last 12–24 months of ticket history per customer, not full history. Older data can be archived with a reference link in the customer's Custom Attributes.
  • Use Gladly's Lookup API to surface order/account/subscription context in real time rather than loading it as static timeline items.
  • Mark all imported items with a consistent prefix (e.g., [Historical - Freshservice]) so agents can visually distinguish imported reference data from live interactions.
  • Gladly does not publish a documented per-timeline item limit, but you should test with your highest-volume customers in a staging environment before committing to a full import.

Extraction: Getting Data Out of Freshservice

Freshservice API v2 Basics

The Freshservice API is RESTful, uses Basic Auth with API keys, enforces minute-level rate limits that vary by pricing plan, and paginates with page and per_page query parameters (max 100 per page). (api.freshservice.com)

The extraction endpoints you will use:

GET /api/v2/tickets?per_page=100&page={n}          # List tickets
GET /api/v2/tickets/{id}                            # Single ticket detail
GET /api/v2/tickets/{id}/conversations               # Replies and notes
GET /api/v2/requesters?per_page=100&page={n}         # List requesters
GET /api/v2/agents?per_page=100&page={n}             # List agents
GET /api/v2/groups?per_page=100&page={n}             # List groups
GET /api/v2/solutions/categories                     # Knowledge base
GET /api/v2/ticket_fields                            # Custom field definitions

Freshservice also provides a Data Export feature (Admin > Account > Data Export) that produces CSV files for tickets. This export covers ticket-level fields but does not include conversation threads or internal notes. It can supplement extraction for large ticket volumes by reducing the number of list API calls needed, but you still require the Conversations API for full thread data.

Rate Limits by Plan

Rate limits are account-wide, regardless of the number of agents or IP addresses making calls:

  • Starter: 100 requests/minute
  • Growth: 200 requests/minute
  • Pro: 400 requests/minute
  • Enterprise: 500 requests/minute

Add-on packs can increase the limit: Pack 1 raises it to 1,000 req/min, Pack 2 to 2,000 req/min.

The List All Tickets endpoint has its own sub-limits, ranging from 40 to 140 requests per minute depending on plan. Invalid requests count against the limit, and embedded resources (include= parameters) consume extra API credits.

Extraction Traps

Deep pagination breaks. Freshservice enforces pagination depth limits on list endpoints. For any dataset beyond a few thousand tickets, standard page-based pagination will eventually fail or return empty results. The fix: use the updated_since filter to paginate chronologically through time windows instead of pages.

GET /api/v2/tickets?updated_since=2023-01-01T00:00:00Z&per_page=100&page=1

Capture the updated_at timestamp of the last record in each batch and use it as the updated_since value for the next request. This approach also handles delta extraction for cutover without re-running the full pull.

include=conversations is a trap. The include=conversations parameter on ticket list endpoints returns only up to 10 conversations per ticket (sorted by created_at ascending) and counts as 2 API calls per request. For full ticket history, you must call the conversations endpoint for each ticket individually.

Standard exports miss conversations. Freshservice's Data Export feature includes ticket-level data only, not conversations or internal notes. You need the Conversations API for those.

Archived tickets require extra handling. Tickets older than approximately one year may be archived (accounts must have 500,000+ total tickets to be eligible for archival). Archived tickets can be accessed individually by ticket ID but will not appear in standard list responses. You cannot enumerate archived tickets via the list endpoint — you need ticket IDs from a prior export or Data Export CSV to fetch them individually.

Attachment URLs expire. Freshservice stores attachments in AWS S3 and provides temporary, expiring URLs in API responses. These URLs typically expire within 24–48 hours. Your extraction script must download attachments immediately upon extraction, not log the URL for later retrieval.

Multi-workspace gotcha. If you do not pass workspace_id, Freshservice returns only the primary workspace. Passing workspace_id=0 gives cross-workspace results but only global fields. Be deliberate about which workspaces you extract.

Tip

Practical extraction throughput by plan, assuming 1 API call per conversation fetch and average 8 conversations per ticket:

  • Starter (100 req/min): ~12 tickets/minute with conversation fetch → 20,000 tickets takes ~28 hours
  • Growth (200 req/min): ~22 tickets/minute → 20,000 tickets takes ~15 hours
  • Pro (400 req/min): ~44 tickets/minute → 20,000 tickets takes ~8 hours
  • Enterprise (500 req/min): ~55 tickets/minute → 20,000 tickets takes ~6 hours

These estimates assume single-threaded extraction, no embedded resources, and average conversation count. Parallelizing across date-range partitions can reduce wall-clock time but does not change throughput against the account-wide rate limit.

Loading Data into Gladly

Import Paths

Gladly offers two paths for historical data:

  1. Gladly Professional Services import — Gladly can import historical conversations from several popular platforms via structured CSV. Freshservice is not listed as a natively supported source as of the time of writing, so you will need to export data into a Gladly-compatible CSV format. Gladly Professional Services recommends batches of 500K rows, loaded approximately 2 weeks before launch, with a final delta load approximately 2 days after launch. If this import is not defined in your Statement of Work, contact your implementation team for a quote. (help.gladly.com)

  2. Gladly REST API (Create Timeline Item) — This API adds items to the timeline for a customer identified by email or phone. If the customer does not exist, a new profile is created. Items created this way are not considered part of a conversation and are non-routable and non-searchable aside from the email address or phone number specified. (developer.gladly.com)

Either way, historical Freshservice data in Gladly is agent context, not operational data. Agents can view it on the customer timeline, but it does not appear in Gladly Insight reporting, cannot be routed, and is not searchable beyond the customer identifier. Set this expectation with your team before the migration begins.

Gladly API Rate Limits

The default is 10 API calls per second. Organizations that exceed this will receive 429 responses. At 10 req/sec, you can create up to 600 timeline items per minute. You need backoff logic that reads the Retry-After response header on 429 responses.

Gladly externalCustomerId and Duplicate Handling

Gladly uses email address as the primary deduplication key for Customer profiles. When you POST a timeline item with a customer email that already exists in Gladly, the item is appended to the existing customer's timeline. A new profile is created only if no matching email is found.

The externalCustomerId field allows you to assign a stable external identifier to a Gladly Customer profile — in this migration, use the Freshservice requester ID (e.g., fs_123456789). This creates a deterministic link that prevents duplicate customer creation during delta syncs.

Important collision behavior: If you attempt to create a Customer with an externalCustomerId that already exists on a different profile, the API returns a conflict error. This can occur if the same requester was extracted twice with different email addresses (common with alias emails or shared inboxes) and loaded as separate Gladly profiles before the deduplication pass. Resolve requester duplicates in your transform step, before loading.

Gladly Import Field Constraints

These limits apply to the historical import CSV format:

  • body: capped at 25,000 characters
  • title: capped at 100 characters
  • activityType: must be one of EMAIL, ISSUE, SMS, or SURVEY
  • Phone numbers: must be in E.164 format
  • Email required: imports without a valid email address are rejected
  • Large imports: Gladly recommends batches of 500K rows, loaded ~2 weeks before launch, with a final delta 2 days after launch
  • Some profile fields are first-import-only and cannot be updated through subsequent imports

(help.gladly.com)

Gladly also supports bulk CSV import for Topics, Answers, and Users. Rules and Inboxes require manual configuration through the Gladly admin UI — there is no bulk import path for those objects.

Step-by-Step Migration Process

Step 1: Audit and Scope Your Freshservice Instance

Before writing any code:

  • How many tickets are in scope? Exclude internal IT tickets, spam, and test data. Count only external customer-facing tickets.
  • How many unique requesters have valid external email addresses?
  • What is your distribution of conversation depth? Average conversations per ticket determines extraction time more than ticket count.
  • Which custom fields are actively used by agents and need to carry over?
  • Do you need to migrate knowledge base articles?
  • What is your Freshservice plan? This determines extraction throughput.
  • How many workspaces are in play? Each workspace requires separate extraction.
  • What is the oldest ticket date you need to migrate? Older data may be archived and require different handling.

Step 2: Set Up the Gladly Environment

  • Provision a Gladly sandbox or staging environment.
  • Create Teams (mapped from Freshservice Groups).
  • Create Inboxes for each support channel.
  • Define Topics (mapped from Freshservice tags or categories — keep the hierarchy shallow, 2–3 levels maximum).
  • Set up Custom Attributes for any custom fields you need to preserve.
  • Create agent accounts via IdP/SSO or CSV bulk upload. Agents must be provisioned in Gladly before the data migration — do not attempt to create agent credentials via the REST API.
  • Disable all Gladly Rules before beginning any import. Active Rules may trigger assignment logic, notifications, or SLA timers on historical data loaded via the API.

Step 3: Extract Data from Freshservice

Build an extraction pipeline that:

  1. Pulls all requesters via /api/v2/requesters — collect id, email, name, phone.
  2. Uses Data Export CSV (if available) for an initial ticket list, then supplements with the API for conversations.
  3. Pulls tickets using updated_since pagination to handle large volumes and enable delta re-runs. Partition by 30-day windows for datasets over 10,000 tickets.
  4. For each ticket, fetches full conversations via /api/v2/tickets/{id}/conversations (do not rely on include=conversations — it caps at 10 replies).
  5. Stores everything in an intermediate staging database (SQLite for small migrations, PostgreSQL for large ones) rather than flat JSON files — this allows restarts without re-extracting.
  6. Downloads all attachments immediately upon extraction to local storage or S3, before URLs expire.
  7. Implements rate-limit handling with exponential backoff using the Retry-After header.
import requests
import time
from datetime import datetime, timedelta
 
FRESHSERVICE_DOMAIN = "yourcompany.freshservice.com"
API_KEY = "your_api_key"
 
def get_tickets_since(updated_since: str, page: int = 1) -> dict:
    """
    Fetch tickets updated after `updated_since` (ISO 8601 string).
    Uses time-window pagination to avoid deep page limits.
    """
    url = (
        f"https://{FRESHSERVICE_DOMAIN}/api/v2/tickets"
        f"?updated_since={updated_since}&per_page=100&page={page}"
    )
    response = requests.get(url, auth=(API_KEY, "X"))
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", 60))
        print(f"Rate limited. Sleeping {retry_after}s.")
        time.sleep(retry_after)
        return get_tickets_since(updated_since, page)
    response.raise_for_status()
    return response.json()
 
def extract_all_tickets(start_date: str) -> list:
    """
    Paginate through all tickets updated since start_date.
    Advances the window using the last ticket's updated_at timestamp.
    """
    all_tickets = []
    current_since = start_date
 
    while True:
        page = 1
        window_tickets = []
 
        while True:
            data = get_tickets_since(current_since, page)
            tickets = data.get("tickets", [])
            if not tickets:
                break
            window_tickets.extend(tickets)
            page += 1
 
        if not window_tickets:
            break
 
        all_tickets.extend(window_tickets)
        # Advance window to last ticket's updated_at timestamp
        last_updated = window_tickets[-1]["updated_at"]
        current_since = last_updated
        # If last batch was less than 100, no more pages in this window
        if len(window_tickets) < 100:
            break
 
    return all_tickets
 
def get_conversations(ticket_id: int) -> list:
    """Fetch all conversation threads for a single ticket."""
    url = f"https://{FRESHSERVICE_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)
    response.raise_for_status()
    return response.json().get("conversations", [])

Step 4: Transform Data to Gladly Format

For each Freshservice ticket:

  1. Identify the customer by requester email. Freshservice requesters without a valid email will be rejected by Gladly — decide whether to enrich those records before migration or accept data loss.

  2. Build Conversation Items from the ticket description (opening message) and each reply/note in the thread. Each public reply and each internal note becomes a separate Conversation Item.

  3. Preserve chronological orderoccurredAt timestamps determine timeline ordering. Out-of-order timestamps produce a confusing agent experience.

  4. Preserve the Freshservice Ticket ID. Write the original ticket number into a Custom Attribute or prepend it to the first Conversation Item body: [Historical Import - Freshservice Ticket #INC-98765]. This is the only way agents can cross-reference the migrated history with the original Freshservice record.

  5. Map Freshservice requester_id → Gladly externalCustomerId using a consistent format like fs_{requester_id}. This creates a deterministic link that prevents duplicate profile creation during delta syncs.

    Requester → Customer mapping example:

    {
      "name": "Jane Doe",
      "emails": ["jane.doe@example.com"],
      "externalCustomerId": "fs_123456789"
    }
  6. Map tags → Topics selectively. Only promote intent-like tags (e.g., billing, returns, account-access) to Gladly Topics. Operational tags (waiting-on-vendor, jira-linked, escalated-l2) belong in the body text or a custom attribute, not your Topic tree.

  7. Map statuses. Freshservice has Open, Pending, Resolved, and Closed. Gladly only has OPEN and CLOSED. Map Open/Pending → OPEN and Resolved/Closed → CLOSED.

  8. Strip ITSM metadata that has no Gladly equivalent (priority, impact, urgency, SLA timer values, asset associations) — or flatten it into the first Conversation Item body for agent reference:

    [Freshservice Ticket #INC-98765 | Priority: High | Category: Network | Resolved: 2024-03-15]
    
  9. Handle internal notes explicitly. Freshservice conversations include both public replies and private notes (incoming flag distinguishes them). Gladly's historical import does not have a separate private note type — all Conversation Items are visible to agents. Decide upfront whether to import private notes or exclude them. If you import them, label them clearly in the body.

  10. Convert HTML to plain text. Freshservice ticket descriptions and replies are HTML. Gladly's historical import expects plain text or a specific format. Strip HTML tags using a library (Python's html.parser, bleach, or markdownify). Rich formatting, inline images, and embedded tables will be lost or degraded — this is expected and not recoverable within Gladly's import constraints.

  11. Truncate to field limits. Trim body to 25,000 characters and title to 100 characters. For long tickets, truncate and append [truncated — see Freshservice ticket #INC-98765 for full history].

Here is the shape of a Gladly-compatible CSV row:

customer_email,customer_name,title,body,activityType,occurredAt,sourceName
jane@example.com,Jane Doe,Ticket 10482 - Password reset,"[Freshservice #INC-10482 | Priority: High | Status: Resolved]
 
Original body goes here.",ISSUE,2026-07-14T13:22:11.000Z,Freshservice

Step 5: Load into Gladly

Using the Gladly REST API or Professional Services bulk import:

  1. Create or match Customers — Use email as the unique identifier. If the customer already exists in Gladly, the API merges the timeline item onto the existing profile. If not, a new profile is created.
  2. Verify externalCustomerId before each load batch — if a collision is detected (same external ID on a different profile), resolve it before proceeding or you will receive a conflict error that halts the batch.
  3. Insert Conversation Items in chronological order per customer.
  4. Validate — Spot-check 50–100 customer profiles, weighted toward your highest-volume customers. Verify data integrity, correct ordering, completeness, and that long ticket threads (10+ replies) came through fully without truncation.
  5. Confirm Rules are disabled during the load. Re-enable them after the import is complete and validated.

Step 6: Rebuild Configurations

No API can migrate business logic. Manually recreate:

  • Rules — replacing Freshservice Workflow Automator, Supervisor rules, Dispatch'r, Observer, and SLA policies. Map each Freshservice automation to its Gladly Rules equivalent, or redesign for Gladly's routing model.
  • Answers — replacing Freshservice knowledge base articles. Freshservice structures knowledge in Categories > Folders > Articles. Gladly Answers are channel-aware content objects with separate email, messaging, public, and internal variants. One Freshservice article often needs to be split into several Gladly Answer variants because messaging Answers do not support custom HTML or vanity links. Gladly supports bulk Answer import by CSV.
  • People Match settings — configure how Gladly identifies returning customers across channels.
  • Routing rules and Inbox assignments — configure channel routing, business hours, and escalation paths.
  • Sidekick (Gladly AI) configuration, if applicable — define which Answers Sidekick can surface autonomously.
  • CSAT survey integration — reconnect or reconfigure your CSAT tooling.

Step 7: Cutover

  1. Freeze ticket creation in Freshservice (or set to read-only) at the agreed cutover timestamp.
  2. Run a delta extraction for any tickets created or updated since your last full extraction, using updated_since={cutover_timestamp}.
  3. Load the delta into Gladly.
  4. Switch DNS, email forwarding, and live channel routing to Gladly.
  5. Monitor for 24–48 hours. Keep Freshservice accessible in read-only mode for at least 90 days — because imported Gladly history is reference data, not a replacement for historical Freshservice analytics or archived ITSM records. Your IT team still needs Freshservice for asset and change history.

Edge Cases and Failure Modes

Requester Deduplication

Freshservice requesters may have multiple records for the same person (different email addresses, duplicate entries from portal and email submission). Gladly deduplicates by email and phone. Run a deduplication pass on your extracted requester data before loading — resolve alias emails and shared inboxes during the transform step, or you will create orphaned profiles in Gladly. Common sources of duplicates: requesters who submitted tickets via the portal with one email and via email with a different address, and shared team inboxes that Freshservice logged as individual requesters.

Tickets Without Email Addresses

Freshservice allows tickets from requesters identified only by name or phone number. Gladly imports require a valid email address — rows without one are rejected. You must either enrich the requester record with an email before migration or accept data loss on those tickets. For phone-only requesters, you can attempt import using E.164 phone number as the identifier via the REST API, but the Professional Services CSV import requires email.

Attachment Archival Strategy

Gladly's historical import is text-only. For significant attachment data (screenshots, logs, documents), archive attachments externally — an S3 bucket or shared drive. Include a reference URL in the migrated Conversation Item body so agents can access the original file. Use the link.url and link.title fields in Gladly's CSV import schema for these archive pointers.

Attachment URL expiry is a real operational risk. Freshservice's S3 URLs expire within 24–48 hours of the API response. Your extraction script must download and store attachment binaries immediately. Any extraction script that logs URLs for batch downloading later will fail.

Requester Without Email — Decision Tree

Does the Freshservice requester have a valid email?
├── YES → Include in migration
└── NO
    ├── Does the requester have a phone number in E.164 format?
    │   ├── YES → Load via REST API using phone as identifier (not via CSV bulk import)
    │   └── NO → Exclude from migration; log ticket IDs for manual review
    └── Can you enrich the record with an email from an external CRM or data source?
        ├── YES → Enrich and include
        └── NO → Exclude and archive

Automation Triggers During Import

If loading data via the Gladly REST API with Rules enabled, newly created timeline items may trigger assignment rules, notifications, or SLA timers on historical data — generating spurious agent notifications and incorrect SLA measurements. Disable all Rules before import; re-enable after validation.

Post-Migration Webhooks and Event System

Gladly supports webhooks for conversation events (conversation created, item added, conversation closed). After cutover, verify that your webhook subscriptions are configured for the live Gladly environment, not the sandbox. If you were sending Freshservice events to a data warehouse or CRM, update those integrations to consume Gladly webhooks instead.

Live Context After Cutover

If agents need order, account, subscription, or loyalty context alongside migrated history, use Gladly's Lookup API rather than overstuffing profile custom attributes with static data. Gladly Lookup responses should return in under 5 seconds; the platform times out after 15 seconds. Loading real-time context via Lookup also avoids the problem of stale data in custom attributes.

Timeline and Effort Estimates

These estimates assume: single-threaded extraction, average of 8 conversations per ticket, average body size of 2KB per conversation, and Gladly Professional Services handling the bulk import. Parallelizing extraction across date-range partitions can reduce wall-clock extraction time but does not increase throughput against the account-wide rate limit.

Instance Size Ticket Count Extraction Time (Pro Plan, 400 req/min) Load Time Total Migration Window
Small < 5,000 2–4 hours 1–2 hours 1 week (including config rebuild)
Medium 5,000–50,000 8–36 hours 4–12 hours 2–3 weeks
Large 50,000–200,000 3–7 days 1–3 days 3–4 weeks
Enterprise 200,000+ 1–2 weeks 3–5 days 4–6 weeks

Configuration rebuild (Rules, Answers, Inboxes, routing) is often the longest phase for complex Freshservice instances — budget 1–2 weeks separately from data migration, regardless of ticket volume.

DIY vs. Managed Migration

DIY makes sense when:

  • You have fewer than 5,000 tickets to migrate
  • Your Freshservice instance uses mostly default fields and one workspace
  • You have engineering resources available for 1–2 weeks
  • You are comfortable with data loss on attachments and non-text content
  • Requesters have clean, unique email addresses with no deduplication issues
  • Your Freshservice plan is Growth or above (100 req/min on Starter makes DIY extraction painful)

A managed migration makes sense when:

  • You have more than 5,000 tickets or complex custom field schemas
  • You need zero-downtime cutover with delta sync
  • You have multi-workspace extraction complexity
  • You need attachment archival and reference linking
  • You need to coordinate the load timing with Gladly Professional Services
  • You cannot afford a failed migration attempt that consumes your cutover window

For related migration planning, see our guides on Zendesk to Gladly migration and Freshdesk to Gladly migration. If you are evaluating adjacent Freshservice destinations, see our Freshservice to LiveChat migration guide.

What a Realistic Migration Looks Like

A Freshservice to Gladly migration is not a weekend project. The data model gap between an ITSM platform and a person-centric CX platform means you are discarding more data than you are keeping — assets, CMDB, changes, problems, releases, SLA history, approval workflows, and all automation logic. That is by design. Gladly is not meant to replace Freshservice's ITSM capabilities.

The honest sequence: audit your Freshservice data and isolate the customer-facing subset, extract within API rate limits using time-window pagination, transform into Gladly's timeline model with explicit handling for internal notes and email-less requesters, load as reference-only historical context with Rules disabled, rebuild all automation and routing logic from scratch in Gladly, and keep Freshservice in read-only mode for at least 90 days post-cutover for IT team reference.

The most common failure modes are: importing too much history (making timelines unusable for high-volume customers), attempting to migrate ITSM concepts that have no Gladly equivalent, and underestimating the configuration rebuild effort for Rules and Inboxes.

Frequently Asked Questions

Can I migrate Freshservice assets and CMDB data to Gladly?
No. Gladly has no asset management, CMDB, or configuration item tracking. These entities must be archived separately (e.g., a data warehouse like Snowflake or Redshift) or kept in Freshservice. Only customer-facing ticket data — requesters, conversations, tags — can be migrated to Gladly.
Does Gladly support importing attachments from Freshservice?
No. Gladly's historical import is text-only and does not support attachments, images, recordings, or metrics. Archive attachments externally (e.g., S3 bucket) and include reference links in the migrated conversation items using Gladly's link.url and link.title fields.
How long does a Freshservice to Gladly migration take?
A small instance (under 5,000 tickets) takes about 1 week including configuration. A mid-size instance (5,000–50,000 tickets) takes 2–3 weeks. Large instances (50,000+) can take 4–6 weeks. Extraction speed depends on your Freshservice plan's API rate limit.
Is migrated Freshservice data searchable in Gladly?
No. Historical imports into Gladly are reference-only on the customer profile. They are not searchable, not reportable, and cannot be routed. Agents can view the data on the customer timeline for context, but it does not appear in Gladly analytics or reporting.
How do I handle multi-workspace Freshservice extraction?
Pass workspace_id deliberately in your API calls. If you omit it, Freshservice returns only the primary workspace. Setting workspace_id=0 gives cross-workspace results but only with global fields. Plan your extraction per workspace to get complete custom field data.

More from our Blog