Skip to content

Freshdesk to Zendesk Migration Checklist: The Engineer's Guide

A step-by-step Freshdesk to Zendesk migration checklist covering API limits, import order, delta sync, attachment handling, and post-migration QA.

Raaj Raaj · · 14 min read
Freshdesk to Zendesk Migration Checklist: The Engineer's 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,200+ migrations completed
  • Zero downtime guaranteed
  • Transparent, fixed pricing
  • Project success responsibility
  • Post-migration support included

A Freshdesk to Zendesk migration is an API orchestration problem with a strict order of operations. Get the sequence wrong — import tickets before users exist, use the standard ticket endpoint instead of the import endpoint, skip the Freshdesk export ceiling — and you end up with broken requester associations, automations firing on historical data, and silent data loss.

The biggest risk isn't a total failure. It's the quiet kind: dropped inline images, broken ticket threads, or five-year-old closed tickets triggering email notifications to customers.

This checklist covers every phase from pre-migration audit through post-cutover validation, with the exact API endpoints, rate limits, and edge cases that determine whether a migration succeeds or fails quietly. For a deeper dive into field-level mapping and method comparisons, see Freshdesk to Zendesk Migration: API Limits, Mapping & Methods.

Pre-Migration Discovery: Auditing Your Freshdesk Instance

Before writing a single line of migration code, inventory everything that exists in Freshdesk. The goal is a complete manifest — not just ticket counts, but every configuration object that agents depend on daily. Zendesk and Freshdesk handle object relationships differently, and assuming a 1:1 mapping will break your support workflows.

Audit checklist:

  • Ticket volume and age distribution. Total open, pending, resolved, and closed tickets. Identify how far back your history goes and how much of it agents actually reference.
  • Custom fields. Document every custom ticket field, contact field, and company field — including field type (dropdown, checkbox, multi-line text, dependent fields). Freshdesk dependent fields have no 1:1 Zendesk equivalent and require conditional field logic or lookup fields on the Zendesk side.
  • Ticket statuses. Freshdesk supports custom statuses natively. Zendesk uses a fixed status lifecycle (New, Open, Pending, On-hold, Solved, Closed) and handles custom statuses through custom ticket status configuration (available on Suite Enterprise and above). Zendesk caps custom statuses at 300 per account and 100 per category. Map every Freshdesk status to its Zendesk equivalent before migration. (developer.zendesk.com)
  • Groups and agents. List every group, agent, and agent role. Note which agents are deactivated — you'll need placeholder accounts for them on the Zendesk side.
  • Automations, dispatch rules, and scenario automations. These don't migrate via API. Document the exact conditions and actions of every active Freshdesk Dispatch'r and Observer rule for manual rebuild in Zendesk.
  • Macros and canned responses. Export the text and field actions for each.
  • SLA policies and business hours. Freshdesk SLA policies don't map to Zendesk SLA policies structurally. Document target response and resolution times per priority level.
  • Help Center articles. Count categories, folders, and articles. Note any article-level visibility restrictions.
  • Tags. Export the full tag list. Zendesk tags are lowercase and alphanumeric — Freshdesk tags with special characters will need cleanup.
  • Integrations. List every active Freshdesk app and webhook. Identify which have Zendesk equivalents.
Tip

Create a shared spreadsheet with tabs for each object type. For each Freshdesk object, record: the field name, field type, possible values, and the target Zendesk field. This mapping sheet becomes the single source of truth for the entire migration. Freeze the mapping sheet before your first full test.

Warning

Never import historical tickets without first disabling Zendesk triggers. Even with the correct API endpoint, active triggers can send thousands of unintended email notifications to customers.

For a full walkthrough of Freshdesk export options, see How to Export Data from Freshdesk: Methods, API Limits & Mapping.

The Freshdesk Export Challenge: API Limits and Account Export

Freshdesk's API has a hard pagination ceiling that catches most teams off guard. The List All Tickets API is capped at 300 pages. With a maximum of 100 tickets per page, the absolute ceiling is 30,000 tickets via pagination. Accounts with more than 30,000 tickets cannot extract their full history through this endpoint alone. (developers.freshdesk.com)

