---
title: "Zoho Desk to Freshdesk Migration: The Complete Technical Guide"
slug: zoho-desk-to-freshdesk-migration-the-complete-technical-guide
date: 2026-07-06
author: Nachi
categories: [Freshdesk, Zoho Desk, Migration Guide]
excerpt: "Step-by-step guide to migrating Zoho Desk to Freshdesk. Covers API rate limits, object mapping, the export trap that drops threads, and edge cases."
tldr: "Zoho Desk CSV exports drop threads. Use the API or Data Backup, plan 2–4 weeks, handle Freshdesk's 400–700 req/min limits, and request a migration API key for timestamps."
canonical: https://clonepartner.com/blog/zoho-desk-to-freshdesk-migration-the-complete-technical-guide/
---

# Zoho Desk to Freshdesk Migration: The Complete Technical Guide


# Zoho Desk to Freshdesk Migration: The Complete Technical Guide

> [!NOTE]
> **TL;DR — Zoho Desk to Freshdesk Migration**
>
> Zoho Desk's standard ticket export drops all conversation threads and comments. A complete migration requires API-based extraction or Zoho's Data Backup feature. Plan 2–4 weeks end-to-end, including discovery, sandbox testing, UAT, and delta sync. The load side is bounded by Freshdesk's plan-based rate limits (400 req/min on Pro, 700 on Enterprise). Zoho Desk Blueprints, Products, and Activities have no Freshdesk equivalent — archive or rebuild those. Contact Freshdesk support for a special migration API key before starting, or all imported tickets will show today's date instead of historical timestamps.

## What Is a Zoho Desk to Freshdesk Migration?

A Zoho Desk to Freshdesk migration is the extraction, transformation, and loading of tickets, contacts, accounts, agents, knowledge base articles, and their associated metadata from Zoho Desk into Freshdesk — while preserving conversation history, relationships, and timestamps.