There are several other extraction gotchas worth knowing up front. The default GET /api/v2/tickets endpoint only returns tickets created in the last 30 days unless you use the updated_since parameter. The Search/Filter Tickets API is even more restrictive — limited to 10 pages of 30 results each, capping at 300 tickets per query. And if you rely on include=conversations from the ticket list endpoint, Freshdesk only returns up to ten conversations per ticket; deeper threads require the dedicated conversations endpoint (GET /api/v2/tickets/{id}/conversations). (developers.freshdesk.com)

Freshdesk API rate limits by plan (per minute):

Plan Calls/min Tickets List limit Ticket Create limit
Growth 200 20 80
Pro 400 100 160
Enterprise 700 200 280
Trial 50

These are account-wide limits — every app, webhook, and integration shares the same pool. When you hit the limit, Freshdesk returns HTTP 429 with a Retry-After header. Your extractor needs checkpoints and backoff, not a blind multithreaded loop. (support.freshdesk.com)

How to get all tickets out of Freshdesk

For accounts exceeding 30,000 tickets, use the Account Data Export: navigate to Admin → Account → Account Details → Export Data. This generates a ZIP archive containing XML files for tickets, users, groups, companies, and solutions. The export is emailed to the account administrator.

Warning

Freshdesk's CSV ticket export does not include full conversation histories or archived tickets. Only the Account Data Export (XML) provides complete historical records including all replies, notes, and conversation threads. (support.freshdesk.com)

Recommended export strategy for high-volume accounts:

  1. Trigger the Account Data Export (XML) first. This captures the bulk of historical data.
  2. Parse the XML into a structured format (JSON) that your import scripts can consume.
  3. Use the List Tickets API with updated_since as a delta sync to capture any tickets created or updated after the export timestamp.
  4. For each ticket, fetch conversations separately via GET /api/v2/tickets/{id}/conversations to ensure all reply and note threads are captured with their attachments.

The Exact Zendesk Import Order: Admin Objects First, Then Tickets

Zendesk's Ticket Import API enforces strict referential integrity. Every ticket references a requester (user), an assignee (agent), a group, and optionally an organization — all by their Zendesk IDs. If any referenced record doesn't exist at import time, the API rejects the ticket.

The required import sequence:

  1. Custom fields and ticket forms — Create all custom ticket fields, user fields, and organization fields in Zendesk Admin Center. Create ticket forms if using multiple forms. Record the Zendesk field IDs for your import mapping.
  2. Groups — Create Zendesk groups to match Freshdesk groups.
  3. Organizations — Create all companies/organizations. Map each Freshdesk company ID to its new Zendesk organization ID.
  4. Users (end-users and agents) — Create all contacts and agents. Every user who has ever been a requester, CC, or comment author on any ticket must exist as an active user in Zendesk before ticket import begins. Zendesk's user create API accepts up to 100 users per batch request.
  5. Tickets — Import tickets last, referencing the Zendesk IDs created in steps 1–4.
  6. Help Center content — Articles, categories, and sections can be imported in parallel with tickets via the Help Center API (separate rate limit pool).
Tip

Store a mapping table in your migration database linking Freshdesk_Contact_ID to Zendesk_User_ID and Freshdesk_Ticket_ID to Zendesk_Ticket_ID. This identity map is your recovery index for QA, rollback, and post-migration support escalations. Store the original Freshdesk ticket ID in a dedicated Zendesk custom field or tag — agents rarely need it day to day, but audits and debugging absolutely do.

Danger

Zendesk's bulk CSV import handles users and organizations only (up to 2,000 rows per file). It does not support ticket import. All tickets must go through the API. If you use Zendesk's Data importer for identities, data imports are not enabled by default and organizations must be imported before users. (support.zendesk.com)

Handling deactivated agents and former employees:

The Zendesk Ticket Import API requires that the requester is an active, non-suspended user. If you have tickets from ex-employees or deactivated contacts, you have two options: temporarily activate a placeholder account for import, or map all such tickets to a generic "Former Employee" user. Plan for this before you start importing.

Using the Zendesk Ticket Import API Correctly

Zendesk exposes two ticket creation endpoints. Use the right one:

  • POST /api/v2/tickets — The standard endpoint. Creates tickets with current timestamps and fires all triggers, automations, and SLA policies. Never use this for migration.
  • POST /api/v2/imports/tickets (single) or POST /api/v2/imports/tickets/create_many (bulk) — The import endpoint. Preserves historical timestamps, bypasses business rules, and supports archived ticket creation. (developer.zendesk.com)

What the Import API gives you:

  • Set created_at, updated_at, and solved_at to their original Freshdesk values
  • Include multiple comments per ticket, each with its own created_at timestamp and author_id
  • Mark comments as private with public: false
  • Use archive_immediately: true for closed tickets to send them directly to the archive without going through the normal ticket lifecycle — Zendesk specifically recommends this for very large imports (750,000+ tickets) to reduce impact on active ticket performance
  • Batch up to 100 tickets per request with the create_many variant
  • The endpoint returns a job_status object — poll GET /api/v2/job_statuses/{id} to check completion
Danger

Zendesk explicitly states that imported tickets do not carry supported historical metrics or SLA history. Tag imported tickets and exclude them from historical SLA reporting. Validate SLA behavior only on brand-new post-cutover tickets. (developer.zendesk.com)

Zendesk API rate limits (per minute):

Plan Requests/min
Team 200
Growth 400
Professional 400
Enterprise 700
Enterprise Plus 2,500

The High Volume API add-on can increase limits to 2,500 requests/min on Growth plans and above (minimum 10 agent seats required). Zendesk also caps queued or running background jobs at 30, so aggressive parallelism can hit TooManyJobs before it hits raw request-per-minute limits. In practice, the bottlenecks are usually the 100-ticket batch ceiling, upload calls for attachments, and the 30-job queue limit — not the headline RPM number alone. (developer.zendesk.com)

import requests
import time
 
ZENDESK_SUBDOMAIN = "yourcompany"
EMAIL = "admin@yourcompany.com"
TOKEN = "your_api_token"
AUTH = (f"{EMAIL}/token", TOKEN)
 
def import_ticket_batch(tickets):
    """Import up to 100 tickets per batch."""
    url = f"https://{ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/imports/tickets/create_many"
    payload = {"tickets": tickets}
    response = requests.post(url, json=payload, auth=AUTH)
    
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", 60))
        time.sleep(retry_after)
        return import_ticket_batch(tickets)  # retry
    
    response.raise_for_status()
    return response.json()["job_status"]

Attachment handling

Attachments require a two-step process:

  1. Upload the file to Zendesk via POST /api/v2/uploads with the binary file content. The response returns an upload token.
  2. Reference the token in the ticket comment's uploads array when creating the ticket.

Inline images (screenshots pasted into ticket bodies) are trickier. They are embedded in the HTML body as <img> tags. You must download each image from Freshdesk, upload it to Zendesk, get the new URL, and rewrite the HTML src attributes before import. Without this rewrite, inline images degrade into downloadable files or broken references. Freshdesk caps total attachment size at 20 MB per ticket; Zendesk allows up to 50 MB per file. (developers.freshdesk.com)

Warning

The Zendesk Ticket Import API rejects comments with empty bodies, even though the Zendesk UI allows them (e.g., when someone emails an attachment with no text). Add placeholder text like "(attachment only)" for these cases.

Side conversations

The Zendesk Ticket Import API does not support importing side conversations. Zendesk has a separate Side Conversations API (POST /api/v2/tickets/{ticket_id}/side_conversations) for creating them on live tickets, with a rate limit of 300 create/reply requests per 10 minutes — but these carry current timestamps, not historical ones. (developer.zendesk.com)

Your options:

  • Convert Freshdesk side conversations (or forwarded conversations) into internal notes on the parent ticket, preserving the content as historical context.
  • Create side conversations as a post-import step using the Side Conversations API — accepting that timestamps will not be historical.
  • Accept the data loss and document it. In practice, most teams choose to flatten side conversations into internal notes.

Golden-Sample Test: Validating Before Full Import

Never run a full migration without a validated test run first. A golden-sample test imports a small, representative subset and verifies every data point.

How to build your golden sample:

  1. Select 50–100 tickets that cover your edge cases: tickets with attachments, inline images, multiple CCs, custom field values across every field type, tickets in every status, tickets from deactivated agents, and your oldest archived tickets.
  2. Import the sample into a Zendesk sandbox (available on Enterprise plans) or a trial instance.
  3. Verify each ticket manually:
    • Does created_at match the Freshdesk original?
    • Are all conversation replies and internal notes present, in order, and attributed to the correct author?
    • Do inline images render correctly?
    • Are attachments downloadable?
    • Are custom field values populated correctly?
    • Is the ticket assigned to the right group and agent?
    • Does the requester link to the correct organization?