Teams typically move to Freshdesk to consolidate within the Freshworks ecosystem, access a more flexible automation engine, or improve SLA management and multi-channel support. If you're still evaluating platforms, review our [operations lead's guide to Freshdesk vs Help Scout vs Zendesk](https://clonepartner.com/blog/blog/freshdesk-vs-help-scout-vs-zendesk-the-operations-leads-guide/).

Three architectural differences make this migration non-trivial:

1. **Zoho Desk uses Departments; Freshdesk uses Groups.** Departments in Zoho Desk are top-level organizational units that control ticket routing, agent access, and layouts. Freshdesk Groups are simpler agent-grouping constructs. There is no 1:1 mapping.
2. **Ticket threading models differ.** Zoho Desk stores Threads and Comments as separate child objects on tickets. Freshdesk uses Conversations (replies and notes). Thread direction, visibility, and channel metadata must be transformed.
3. **API throttling models are fundamentally different.** Zoho Desk uses a daily credit-based system with concurrency limits. Freshdesk uses per-minute rate limits with per-endpoint sub-limits.

## Zoho Desk vs Freshdesk: Core Object & Field Mapping

Mapping objects correctly before writing a single line of code prevents orphaned records and re-work. The failure point is usually not the objects themselves — it's the behavior attached to those objects: queue ownership, form logic, conversation visibility, and reporting timestamps.

| Zoho Desk Object | Freshdesk Object | Notes / Caveats |
|---|---|---|
| Departments | Groups | Departments control layouts, SLAs, and agent access in Zoho Desk. Groups in Freshdesk are simpler. If you use Zoho Departments for distinct brands, map them to Freshdesk Products instead. |
| Accounts | Companies | Freshdesk requires Company names to be unique — deduplicate Zoho Accounts before loading. Custom fields require manual re-creation. |
| Contacts | Contacts | Freshdesk uses email as the primary identifier. Zoho Desk supports multi-account contact mapping; Freshdesk links one company per contact. Contacts without emails require dummy emails or phone number mapping. |
| Tickets | Tickets | Status values, picklists, and custom fields need explicit mapping. Zoho custom fields must be pre-created in Freshdesk with matching data types. |
| Threads | Conversations (replies/notes) | Zoho Desk separates public threads, private threads, and comments. Freshdesk uses reply, note, and forward. Direction (`in`/`out`) and visibility (`public`/`private`) must be transformed. |
| Tags | Tags | Direct mapping. |
| Agents | Agents | Agent roles and profiles differ structurally. Agents must be created in Freshdesk first to retain ticket assignment history. |
| KB Articles | Solution Articles | Freshdesk structures KB articles under Categories and Folders. Zoho Desk hierarchies must be rebuilt to match this structure. |
| Blueprints | ❌ No equivalent | Freshdesk has no Blueprint feature. Workflow rules can partially replicate this. |
| Products | ❌ No native equivalent | Freshdesk does not have a Products module. Products can be stored as tags or custom dropdown values. |
| Activities (Tasks/Calls/Events) | ❌ No equivalent | Freshdesk does not support activities. Archive these separately. |
| SLAs | SLA Policies | Must be manually recreated. SLA history does not migrate. |
| Custom Fields | Custom Fields | Field types must match exactly. A Zoho `Picklist` maps to a Freshdesk `custom_dropdown`. A Zoho `Multiselect` maps to a Freshdesk `custom_checkbox` (array). Mismatched types cause silent data truncation. |

**Field-level detail:** Custom field API names in Freshdesk are auto-generated with a `cf_` prefix based on the UI label — not the Zoho Desk API name. Use `GET /api/v2/ticket_fields` on Freshdesk to discover the correct internal names before writing any import logic.

Zoho Desk allows custom statuses in some configurations, while Freshdesk requires strict predefined status IDs (e.g., Open = 2, Pending = 3, Resolved = 4, Closed = 5). Any historical Zoho status that doesn't have a Freshdesk equivalent must be mapped to an existing ID or recreated in the destination before the load begins.

For a deeper dive into deciding what historical data to actually migrate, read our [help desk data migration playbook](https://clonepartner.com/blog/blog/help-desk-data-migration-playbook/).

## The Export Trap: Why Standard Zoho Desk Exports Lose Ticket Threads

This is the single most common mistake teams make when planning a Zoho Desk to Freshdesk migration.

Zoho Desk's standard ticket export (Setup → Data Administration → Export) omits ticket threads and comments entirely. <cite index="43-3,43-4,43-5,43-6">Exports from the standard module export include up to 3,000 records at a time, and report exports max out at 20,000 records. But these exports do not include threads or comments. To get an export that includes threads and comments, you must contact support@zohodesk.com for a Data Backup.</cite>

If you export via CSV and import into Freshdesk, you get ticket metadata (subject, status, priority, custom fields) but zero conversation history. You recreate ticket shells but lose the actual customer-agent exchanges that make those tickets useful.

**Three extraction paths that preserve threads:**

1. **Zoho Desk REST API** — The `GET /api/v1/tickets/{ticket_id}/threads` endpoint returns full thread content including HTML body, attachments, and direction. This is the only path that gives you programmatic, reliable, targeted access to full conversation data. **Note:** Zoho Desk has been introducing v2 API endpoints alongside v1. Verify current endpoint availability against Zoho's API changelog before locking your script to a specific version, as v1 endpoints may be deprecated on a rolling basis.
2. **Data Backup feature** — Available on request from Zoho Desk support (contact support@zohodesk.com). Provides a bulk export including tickets, threads, comments, and attachment download links. Attachments arrive as secure download links that must be fetched separately before they expire.
3. **Bulk Export API** — The `/api/v1/bulkExport` endpoint supports exporting up to 100,000 records per request with callback URLs, but thread content still requires individual API calls per ticket.

> [!WARNING]
> **Data Backup constraints:** Only the Zoho Desk **primary contact** can create or download backups. Zoho documents a **10 million record** backup ceiling, **31-day** limits for custom backup windows, and a **30-day** wait between full backups. Attachment entries arrive as secure download links rather than already-expanded files — plan around these rules before announcing a cutover date. ([help.zoho.com](https://help.zoho.com/portal/en/kb/desk/data-administration/backup-and-data-archive/articles/backing-up-your-help-desk-data))

## Migration Architecture: API Rate Limits & Throughput Math

API rate limits are the primary bottleneck in any helpdesk migration. Your extraction and loading scripts must be modeled against vendor constraints to prevent throttling and data gaps.

### Zoho Desk Extraction

<cite index="2-3">All Zoho Desk APIs support a maximum of 50 records per request.</cite> The API uses a credit-based system where credits reset every 24 hours.

| Zoho Desk Edition | Base Credits + Per User/Day | Concurrency Limit |
|---|---|---|
| Standard | 50,000 + 250/user | 10 |
| Professional | 75,000 + 500/user | 15 |
| Enterprise | 100,000 + 1,000/user | 25 |

<cite index="2-19,2-20,2-21,2-22">Fetching records near the beginning of the dataset consumes around 3 credits per call. Fetching the same number of records from index 10,005 to 10,054 consumes up to 50 credits. The deeper the data range, the higher the credit consumption.</cite>

**Throughput calculation for a Professional account with 20 agents:**
- Daily credits: 75,000 + (20 × 500) = 85,000
- A ticket with 10 threads costs roughly 11 credits (1 to list threads + 1 per thread detail)
- At 85,000 daily credits: ~7,700 tickets with full thread extraction per day
- **Deep-pagination tax:** If you're extracting tickets at high offsets (beyond the 10,000th record), credit costs per call escalate from ~3 to ~50 credits. Extract in `modifiedTime`-sorted batches with date windowing to minimize deep pagination.

**OAuth token refresh:** Zoho OAuth2 access tokens expire every 60 minutes. Your extraction script must handle automatic token refresh using the refresh token grant flow (`POST https://accounts.zoho.com/oauth/v2/token` with `grant_type=refresh_token`). A static token will silently fail after the first hour, causing incomplete extraction without an obvious error.

### Freshdesk Load

<cite index="14-18">Freshdesk enforces per-minute rate limits: Growth plan gets 200 calls/min, Pro gets 400 calls/min, and Enterprise gets 700 calls/min.</cite> <cite index="14-20">The limit is account-wide regardless of how many agents or IPs make the calls, and there are additional per-endpoint sub-limits.</cite>

<cite index="17-8">When the limit is exceeded, HTTP 429 is returned.</cite> <cite index="17-24">Authentication is HTTP Basic Auth using an API key as the username and any non-empty string as the password.</cite>

**Throughput calculation on Freshdesk Pro (400 calls/min):**
- Creating one ticket: 1 call
- Adding one conversation note: 1 call
- A ticket with 10 conversations: 11 calls
- At 400 calls/min: ~36 tickets/minute → ~2,180 tickets/hour with full conversations
- 50,000 tickets with an average of 10 conversations: ~23 hours of continuous loading

**Worked example for 100,000 tickets:**
Assume 100,000 historical tickets averaging 3 conversation threads each. That's 100,000 ticket creates plus 300,000 conversation creates — 400,000 total Freshdesk API calls. At the Pro plan limit of 400 requests/minute, the theoretical minimum is ~16.7 hours. In practice, accounting for network latency, attachment uploads (which consume additional calls and bandwidth), and retry logic, this load takes 35–45 hours.

**Attachment-specific limits:** Freshdesk caps file attachments at 20 MB per file and allows a maximum of 15 attachments per ticket or conversation. Your loader must validate attachment sizes before upload and handle oversized files gracefully (e.g., host on S3 and inject a download link into the note body).

**Concurrent extraction and loading:** You can run Zoho Desk extraction and Freshdesk loading in parallel — extract a batch, transform, and load while the next batch extracts — as long as dependency ordering is maintained (companies before contacts before tickets). Running sequentially is simpler but adds elapsed time. Parallel pipelines require a queue or staging database to buffer transformed records.

> [!WARNING]
> **Freshdesk timestamp limitation:** The standard Freshdesk ticket creation API (`POST /api/v2/tickets`) does not allow you to set `created_at` or `updated_at` timestamps. All imported tickets will show today's date unless you contact Freshdesk support for a special migration API key that permits setting historical timestamps. This is a well-documented limitation that catches many DIY migrations. Request the key before you start scripting — approval can take 2–5 business days and there is no additional cost, but it requires explaining your migration use case to Freshdesk support.

For detailed timeline planning, see our [help desk data migration timeline](https://clonepartner.com/blog/blog/help-desk-data-migration-timeline/).

## How to Choose a Migration Approach

The right method depends less on raw ticket count and more on whether you need threaded history, attachments, custom field fidelity, and a live delta sync while support keeps working.

| Approach | How It Works | Best For | Complexity | Risk |
|---|---|---|---|---|
| **CSV Export/Import** | Export from Zoho Desk UI, import into Freshdesk via UI | Quick snapshot of ticket metadata only — no threads | Low | High — you lose all conversation history |
| **Third-Party Migration Tool** (e.g., Help Desk Migration) | Automated SaaS wizard connecting both platforms | Mid-size accounts with standard configurations | Low–Medium | Medium — limited control over inline images, custom objects, and edge cases |
| **Custom API Scripts** | Build extraction and load scripts against both REST APIs | Engineering teams needing full control over complex field mapping | High | Medium — if you handle rate limits, retries, and relationship ordering correctly |
| **Managed Migration Service** | Dedicated migration engineers handle end-to-end | Enterprise volumes, complex data models, zero-downtime requirements | Low (for you) | Low — accountability and error handling are built in |

**Practical guidance:** Use CSV import only for seed data (contacts, companies). Once the requirement includes tickets, conversations, or attachments, you're in API territory. A third-party tool can work if you have fewer than 5,000 tickets with standard fields and no attachment dependencies. Above 50,000 tickets, or if you need inline image preservation and timestamp fidelity, a managed service will save weeks of debugging.

## Step-by-Step Migration Process & Order of Operations

The order in which you create records in Freshdesk determines whether relationships survive. You cannot assign a ticket to a contact that doesn't exist, and you cannot link a contact to a company that hasn't been created.

**Required sequence:**

1. **Disable Freshdesk automations** — Before loading any data, disable Dispatch'r (ticket assignment rules), Supervisor (time-based rules), Observer (event-based rules), and all email notification rules in Freshdesk Admin. Imported tickets will otherwise trigger auto-assignment, SLA timers, canned responses, and customer notification emails — cascading side effects that corrupt both data and customer relationships.
2. **Create Agents and Groups** — Create all agents in Freshdesk first. Map Zoho Desk Departments to Freshdesk Groups. Store the new Freshdesk Agent and Group IDs for ticket assignment.
3. **Load Companies** — Migrate Zoho Desk Accounts as Freshdesk Companies. Freshdesk requires unique Company names — deduplicate before loading. Store the `Zoho_Account_ID → Freshdesk_Company_ID` mapping.
4. **Load Contacts** — Create Contacts, linking them to newly created Company IDs. Deduplicate by email to avoid HTTP 409 conflicts.
5. **Load Tickets** — POST to `/api/v2/tickets` with the correct `requester_id`, `group_id`, and `responder_id`. Use the migration API key (from Freshdesk support) to preserve historical timestamps. Store legacy Zoho ticket IDs in a custom field for traceability.
6. **Load Conversations** — For each ticket, create historical conversations as **notes** (not replies). Prepend the original sender name and timestamp to each note body. Preserve chronological ordering by inserting notes in sequence from oldest to newest.
7. **Download and Upload Attachments** — Download attachments and inline images from Zoho Desk to a temporary secure server, upload them to Freshdesk, and associate them with the correct ticket or conversation. Rewrite inline image `src` attributes in the HTML before loading. Respect the 15-attachment-per-conversation Freshdesk limit; split overflows into additional notes.
8. **Migrate Knowledge Base** — Recreate the category/folder structure in Freshdesk, then import articles with their hierarchy.
9. **Associate Tags** — Apply tags to tickets after ticket creation.
10. **Re-enable automations** — After the load and validation are complete, re-enable Dispatch'r, Supervisor, Observer, and email notifications. Verify automation rules fire correctly on a test ticket before opening inbound email flow.

> [!CAUTION]
> **Critical: Never use the Freshdesk reply endpoint (`POST /api/v2/tickets/{id}/reply`) for importing historical conversations.** Replies trigger outbound emails to customers. Use notes instead. Public notes are visible in the Freshdesk customer portal without sending an email — useful when you need portal-visible history without re-sending old messages. Disabling all email notification rules in Freshdesk Admin before starting the import provides an extra safeguard, but the note endpoint is the primary protection.

```python
# Extract threads from Zoho Desk with OAuth token refresh
import requests
import time

ZD_BASE = "https://desk.zoho.com/api/v1"
ZD_ORG_ID = "YOUR_ORG_ID"
ZD_REFRESH_TOKEN = "YOUR_REFRESH_TOKEN"
ZD_CLIENT_ID = "YOUR_CLIENT_ID"
ZD_CLIENT_SECRET = "YOUR_CLIENT_SECRET"

_access_token = None
_token_expiry = 0

def get_access_token():
    global _access_token, _token_expiry
    if _access_token and time.time() < _token_expiry - 60:
        return _access_token
    resp = requests.post("https://accounts.zoho.com/oauth/v2/token", data={
        "grant_type": "refresh_token",
        "client_id": ZD_CLIENT_ID,
        "client_secret": ZD_CLIENT_SECRET,
        "refresh_token": ZD_REFRESH_TOKEN
    })
    data = resp.json()
    _access_token = data["access_token"]
    _token_expiry = time.time() + data.get("expires_in", 3600)
    return _access_token

def extract_ticket_threads(ticket_id):
    url = f"{ZD_BASE}/tickets/{ticket_id}/threads"
    headers = {
        "Authorization": f"Zoho-oauthtoken {get_access_token()}",
        "orgId": ZD_ORG_ID
    }
    params = {"from": 1, "limit": 50}
    resp = requests.get(url, headers=headers, params=params)
    if resp.status_code == 429:
        time.sleep(60)  # Back off on rate limit
        return extract_ticket_threads(ticket_id)
    return resp.json().get("data", [])
```

```python
# Load conversation into Freshdesk as a note (avoids email notifications)
import requests
import time

FD_BASE = "https://yourdomain.freshdesk.com/api/v2"
FD_AUTH = ("YOUR_API_KEY", "X")

def create_fd_note(ticket_id, body_html, is_private=True):
    url = f"{FD_BASE}/tickets/{ticket_id}/notes"
    payload = {
        "body": body_html,
        "private": is_private
    }
    resp = requests.post(url, json=payload, auth=FD_AUTH)
    if resp.status_code == 429:
        retry_after = int(resp.headers.get("Retry-After", 60))
        time.sleep(retry_after)
        return create_fd_note(ticket_id, body_html, is_private)
    if resp.status_code == 413:
        # Attachment too large — log for manual review
        print(f"Payload too large for ticket {ticket_id}")
        return None
    return resp.json()
```

Make the loader **idempotent**. Persist legacy Zoho IDs in destination custom fields, log every request-response pair, retry 429s with exponential backoff and jitter (e.g., base delay × 2^attempt + random(0, 1s)), and never assume an attachment fetch will succeed on the first pass. Both platforms enforce limits differently, so transient failures are part of the job.

For keeping support running during cutover, see our guide on [zero-downtime help desk data migration](https://clonepartner.com/blog/blog/zero-downtime-help-desk-data-migration/).

## Timeline, Phases & Resourcing [For PMs]

A standard API-based migration takes 2–4 weeks from kickoff to go-live. A phased approach — moving the knowledge base first, then closed tickets, then active tickets — minimizes risk compared to a big-bang weekend cutover.

| Phase | Duration | Dependencies |
|---|---|---|
| Discovery & field mapping | 2–3 days | Access to both platforms, stakeholder alignment on which data to migrate |
| Script development / tool configuration | 3–5 days | API credentials (including Freshdesk migration API key — request immediately), custom field list, sample data |
| Test migration (subset) | 1–2 days | Freshdesk sandbox (Enterprise plan only) or a separate Freshdesk trial account for Pro/Growth plans |
| Validation & UAT | 2–3 days | Customer success and support lead review |
| Production migration | 1–3 days | Depends on volume — 50K tickets ≈ 1 day on Freshdesk Pro |
| Delta sync & go-live | 1–2 days | Final sync + DNS/email forwarding cutover |
| **Total** | **10–18 days** | |

**Sandbox availability note:** Freshdesk sandbox environments are only available on the Enterprise plan. If you're on Pro or Growth, create a separate free trial Freshdesk account for test migrations. Delete the trial after validation or convert it if needed.

**Risk register:**

| Risk | Likelihood | Mitigation |
|---|---|---|
| Zoho Desk API credit exhaustion mid-extraction | Medium | Monitor `X-Rate-Limit-Remaining` headers; use date-windowed batches to avoid deep pagination; spread extraction over multiple days |
| Freshdesk 429 errors causing data gaps | High | Implement exponential backoff with jitter; log every failed request to a retry queue; monitor `Retry-After` header |
| Inline images breaking post-migration | High | Download and re-upload all inline images; rewrite HTML `src` attributes before loading; verify with spot checks |
| Timestamps not preserved on imported tickets | High | Contact Freshdesk support for migration API key before starting; allow 2–5 business days for approval |
| Duplicate contacts/companies on re-run | Medium | Deduplicate by email; handle HTTP 409 responses; build idempotent loaders using Zoho ID → Freshdesk ID mapping tables |
| Freshdesk automations firing on imported tickets | High | Disable Dispatch'r, Supervisor, and Observer rules before import; re-enable after validation |
| Zoho OAuth token expiry during extraction | Medium | Implement automatic token refresh using refresh token grant; never hardcode access tokens |
| Partial migration failure with no rollback | Medium | Freshdesk has no bulk-delete API; build migration in reversible batches with clear logging; maintain a complete ID mapping for manual cleanup if needed |
| GDPR/data residency compliance breach | Low–Medium | If staging data on intermediate servers, ensure staging infrastructure complies with data residency requirements; use encrypted storage; delete staging data after migration completes |

## What Customers Notice During Migration [For Customer Success]

**If executed correctly: nothing significant.** Historical tickets appear in Freshdesk with their thread history intact (as notes). Customers can continue submitting new tickets throughout the migration — keep Zoho Desk live for inbound email during the cutover window, then redirect email forwarding to Freshdesk and run a final delta sync.

**What to communicate to customers:**
- Ticket reference numbers will change (Zoho Desk and Freshdesk use independent numbering). Consider storing the old Zoho ticket ID in a custom field and including it in the Freshdesk subject line for cross-reference.
- Help center URLs will change if you're migrating your knowledge base. Set up 301 redirects from old Zoho KB URLs to new Freshdesk Solution article URLs to preserve SEO and bookmarks.
- Customer portal login credentials may need to be re-issued.

**Preserving conversation history matters for trust.** When an agent opens a migrated ticket, they need to see the full customer exchange — not just the latest status. Without thread history, agents waste time asking customers to repeat themselves, which directly damages CSAT.

Decide early whether legacy conversations must be customer-visible in the Freshdesk portal. If yes, public notes work well — they are visible in the portal without triggering email notifications. If historical SLA reporting matters, keep a legacy Zoho Desk export as an archive; Freshdesk's SLA model won't reproduce Zoho Desk's historical SLA data on migrated tickets.

## Edge Cases & Known Limitations

No migration is clean out of the box. Plan for these specific failure modes:

**Inline images** are the most common silent failure. Zoho Desk stores inline images as Zoho-hosted URLs embedded in HTML ticket thread bodies. If you decommission your Zoho Desk account after migration, every inline image URL breaks permanently. The fix: download each image during extraction, upload it to Freshdesk (or host it on a CDN/S3 bucket), and rewrite the `src` attribute in the HTML before loading.

**Attachment size limits.** Freshdesk caps attachments at 20 MB per file and 15 attachments per ticket or conversation. If a Zoho Desk ticket contains a file exceeding 20 MB, the Freshdesk API returns a `413 Payload Too Large` error. Your script must catch this and either host the file externally (e.g., an S3 bucket with a secure download link injected into the ticket note) or log it for manual review. If a ticket has more than 15 attachments, split them across multiple notes.

**Suspended or deleted users.** If a contact was deleted or suspended in Zoho Desk but has historical tickets, Freshdesk may reject the ticket creation because it can't resolve the requester. Map these to a generic "Deactivated User" contact in Freshdesk to preserve the ticket data.

**Multi-company contacts.** Zoho Desk supports contacts linked to multiple accounts. Freshdesk links one company per contact. You'll need to pick a primary company or flatten the relationship. Document the mapping decision for audit purposes.

**Duplicate records on re-run.** If you run the migration twice (test + production), you'll create duplicate contacts and companies unless you deduplicate by email. Freshdesk returns HTTP 409 for duplicate contact email addresses — handle these in your script. Freshdesk does not have a bulk-delete API, so cleanup of duplicates is manual and time-consuming.

**Non-migratable objects.** Zoho Desk Blueprints, Products, Activities (Tasks/Calls/Events), SLA history, workflow rules, and satisfaction ratings have no native Freshdesk equivalent. These must be archived separately, manually rebuilt using Freshdesk automations and tagging, or accepted as losses. For archival, Zoho Desk's Data Backup includes these records — store the backup export in durable storage before decommissioning.

**GDPR and data residency.** If you stage extracted data on intermediate servers during the migration (which is common for attachment handling), ensure those servers comply with your data residency and privacy requirements. Use encrypted storage, restrict access, and delete staging data after migration validation completes. Both Zoho and Freshdesk offer region-specific data centers — verify that your Freshdesk instance is in the correct region before loading.

## Validation and Testing

Do not trust a `200 OK` as proof of data integrity. Execute validation at multiple levels:

1. **Record-count reconciliation** — Compare total tickets, contacts, and companies between source and target. A mismatch greater than 0.1% requires investigation.
2. **Field-level spot checks** — Sample 50 random tickets and verify every field (status, priority, custom dropdowns, assignee, tags) matches the source.
3. **Thread completeness** — For sampled tickets, verify that every thread in Zoho Desk has a corresponding note in Freshdesk with correct content and chronological ordering.
4. **Attachment verification** — Open 20 tickets with attachments and confirm files are downloadable without 404 errors. Verify file sizes match the source.
5. **Inline image verification** — Open 10 tickets with inline images and confirm images render correctly in the Freshdesk agent view and customer portal.
6. **Timestamp verification** — Confirm that migrated tickets display their original Zoho Desk creation dates, not the import date. If timestamps show today's date, the migration API key is not working correctly.
7. **Automation smoke test** — Create a new test ticket in Freshdesk post-migration (after re-enabling automations) to verify Dispatch'r, Supervisor, SLA policies, and email notifications fire correctly on new tickets. Migrated tickets will not have accurate SLA history.
8. **Portal visibility check** — Log in as a customer to the Freshdesk portal and verify that public notes on migrated tickets are visible and readable.

For a complete QA protocol, see our [post-migration QA checklist](https://clonepartner.com/blog/blog/help-desk-data-migration-qa-checklist/).

## When to Build In-House vs. Use a Managed Service

**Build in-house when:**
- You have fewer than 10,000 tickets
- No inline images or attachments to preserve
- Standard fields only — no custom objects or complex picklist logic
- You have an engineer with a free week and experience with both APIs
- You can tolerate a test-and-iterate cycle if the first run has issues

**Use a managed service when:**
- Volume exceeds 50,000 tickets
- You need timestamp preservation and full thread fidelity
- Inline images must survive the migration
- You can't afford to re-migrate if something breaks (Freshdesk has no bulk-delete API for rollback)
- You need zero downtime during cutover
- Your team relies on Zoho Desk's CRM integration and needs careful handling of the ecosystem transition
- GDPR or compliance requirements demand auditable data handling during transfer

The hidden cost of DIY isn't the initial build — it's the debugging. Broken relationships, missing threads, expired OAuth tokens, 429 errors at 2 AM during a weekend cutover, automation rules firing on imported tickets, and the discovery that inline images are all broken after you've already redirected email routing. Those recovery hours typically exceed the cost of outsourcing.

If your Zoho Desk to Freshdesk migration involves more than basic ticket metadata, [talk to our engineering team](https://cal.com/clonepartner/meet?duration=30).

## Frequently Asked Questions

### Can I migrate Zoho Desk to Freshdesk without losing data?
Yes, but only if you use the Zoho Desk REST API or Data Backup feature for extraction — not the CSV export, which omits threads and comments. API-based migration preserves full conversation history, attachments (when downloaded and re-uploaded), tags, and custom fields. The data most at risk is inline images embedded in HTML thread bodies — these must be downloaded, re-hosted, and rewritten before the Zoho account is decommissioned.

### How long does a Zoho Desk to Freshdesk migration take?
Typical end-to-end timelines are 10–18 days including discovery, script development, test migration, production load, and validation. The actual data transfer for 50,000 tickets with an average of 10 conversations each takes approximately 23 hours on a Freshdesk Pro plan (400 calls/min). Most elapsed time goes to field mapping decisions, UAT, and stakeholder review — not the data transfer itself.

### What data cannot be migrated from Zoho Desk to Freshdesk?
Zoho Desk Blueprints, Products, Activities (Tasks/Calls/Events), SLA history, workflow rules, and satisfaction ratings have no native Freshdesk equivalent. These must be archived (Zoho's Data Backup includes them), manually recreated using Freshdesk automations and tagging, or accepted as losses.

### Does Freshdesk preserve timestamps during ticket import?
Not with the standard API. The `POST /api/v2/tickets` endpoint ignores `created_at` and `updated_at` fields. You must contact Freshdesk support for a special migration API key that allows setting historical timestamps. There is no additional cost, but approval takes 2–5 business days. Without this key, all imported tickets show the import date.

### Will Freshdesk send emails to customers during import?
Yes — if you use the reply endpoint. Creating a reply via the Freshdesk API triggers an outbound email notification to the customer. Import historical conversations as private or public notes instead of replies. Additionally, disable Dispatch'r, Supervisor, Observer, and all email notification rules in Freshdesk Admin before starting the import. Re-enable them only after validation is complete.

### How do I test the migration if I'm not on Freshdesk Enterprise?
Freshdesk sandbox environments are exclusive to the Enterprise plan. If you're on Pro or Growth, create a separate Freshdesk free trial account for test migrations. Run a subset migration (e.g., 500 tickets) against the trial, validate, then run the full production migration against your real account.

### What happens if the migration fails partway through?
Freshdesk does not offer a bulk-delete API, so rollback is difficult. Mitigate this by: (1) maintaining a complete Zoho ID → Freshdesk ID mapping table, (2) running migrations in batches with clear checkpoints, (3) logging every API call and response, and (4) testing thoroughly on a non-production instance first. If you must clean up a partial load, you'll need to delete records individually via the API or contact Freshdesk support.

> Migrating from Zoho Desk to Freshdesk? Our engineers handle thread preservation, inline image handling, timestamp fidelity, and zero-downtime cutover. Get a free 30-minute migration assessment.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## Frequently asked questions

### Can I migrate Zoho Desk to Freshdesk without losing data?

Yes, but only through API-based extraction or Zoho's Data Backup feature. The standard CSV export omits all ticket threads and comments. Use the REST API to extract tickets, threads, and attachments, then load them into Freshdesk as notes to avoid triggering outbound emails.

### How long does a Zoho Desk to Freshdesk migration take?

Typical end-to-end timelines are 10–18 days including discovery, script development, test migration, production load, and validation. The actual data transfer for 50,000 tickets takes about 1 day on Freshdesk Pro (400 calls/min). Most elapsed time goes to field mapping, UAT, and stakeholder review.

### What data cannot be migrated from Zoho Desk to Freshdesk?

Zoho Desk Blueprints, Products, Activities (Tasks/Calls/Events), SLA history, workflow rules, and satisfaction ratings have no native Freshdesk equivalent. These must be archived or manually recreated using Freshdesk automations and tagging.

### Does Freshdesk preserve timestamps during ticket import?

Not with the standard API. The POST /api/v2/tickets endpoint ignores created_at and updated_at fields. You must contact Freshdesk support for a special migration API key that allows setting historical timestamps.

### Will Freshdesk send emails to customers during import?

Yes, if you use the reply endpoint. Import historical conversations as private or public notes instead of replies to avoid triggering outbound notifications. Disable all email notification rules in Freshdesk Admin before starting.