Tip

Build an automated validation script that compares source (Freshdesk) and target (Zendesk) tickets by original ID. Check comment count, attachment count, custom field values, and timestamps programmatically. Manual spot-checks catch what scripts miss — run both.

If your golden sample passes, run a larger batch (1,000–5,000 tickets) before committing to the full import. Use the same golden sample before and after every rerun to catch regressions.

Delta Sync and Cutover: Achieving Zero Downtime

A production migration takes hours to days depending on volume. Agents can't stop working during that window. The solution is a delta sync — a final incremental import of everything that changed while the bulk migration was running.

Cutover sequence:

  1. Announce a maintenance window to your support team. Even with zero downtime, agents need to know which system is authoritative.
  2. Complete the bulk import of all historical tickets during off-peak hours (weekends or overnight).
  3. Record the cutover timestamp — the exact moment your bulk import data was frozen.
  4. Run the delta sync. Query Freshdesk for all tickets with updated_since set to your cutover timestamp. Import these into Zendesk using the same import pipeline.
  5. Switch email routing. Update your support email DNS (MX records or forwarding rules) to point to your Zendesk instance. This is the point of no return for incoming tickets.
  6. Disable Freshdesk automations to prevent any automated responses from firing on the old system.
  7. Run one final delta pass to catch any stragglers created during the routing switch.
  8. Enable live Zendesk automations on new traffic and run smoke tests: inbound email, outbound reply, internal note, attachment upload, assignment, SLA clock start, and webhook firing.
Tip

Cut over email routing only after the final delta has loaded and the golden sample passes. Because imported tickets do not fire business rules, your smoke tests must use brand-new tickets created after routing flips to Zendesk. (developer.zendesk.com)

Sample timelines by ticket volume

Total tickets Estimated bulk import time Delta sync window Total migration window
< 10,000 2–4 hours 30 min 1 day
10,000–50,000 6–12 hours 1–2 hours 1–2 days
50,000–200,000 1–3 days 2–4 hours 2–4 days
200,000–500,000 3–7 days 4–8 hours 5–10 days
500,000+ 1–2 weeks 8–12 hours 2–3 weeks

These estimates assume Enterprise-tier rate limits on both platforms (700 req/min) and include attachment transfer time. Actual duration varies based on average attachments per ticket, comment depth, and API throttling behavior during peak hours.

For a detailed breakdown of zero-downtime strategies, see Zero-Downtime Helpdesk Migration: How to Keep Support Running During the Move.

Post-Migration Validation and QA

A successful ticket count match is not a successful migration. Post-migration QA must verify data integrity at the field level — and it breaks down into two distinct jobs: historical fidelity and live workflow validation. Treat them separately.

Historical fidelity checks

  • Total ticket count matches (open + closed + archived)
  • Random sample of 50 tickets: all comments present and in correct chronological order
  • Timestamps preserved (created_at, updated_at, solved_at)
  • Custom field values correctly mapped and populated
  • Tags transferred and lowercase-normalized
  • Requester, assignee, and group associations correct
  • Organization membership preserved
  • File attachments downloadable on 10+ sample tickets across age ranges
  • Inline images render in ticket comment HTML
  • No broken image references in ticket bodies
  • Agent count matches expected total
  • End-user count matches (within tolerance for deduplication)
  • Organization custom fields populated
  • User identities (email, phone) correctly associated
  • Agents can search by old Freshdesk ticket ID (if stored as a custom field)

Live workflow checks

  • Create new test tickets and verify triggers, automations, views, and macros fire correctly
  • Validate SLA policies only on new tickets — imported tickets do not carry supported SLA history (developer.zendesk.com)
  • Auto-replies and notification templates render properly
  • Assignment automations route to correct groups
  • Reconnect downstream integrations one by one: CRM sync, telephony, chat, CSAT, data warehouse exports, and webhook consumers
  • Default and custom views return expected ticket sets
  • Explore reports return data for imported tickets
  • CSAT surveys trigger correctly on newly solved tickets
  • Review dashboards with stakeholders and rebuild any report that depended on Freshdesk-only logic or fields

For a comprehensive QA protocol, see Post-Migration QA: 20 Tests to Run After Your Helpdesk Migration.

Rollback and Contingency Planning

No migration should go live without a documented rollback plan. A helpdesk migration rollback is usually a channel-routing rollback, not a delete-everything rollback. Keep that distinction clear.

  • Keep Freshdesk active for at least 30 days post-cutover. Don't cancel your subscription immediately.
  • Maintain a ticket ID mapping table — a file linking every Freshdesk ticket ID to its new Zendesk ticket ID. This is your recovery index.
  • Export a full backup from Zendesk before going live, so you can distinguish imported data from new production data if a rollback is needed.
  • DNS rollback plan. Know exactly how to revert your MX records or email forwarding to point back to Freshdesk. Test this in advance — DNS propagation can take up to 48 hours.
  • Define your rollback trigger. What failure threshold triggers a rollback? Examples: more than 5% of tickets missing comments, any attachment corruption, or SLA miscalculation on live tickets.
  • Keep source-to-target ID maps, job logs, and batch manifests so you can reload only the failed segment rather than re-running the entire migration.
Info

Zendesk does not support bulk ticket deletion via the UI. If you need to roll back and re-import, you'll need the API (DELETE /api/v2/tickets/destroy_many) or Zendesk Support assistance to purge imported data. Prefer re-importing a controlled batch over hand-editing hundreds of tickets.

When to Bring in a Migration Partner

DIY migrations work for small accounts with straightforward configurations — under 10,000 tickets, few custom fields, no attachments to preserve, and an engineer with a week to spare.

The math changes when you're dealing with:

  • High volume (50,000+ tickets) where rate limits turn a weekend project into a multi-week grind
  • Complex attachment trees with inline images that need URL rewriting across hundreds of thousands of comments
  • Strict compliance requirements (HIPAA, SOC 2) where data handling must be auditable
  • Zero tolerance for downtime — agents need to keep working without interruption
  • Side conversation preservation requiring custom flattening logic

At ClonePartner, we've run 1,200+ data migrations including hundreds of Freshdesk-to-Zendesk moves. We handle the Freshdesk export ceiling, the Zendesk import ordering, the 429 retry logic, the attachment rewrites, and the delta sync — so your team doesn't burn engineering cycles on a one-time operation that has to be perfect the first time.

Frequently Asked Questions

How do I export more than 30,000 tickets from Freshdesk?
Freshdesk's List Tickets API is hard-capped at 300 pages (max 100 per page = 30,000 tickets). For full historical exports, use the Account Data Export under Admin → Account → Account Details → Export Data. This generates a complete XML archive emailed to the admin. Freshdesk's UI CSV export does not include full conversations or archived tickets.
What order should I import data from Freshdesk into Zendesk?
Import in this order: custom fields and ticket forms first, then groups, organizations, users (end-users and agents), and tickets last. Zendesk's Ticket Import API rejects tickets if the referenced requester, assignee, group, or organization doesn't already exist.
What is the difference between Zendesk's ticket create and ticket import API?
The standard POST /api/v2/tickets endpoint sets current timestamps and fires all triggers and automations. The import endpoint (POST /api/v2/imports/tickets) preserves historical created_at, updated_at, and solved_at values and bypasses all business rules — making it the only correct choice for migration.
Can I migrate side conversations from Freshdesk to Zendesk?
Not through the Ticket Import API — it doesn't support side conversations. Your best option is to flatten side conversations into internal notes on the parent ticket during import, preserving the content as historical context. Zendesk's separate Side Conversations API can create them post-import, but timestamps will not be historical.
Will my Zendesk SLA reports be accurate after import?
Not for historical tickets. Zendesk states that imported tickets do not support historical metrics and SLAs. Tag imported tickets and exclude them from historical SLA reporting. Validate SLA behavior on brand-new tickets created after cutover.

More from our Blog

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

Post-Migration QA: 20 Tests to Run After Your Helpdesk Migration

Ensure your helpdesk 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
Zero-Downtime Helpdesk Migration: How to Keep Support Running During the Move
Help Desk

Zero-Downtime Helpdesk Migration: How to Keep Support Running During the Move

This guide details the 3-stage technical process for a zero-downtime helpdesk migration. Learn how to use an initial bulk data transfer, a continuous delta migration (Change Data Capture), and a seamless final cutover to move platforms without any service interruption. Discover how an engineer-led approach can guarantee a 100% accurate, 50x faster migration.

Raaj Raaj · · 6 min read