---
title: "How to Migrate from Freshdesk to Dixa: The Complete Technical Guide"
slug: how-to-migrate-from-freshdesk-to-dixa-the-complete-technical-guide
date: 2026-07-13
author: Raaj
categories: [Migration Guide, Freshdesk, Dixa]
excerpt: "Step-by-step guide to migrating from Freshdesk to Dixa. Covers API rate limits, object mapping, ticket-to-conversation transformation, and validation."
tldr: "Migrating Freshdesk to Dixa requires transforming tickets into conversations, managing two different API rate-limit models, and rebuilding automations manually. Most mid-market migrations complete in 1–3 weeks."
canonical: https://clonepartner.com/blog/how-to-migrate-from-freshdesk-to-dixa-the-complete-technical-guide/
---

# How to Migrate from Freshdesk to Dixa: The Complete Technical Guide


> [!NOTE]
> **TL;DR — Freshdesk to Dixa Migration**
>
> Migrating from Freshdesk to Dixa is a high-complexity project because the two platforms use fundamentally different data models: Freshdesk is ticket-centric, Dixa is conversation-centric. A typical migration for 50,000–200,000 tickets takes 1–3 weeks including mapping, testing, and cutover. The biggest risks are losing threaded message history due to the structural mismatch, and the fact that Dixa's historical import endpoint only supports `email` and `genericapimessaging` channel types — phone and social history require normalization or sandbox testing. Freshdesk automations, macros, SLA policies, and canned responses cannot be migrated and must be rebuilt manually. The Dixa API requires the Ultimate or Prime plan; the Growth plan does not include API access. Teams with fewer than 10,000 tickets and no custom fields can attempt a scripted DIY migration (80–120 engineer-hours). For anything larger or with complex relationships, a managed service ($5,000–$15,000 for 50K–200K tickets) or custom ETL pipeline is the safer path.
>
> *Written June 2025. Targets Freshdesk API v2 and Dixa API v1.*

## What Is a Freshdesk to Dixa Migration?

A Freshdesk to Dixa migration is the process of extracting tickets, contacts, conversations, agents, groups, tags, custom fields, and attachments from Freshdesk and loading them into Dixa's conversation-based data model. The goal is to preserve full customer interaction history so agents in Dixa can see every previous exchange without gaps.

### Why Teams Move from Freshdesk to Dixa

Teams typically migrate from Freshdesk to Dixa for three reasons:

1. **Omnichannel routing architecture.** Dixa routes phone, email, chat, and social conversations through a single intelligent routing engine rather than treating each channel as a separate queue. For mid-market support teams handling 8,000+ conversations per month, this eliminates channel silos.
2. **Agent experience.** Dixa's single-screen workspace surfaces customer context, order data (via Shopify/Magento integrations), and conversation history without tab-switching.
3. **Built-in telephony.** Freshdesk requires Freshcaller as a separate add-on. Dixa includes browser-based VoIP as a first-class channel on all plans.

For context, Zendesk-to-Dixa migrations are somewhat simpler because Zendesk's ticket model more closely parallels Dixa's conversation model and Zendesk has more mature bulk export tooling. Intercom-to-Dixa migrations are harder because Intercom's data model splits conversations across multiple object types (conversations, contacts, events, custom objects) with no single export mechanism covering all relationship types.

### Architectural Differences That Make This Migration Non-Trivial

Two core differences create the friction:

- **Tickets vs. Conversations.** Freshdesk's atomic unit is the **Ticket** — a numbered record with a status, priority, and child **Conversations** (replies and notes). Dixa's atomic unit is the **Conversation** — an omnichannel thread that contains **Messages** and **Internal Notes** directly. There is no "ticket number" in Dixa; conversations are identified by UUID. You cannot map a ticket 1:1 to a Dixa conversation without rebuilding the chronological thread.
- **Groups vs. Queues + Teams.** Freshdesk uses **Groups** for agent routing. Dixa separates this into **Queues** (routing containers with SLA and offering algorithms) and **Teams** (organizational groupings of agents). A single Freshdesk Group often needs to map to both a Queue and a Team in Dixa.

## Freshdesk to Dixa Object Mapping

Before writing a single line of code, finalize your data map. Below is the mapping required to move data from Freshdesk to Dixa.

| Freshdesk Object | Dixa Object | Notes / Caveats |
|---|---|---|
| Ticket | Conversation | One-to-one, but Dixa conversations have no numeric ticket ID. Status values differ (Freshdesk uses integers 2–5; Dixa uses open/closed/followup). Store legacy ticket ID in `externalId` or a custom attribute. |
| Conversation (reply/note) | Message / Internal Note | Public replies → Dixa Messages. Private notes → Dixa Internal Notes via separate `POST /v1/conversations/{id}/notes` call. Preserve chronological order. |
| Contact | End User | Freshdesk contacts have `company_id`; Dixa End Users have no native company field — use custom attributes. |
| Company | *(No direct equivalent)* | Must be stored as a custom attribute on End Users or handled via an external CRM integration. |
| Agent | Agent | Map by email, not numeric ID. Dixa has 3 built-in roles (Administrator, Agent, Team Lead/Supervisor) — no custom roles. Must be provisioned before importing conversations. |
| Group | Queue + Team | Requires splitting: create a Queue for routing and a Team for organizational grouping. |
| Tag | Tag | Create via `POST /v1/tags` before importing conversations. Apply to conversations via `POST /v1/conversations/{id}/tags/{tagId}`. |
| Custom Field | Custom Attribute | Freshdesk supports dropdown, checkbox, date, number, text, and nested fields. Dixa custom attributes are simpler — verify type compatibility before migration. |
| Attachment | Attachment (URL-based) | Dixa's import endpoint accepts attachments as `{"url": "...", "prettyName": "..."}`. Source URLs must be accessible at import time. If Freshdesk URLs require auth or expire, re-host to S3/GCS first. |
| Satisfaction Rating | Conversation Rating | Freshdesk uses satisfied/unsatisfied. Dixa supports CSAT (1–5), NPS, and ThumbsUpOrDown. Requires normalization. |
| Knowledge Base Article | Knowledge Article | Dixa has a Knowledge API on the Prime plan. Content must be re-imported or recreated. |
| Automation / Trigger | *(Cannot be migrated)* | Must be rebuilt in Dixa's flow builder. |
| Canned Response | *(Cannot be migrated)* | Must be recreated as Dixa Templates. |
| SLA Policy | *(Cannot be migrated)* | Dixa SLAs are configured per-queue. Rebuild from scratch. |

### Field-Level Transforms That Matter Most

- **Status mapping.** Freshdesk ticket `status` is numeric (2=Open, 3=Pending, 4=Resolved, 5=Closed) and often customized with additional values beyond 5. Dixa conversations use state values like `Open`, `Pending`, `AwaitingPending`, and `Closed`. Build an explicit lookup table that includes any custom status values your Freshdesk instance has added. ([developers.freshdesk.com](https://developers.freshdesk.com/api/))
- **Custom fields.** Freshdesk `custom_fields` can include nested/dependent dropdown fields and date inputs using `YYYY-MM-DD`. Dixa custom attributes support `Text` and `Select` types. Flatten nested dropdowns into separate attributes or concatenate values before loading. Standardize all date fields to ISO 8601. ([developers.freshdesk.com](https://developers.freshdesk.com/api/))
- **Company relationships.** Freshdesk contacts can belong to a primary company and additional companies. Dixa has no built-in company object, so these relationships must be stored as custom attributes on End Users. If company relationships matter for routing or reporting, validate the destination model in a sandbox before committing to a build.

### What Has No Clean Equivalent in Dixa

- **Freshdesk Companies** — You lose the hierarchical contact-to-company relationship.
- **Multi-product support** — Freshdesk supports multiple products with separate email inboxes. Dixa handles this through separate Queues and contact endpoints, which requires restructuring. Map Freshdesk `product_id` to the correct Dixa Queue.
- **Forums and Community** — No equivalent in Dixa.
- **Time tracking entries** — No equivalent in Dixa.
- **Ticket views and dashboards** — Must be rebuilt in Dixa's analytics.
- **Parent-child ticket relationships** — Freshdesk's `associated_tickets_list` has no direct equivalent. Dixa supports linking conversations via `PUT /v1/conversations/{id}/link`, but the relationship semantics differ.

## Migration Approaches: Native vs. DIY vs. Third-Party vs. Managed

| Approach | How It Works | Best For | Key Risk | Estimated Cost | Complexity |
|---|---|---|---|---|---|
| **CSV Export + Manual Re-entry** | Export tickets from Freshdesk as CSV; manually reformat and import into Dixa | < 500 tickets, no attachments | Loses threaded history, attachments, timestamps, and archived tickets | Staff time only | Low |
| **Freshdesk Account Export + Custom ETL** | Use Freshdesk's admin account export for a high-fidelity baseline; transform JSON; load via Dixa import endpoint | History-preserving one-time migration | Mapping work is non-trivial; account export is admin-only | 80–120 engineer-hours | Medium-High |
| **Freshdesk REST API → Custom Script → Dixa API** | Python/Node.js ETL that reads from Freshdesk API, transforms to Dixa schema, writes via import endpoint | 1K–200K tickets, engineering team available | Requires 2–4 weeks of engineering time; retry logic is non-trivial | 80–160 engineer-hours | High |
| **Third-party migration tool** | Self-serve tool that maps and moves records between platforms | Simple migrations, standard fields only | Limited custom field support; see tool notes below | $1,000–$5,000 depending on volume | Medium |
| **Managed migration service** | Dedicated engineers handle extraction, transformation, loading, validation, and cutover | 50K+ tickets, custom fields, zero-downtime requirement | Cost, but eliminates engineering distraction | $5,000–$15,000 for 50K–200K tickets | Low (for you) |

### Third-Party Tool Landscape (as of June 2025)

As of June 2025, **Help Desk Migration** and **Import2** both offer Freshdesk source connectors, but neither has a verified, production-tested Dixa destination connector. If you evaluate a third-party tool, confirm these specifics before purchasing: (1) whether it supports Dixa's `POST /v1/conversations/import` endpoint or uses a different integration method, (2) whether it preserves threaded message chronology and internal notes, (3) whether it handles attachment re-hosting, and (4) whether it supports custom field mapping beyond standard text fields. Request a test migration on a sample of 100 tickets before committing.

### When to Pick What

- **Small business, < 10K tickets, no custom fields:** Account export, third-party tool, or a simple script.
- **Mid-market, 10K–100K tickets, some custom fields:** Custom script if you have a backend engineer with 2+ weeks of dedicated bandwidth. Managed service if you don't.
- **Enterprise, 100K+ tickets, multi-brand, attachments:** Managed service. The API rate-limit math alone makes DIY a multi-week engineering project.

## Extraction: Freshdesk API Limits and Pagination

[For engineering] Freshdesk's REST API v2 (`https://<domain>.freshdesk.com/api/v2/`) uses Basic Auth with the API key as the username. Rate limits are enforced per account, not per API key or IP address — all integrations, apps, and scripts sharing the account draw from the same pool. Pause other Freshdesk integrations during extraction to maximize throughput.

| Plan | Rate Limit |
|---|---|
| Free | 100 req/min |
| Growth | 200 req/min |
| Pro | 400 req/min |
| Enterprise | 700 req/min |
| Trial | 50 req/min |

([developers.freshdesk.com — Rate Limits](https://developers.freshdesk.com/api/#ratelimit))

Pagination defaults to 30 records per page. You can set `per_page` up to 100 for list endpoints like `GET /api/v2/tickets`. The Filter/Search Tickets endpoint (`GET /api/v2/search/tickets`) ignores `per_page` entirely — it always returns 30 results per page with a hard ceiling of 10 pages (300 results per query). For bulk extraction, use the List All Tickets endpoint with `updated_since` and paginate via the `Link` response header. To extract more than 300 results from a filtered query, segment by date range.

> [!WARNING]
> **Critical Freshdesk extraction gotcha**
>
> `GET /api/v2/tickets/{id}?include=conversations` returns only up to **10 conversations per ticket**. For full threads, always use the dedicated endpoint: `GET /api/v2/tickets/{id}/conversations`. Avoid deep pagination past page 500. Invalid requests still count toward the account-wide rate limit — honor `Retry-After` headers on 429 responses. ([developers.freshdesk.com](https://developers.freshdesk.com/api/))

Conversations (replies and notes) must be fetched per-ticket via `GET /api/v2/tickets/{id}/conversations`, which means one API call per ticket. For 100,000 tickets on an Enterprise plan (700 req/min), extracting conversations alone takes approximately 143 minutes (100,000 ÷ 700) — before accounting for retries on 429 errors.

Freshdesk also offers an **admin account export** (`/api/v2/account/export`) that can include tickets with notes and attachments, archived tickets, contacts, companies, and groups. This is a strong option for an initial baseline extract, supplemented by REST endpoints for delta syncs and validation. Note: the account export is only available to users with administrator-level access. ([developers.freshdesk.com](https://developers.freshdesk.com/api/))

For a deeper breakdown of Freshdesk extraction methods, see our guide on [how to export data from Freshdesk](https://clonepartner.com/blog/blog/how-to-export-data-from-freshdesk-methods-api-limits-mapping/).

## Loading: Dixa API Constraints and Rate Limits

[For engineering] Dixa's API uses bearer token authentication and follows REST conventions. The import endpoint for historical conversations is `POST /v1/conversations/import`. ([docs.dixa.io](https://docs.dixa.io/openapi/dixa-api/v1/conversations))

**Dixa API rate limits per token:**

| Parameter | Limit | Source |
|---|---|---|
| Rate | 10 requests per second | Dixa API response headers (`X-RateLimit-Limit`); not published on a standalone documentation page as of June 2025 |
| Burst | 4 requests | Observed from `X-RateLimit-Burst` response header |
| Daily quota | 864,000 requests per day (derived: 10 req/sec × 86,400 sec) | Confirmed via Dixa support; not published in public docs |

The daily quota of 864,000 is derived from the per-second limit (10 × 86,400 = 864,000). Dixa does not publish a standalone rate limit documentation page — these values are available in API response headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`) and confirmed via Dixa support. If you need authoritative rate limit figures, contact Dixa support or inspect response headers from your own API calls.

At 10 requests per second, you can theoretically create 36,000 conversations per hour — but each conversation with messages and attachments may require multiple API calls (create end user, import conversation, add internal notes, add tags, set custom attributes). Realistically, expect **4,000–8,000 fully loaded conversations per hour** depending on message count and attachment handling.

> [!WARNING]
> **Dixa API access requires the Ultimate or Prime plan.** The Growth plan ($89/agent/month) does not include API access. The Ultimate plan starts at $139/agent/month (annual billing) and the Prime plan at $179/agent/month. All Dixa plans require a 7-seat minimum ($973/month minimum on Ultimate). If your Dixa instance is on the Growth plan, you cannot use the API for migration — you will need to upgrade before beginning any API-based work. ([dixa.com/pricing](https://www.dixa.com/pricing))

### Throughput Math and Design Constraints

If you are on Freshdesk Pro (400 req/min), your theoretical maximum extraction is 40,000 ticket records per minute (400 requests × 100 tickets per page). But to get conversation threads, you must make a secondary call to `GET /api/v2/tickets/{id}/conversations` for every single ticket. This drops your effective throughput to roughly 300–400 complete tickets per minute.

On the Dixa side, the 10 req/sec limit caps you at 600 raw requests per minute. Since each fully loaded conversation requires multiple calls (import + notes + tags + custom attributes), effective throughput is closer to 100–150 complete conversations per minute. You must architect your ETL pipeline with asynchronous queues or a worker pool to balance these disparate rate limits, using a local staging layer (PostgreSQL, SQLite, or JSON files on disk) to decouple extraction from loading.

**Channel types for historical import.** The documented `genericChannelName` values for the import endpoint are `email` and `genericapimessaging`. Phone, social, and messaging history from Freshdesk cannot be imported as native phone or social conversations in Dixa — they must be normalized to one of these two types. Test non-email channel imports in a Dixa sandbox before committing to a timeline. ([docs.dixa.io](https://docs.dixa.io/openapi/dixa-api/v1/conversations))

**Attachment handling.** Attachments are passed as URL references — Dixa downloads them during import, so the source URLs must be accessible at import time. If Freshdesk attachment URLs require authentication or expire (which they do for some account configurations), download attachments to temporary public storage (S3 with presigned URLs, or GCS) first. Budget 1–3 hours of additional engineering time for the attachment re-hosting pipeline.

The conversation import endpoint supports inbound and outbound messages. For outbound messages, you must specify an `agentId`. Internal notes require a separate call per note via `POST /v1/conversations/{id}/notes` after the conversation is created.

For Dixa's export capabilities and data model details, see our guide on [how to export data from Dixa](https://clonepartner.com/blog/blog/how-to-export-data-from-dixa-methods-api-limits-data-mapping/).

## Step-by-Step Migration Process

The correct order of operations prevents broken relationships and orphaned records. Load dependency objects first, then reference them. Review our overarching [help desk data migration checklist](https://clonepartner.com/blog/blog/help-desk-data-migration-checklist/) for broader project management steps.

### Step 1: Extract and Cache Freshdesk Data

Pull all records from Freshdesk and store locally (JSON files or a staging database). Use the admin account export for a high-fidelity baseline, then REST endpoints for any records created during the migration window.

```python
import requests, time

API_KEY = "your_freshdesk_api_key"
DOMAIN = "yourcompany.freshdesk.com"

def get_tickets(page=1):
    resp = requests.get(
        f"https://{DOMAIN}/api/v2/tickets?per_page=100&page={page}&include=description",
        auth=(API_KEY, "X")
    )
    if resp.status_code == 429:
        wait = int(resp.headers.get("Retry-After", 60))
        time.sleep(wait)
        return get_tickets(page)
    return resp.json()

def get_conversations(ticket_id):
    resp = requests.get(
        f"https://{DOMAIN}/api/v2/tickets/{ticket_id}/conversations?per_page=100",
        auth=(API_KEY, "X")
    )
    if resp.status_code == 429:
        time.sleep(int(resp.headers.get("Retry-After", 60)))
        return get_conversations(ticket_id)
    return resp.json()
```

### Step 2: Create End Users in Dixa

Map Freshdesk Contacts to Dixa End Users. Use the bulk endpoint (`POST /v1/endusers/bulk`) where possible. Use Freshdesk's `contact_id` as the Dixa `externalId` for idempotency — this makes reruns and deduplication safe.

```python
def create_end_user(contact):
    payload = {
        "email": contact["email"],
        "displayName": contact["name"],
        "phoneNumber": contact.get("phone"),
        "externalId": str(contact["id"])
    }
    resp = requests.post(
        "https://dev.dixa.io/v1/endusers",
        json=payload,
        headers={"Authorization": f"Bearer {DIXA_TOKEN}"}
    )
    if resp.status_code == 409:
        # End user with this email already exists — retrieve existing ID
        existing = requests.get(
            f"https://dev.dixa.io/v1/endusers?email={contact['email']}",
            headers={"Authorization": f"Bearer {DIXA_TOKEN}"}
        )
        return existing.json()["data"][0]["id"]
    return resp.json()["data"]["id"]  # UUID
```

Store a mapping table of Freshdesk `contact_id` → Dixa `end_user_id`. This mapping is critical for linking conversations to the correct requester.

Dixa deduplicates end users by email — a `POST /v1/endusers` call with an existing email returns a 409 Conflict. Always handle this response gracefully, as shown above.

### Step 3: Create Agents, Teams, and Queues

Agents must exist in Dixa before you can assign them as message authors. Create agents manually or via `POST /v1/agents/bulk`, matching by email address. Then create Teams (`POST /v1/teams`) and Queues (`POST /v1/queues`) to mirror your Freshdesk Group structure — remembering that a single Freshdesk Group often maps to both a Queue and a Team.

### Step 4: Create Tags and Custom Attributes

Create all tags via `POST /v1/tags` and all custom attribute definitions before importing conversations. Store a mapping of Freshdesk tag names → Dixa tag UUIDs and Freshdesk custom field keys → Dixa custom attribute IDs.

### Step 5: Import Conversations

Transform each Freshdesk ticket into a Dixa conversation import payload. Public replies become messages; private notes are handled separately in Step 6.

```python
def import_conversation(ticket, conversations, requester_id, agent_map):
    messages = []
    private_notes = []
    for conv in sorted(conversations, key=lambda c: c["created_at"]):
        if conv.get("private"):
            private_notes.append(conv)  # Handle in Step 6
            continue
        msg = {
            "content": {"value": conv["body"], "_type": "Html"},
            "attachments": [
                {"url": a["attachment_url"], "prettyName": a["name"]}
                for a in conv.get("attachments", [])
            ],
            "createdAt": conv["created_at"],
            "_type": "InboundImport" if conv["incoming"] else "OutboundImport"
        }
        if not conv["incoming"]:
            msg["agentId"] = agent_map.get(conv["user_id"])
        messages.append(msg)

    payload = {
        "requesterId": requester_id,
        "direction": "Inbound",
        "messages": messages,
        "createdAt": ticket["created_at"],
        "externalId": f"freshdesk-ticket-{ticket['id']}",
        "_type": "Email"  # Only "Email" and "GenericApiMessaging" supported
    }
    if ticket["status"] in [4, 5]:  # Resolved/Closed
        payload["closing"] = {"closedAt": ticket["updated_at"]}

    resp = requests.post(
        "https://dev.dixa.io/v1/conversations/import",
        json=payload,
        headers={"Authorization": f"Bearer {DIXA_TOKEN}"}
    )
    result = resp.json()
    if result.get("data", {}).get("partialErrors"):
        log_partial_errors(ticket["id"], result["data"]["partialErrors"])
    return result, private_notes
```

Use structured logging, not print statements. Log **source ticket ID, destination conversation ID, step, retry count, response code, and payload hash** so you can rerun by `externalId` instead of by date.

### Step 6: Apply Internal Notes, Tags, and Custom Attributes

After import, add private notes through Dixa's notes endpoint (`POST /v1/conversations/{id}/notes`), tag each conversation via `POST /v1/conversations/{id}/tags/{tagId}`, and patch custom attributes using the conversation ID returned from the import step.

### Step 7: Delta Sync and Cutover

Replay tickets updated after the baseline export using Freshdesk's `updated_since` parameter. For near-real-time delta sync during the cutover window, you can also configure Freshdesk webhooks (`Admin > Automations > Webhook`) to POST new/updated ticket data to your ETL pipeline, reducing the gap between Freshdesk and Dixa during the final switchover. Validate counts and sampled threads, then switch agents to Dixa during a short cutover window. Do not cut over if counts reconcile but thread order, private notes, or requester identity are wrong.

## Dixa Sandbox Setup for Testing

Dixa does not offer a self-service sandbox environment. To get a test/sandbox instance:

1. **Contact your Dixa account manager** and request a sandbox organization. This is typically provisioned as a separate Dixa organization with the same plan features as your production instance.
2. **Sandbox instances share the same API rate limits** as production — plan your test migration load accordingly.
3. **Data in sandbox is fully isolated** from production. After testing, you can request sandbox data deletion before running the production migration.

If you cannot get a sandbox, create a separate Dixa organization on a trial and run test imports there. Trial accounts have reduced rate limits, so throughput numbers from trial testing will not reflect production performance.

## Edge Cases and Known Limitations

Prepare for these specific failure modes:

**Inline images.** Freshdesk often embeds images directly in the HTML body using `<img>` tags referencing Freshdesk CDN URLs. After migration, if your Freshdesk account is deactivated, those CDN URLs break. Before cutover, parse the HTML, extract the `src` URLs, download each image, re-host it (on S3 or your own CDN), and rewrite the HTML body before loading into Dixa.

**Attachment authentication and expiry.** If Freshdesk attachment URLs require authentication or expire, download attachments to temporary public storage and reference those URLs in the import payload. Dixa downloads attachments from the provided URLs during import — they must be accessible at that moment.

**Private notes handling.** Freshdesk private notes with `private: true` should map to Dixa Internal Notes. The conversation import endpoint does not support internal notes in the same payload — you need a separate API call per note via `POST /v1/conversations/{id}/notes` after the conversation is created.

**Custom field type mismatches.** Freshdesk supports nested dropdown fields (dependent fields). Dixa custom attributes do not support nested dropdowns. Flatten these into separate attributes or concatenate values.

**Duplicate end users.** Freshdesk allows multiple contacts with the same email. Dixa deduplicates end users by email — a create call with an existing email returns a 409 Conflict. Query for existing end users first, or handle 409 responses as shown in the code sample above.

**Multi-brand mapping.** Freshdesk handles multiple brands under one account. Dixa handles this through separate Queues and contact endpoints. Map the Freshdesk `product_id` to the correct Dixa Queue.

**Archived tickets.** Freshdesk UI exports may omit archived tickets. Use the admin account export (`/api/v2/account/export`) or the REST API with appropriate filters to ensure archived tickets are included. ([support.freshdesk.com](https://support.freshdesk.com/support/solutions/articles/225158-how-do-i-export-my-tickets-from-freshdesk-))

**Merged tickets.** Freshdesk ticket merges create a primary ticket with references to merged ticket IDs. Verify that merged ticket conversations are extracted from the primary ticket, not the now-closed merge sources.

## Rollback Strategy

If the migration fails mid-flight or post-cutover validation reveals unacceptable data quality:

1. **Freshdesk data is never modified** by the extraction process — your source system remains intact.
2. **Revert DNS and email routing** from Dixa contact endpoints back to Freshdesk inboxes. This can be done in minutes if you pre-document the original DNS records.
3. **Delete imported Dixa conversations** via `DELETE /v1/conversations/{id}` if you need a clean slate before re-running. For bulk deletion, script against your migration log (which should contain all created conversation UUIDs).
4. **Re-run the migration** after fixing transformation bugs. Using `externalId` on every imported record makes re-runs idempotent — you can skip already-imported records.

Document your original Freshdesk DNS/MX records, email forwarding rules, and routing configuration before making any changes during cutover.

## GDPR and Compliance Considerations

If you are migrating customer data across systems, consider the following:

- **Data residency.** Freshdesk stores data in AWS regions (US, EU, India, Australia). Dixa's primary data center is in Europe (AWS eu-west-1). If your Freshdesk instance is in a non-EU region, the migration constitutes a cross-border data transfer. Verify that your DPA (Data Processing Agreement) with Dixa covers the relevant transfer mechanism (Standard Contractual Clauses or adequacy decision).
- **Data minimization.** Migration is an opportunity to purge data you no longer need. Consider excluding tickets older than your retention policy, or tickets from deleted contacts who have exercised their right to erasure.
- **Staging data.** If you cache extracted data locally during transformation, that staging database or file system is a temporary data store subject to GDPR. Delete staging data after successful migration and validation.
- **Audit trail.** Maintain a log of what was migrated, when, by whom, and from where. Managed migration services typically provide this as a deliverable. For DIY migrations, your structured logging (source ID, destination ID, timestamp) serves this purpose.
- **HIPAA.** If you handle protected health information, confirm that both your Freshdesk and Dixa accounts are on HIPAA-eligible plans with signed BAAs before migrating any PHI.

## How Long Does a Freshdesk to Dixa Migration Take?

[For PMs] Realistic timelines depend on volume and complexity:

| Scenario | Volume | Timeline | Approach | Estimated Cost |
|---|---|---|---|---|
| Small team, email only | < 10,000 tickets | 3–5 days | CSV export + script or third-party tool | 20–40 engineer-hours or $1,000–$3,000 (tool) |
| Mid-market, multi-channel | 10,000–100,000 tickets | 1–2 weeks | API-based migration | 80–120 engineer-hours or $5,000–$10,000 (managed) |
| Enterprise, multi-brand | 100,000–500,000+ tickets | 2–4 weeks | Managed service or custom ETL | $10,000–$20,000+ (managed) |

These timelines include extraction, transformation, test loads, validation, and cutover. The mapping and transformation phase typically consumes 40–50% of the total project time. The timeline depends more on archived history, company mapping, attachments, and custom field cleanup than raw ticket count.

### Phased Approach

Do not attempt a big-bang migration for anything over 10,000 tickets. Use a phased approach.

| Phase | Duration | Activities |
|---|---|---|
| Discovery & Mapping | 2–3 days | Audit Freshdesk data, build object map, identify custom fields and edge cases |
| Script Development / Tool Config | 3–5 days | Build ETL pipeline or configure migration tool, handle auth and rate-limit logic |
| Test Migration (Dry Run) | 2–3 days | Full test load into Dixa sandbox, validate record counts and field accuracy |
| UAT & Fixes | 2–3 days | Agent testing, fix transformation bugs, re-run if needed |
| Production Migration | 1–2 days | Final extraction, delta sync, cutover, DNS/email routing switch |
| Post-Go-Live Support | 3–5 days | Monitor for missing data, handle edge cases, answer agent questions |

### Risk Register

| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| API rate limit exhaustion delays extraction | High | Medium | Implement exponential backoff; run extraction during off-hours; pause other Freshdesk integrations |
| Attachment URLs expire before Dixa downloads them | Medium | High | Pre-download to temporary cloud storage (S3, GCS) with presigned URLs |
| Custom field type mismatch causes data truncation | Medium | Medium | Audit all custom fields before migration; build explicit type converters |
| Dixa API returns partial errors on conversation import | Medium | Medium | Check `data.partialErrors` in every 201 response; log and retry failures |
| End user deduplication conflicts | High | Low | Query existing end users before create; handle 409 responses |
| Hitting the Dixa 864,000 daily request limit | Medium | High | Throttle the historical sync over multiple days; monitor `X-RateLimit-Remaining` header |
| Missing in-flight ticket updates during cutover | Medium | High | Use Freshdesk `updated_since` parameter and/or webhooks during final delta sync |
| Archived tickets omitted from export | Medium | High | Use account export or REST API, not UI export ([support.freshdesk.com](https://support.freshdesk.com/support/solutions/articles/225158-how-do-i-export-my-tickets-from-freshdesk-)) |
| Inline images break after Freshdesk deactivation | High | Medium | Parse HTML bodies, extract image URLs, re-host to S3/CDN before import |
| Mid-migration failure requires rollback | Low | High | Document original DNS/MX records; use `externalId` for idempotent re-runs |

## Validation and Testing

Validation catches data loss before your agents do. Run these checks after every test load:

| Check | Method | Pass Criteria |
|---|---|---|
| Record count | Compare Freshdesk ticket count vs. Dixa conversation count | 100% match |
| Message count | Sample 50 tickets; compare reply count in Freshdesk vs. message count in Dixa | 100% match per ticket |
| Internal notes count | Sample 30 tickets with private notes; verify note count in Dixa | 100% match per ticket |
| Attachment integrity | Sample 20 tickets with attachments; verify files open in Dixa | All files accessible and not zero-byte |
| Custom attribute values | Sample 30 records; compare field values | Exact match |
| Tag assignment | Query Dixa conversations by tag; compare counts | Within 1% of source |
| Agent attribution | Verify outbound messages show correct agent names | Spot-check 20 conversations |
| Timestamps | Confirm `createdAt` on imported conversations matches Freshdesk `created_at` | Exact match (UTC) |
| Thread order | Sample recent, old, reopened, merged, and archived tickets | Chronological order preserved |
| Legacy ID search | Search for old Freshdesk ticket IDs stored in `externalId` | All searchable |
| Inline images | Sample 10 tickets with embedded images; verify images render | All images display correctly |

[For customer success] Run a UAT session with 3–5 agents: ask them to search for 10 known customers, verify conversation history appears correctly, and confirm they can follow up on imported conversations. Do not cut over if counts reconcile but thread order, private notes, or requester identity are wrong.

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

## Customer and Operational Impact

[For customer success] Here's what your customers and agents will actually experience:

- **Downtime.** A well-executed migration causes zero customer-facing downtime. New tickets continue to flow into Freshdesk until the final delta sync, then DNS/email routing switches to Dixa.
- **Ticket continuity.** Customers who reply to old Freshdesk notification emails will hit a dead end unless you set up email forwarding from Freshdesk inboxes to Dixa contact endpoints.
- **History visibility.** Imported conversations appear in Dixa's End User timeline. Agents can see the full thread, but the conversation won't have a Freshdesk ticket number — only a Dixa conversation UUID. Store the old ticket ID in `externalId` or a custom attribute so agents can search both systems during the transition.
- **SLA reset.** Freshdesk SLA data does not transfer. SLA timers in Dixa start fresh based on queue configuration.

### Change Management Checklist

1. Communicate the migration timeline to agents 2 weeks before cutover.
2. Run a 30-minute training session on Dixa's conversation view, queue structure, and tag workflow.
3. Provide a searchable FAQ document mapping "how I did X in Freshdesk" → "how to do X in Dixa."
4. Keep Freshdesk in read-only mode for 2 weeks post-cutover as a reference fallback.
5. Designate 1–2 agents as "migration champions" who escalate data issues found during the first week.

## What Data Cannot Be Migrated from Freshdesk to Dixa?

The following Freshdesk objects have no migration path to Dixa:

- **Automations, Dispatch Rules, and Supervisor Rules** — must be rebuilt in Dixa's flow builder
- **Canned Responses** — recreate as Dixa Templates
- **SLA Policies** — rebuild per-queue in Dixa
- **Customer Satisfaction Survey configuration** — reconfigure in Dixa's rating system
- **Forum/Community content** — no equivalent in Dixa
- **Time tracking entries** — no equivalent in Dixa
- **Agent Shift schedules** — configure Business Hours in Dixa separately
- **Ticket views and dashboards** — rebuild in Dixa's analytics
- **Freddy AI / chatbot configurations** — no migration path; configure Dixa's own automation tools

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

**Build in-house when:**
- You have fewer than 10,000 tickets with simple fields
- You have a backend engineer with 2+ weeks (80–120 hours) of dedicated bandwidth
- You don't need attachments or complex threading preserved
- You're comfortable writing and maintaining retry logic against two different API rate-limit models

**Use a managed service when:**
- You have 50,000+ tickets or complex custom fields
- Engineering time has a higher-value alternative (shipping product features)
- You need zero-downtime cutover with delta sync
- You need guaranteed data integrity with validation reports
- You have compliance requirements (GDPR, HIPAA) that require auditable migration logs

The hidden cost of DIY is not the first migration — it's the second one. When the test load reveals 200 edge cases in custom field mapping or broken attachment URLs, you've already burned a sprint. And if something breaks in production, the engineer who built the script is the only person who can fix it.

A good migration preserves **history, searchability, and routing intent**. It does not promise fake 1:1 parity where the platforms are structurally different. If you design for ticket-to-conversation remapping, seed Dixa metadata first, use the historical import endpoint, and treat validation as part of the build, this migration is very workable.

---

*ClonePartner is a managed migration service. We handle the ticket-to-conversation model translation, per-minute and per-second rate-limit orchestration across both APIs, attachment re-hosting, and full validation with record-count reconciliation — with zero downtime for your support operations. The technical content above reflects our direct experience with these APIs and is accurate as of June 2025.*

> Need help migrating from Freshdesk to Dixa? ClonePartner handles the full migration — extraction, transformation, loading, and validation — with zero downtime. Book a 30-minute call to scope your project.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## Frequently asked questions

### Can I migrate Freshdesk to Dixa without losing data?

Yes — ticket content, replies, notes, contacts, tags, and attachments can all be migrated to Dixa with full fidelity using the API. The data you will lose is operational configuration: automations, SLA policies, canned responses, and time tracking entries. These must be rebuilt manually in Dixa. The common data-loss pattern is relying on Freshdesk CSV export alone, because it omits full conversation threads and archived tickets.

### What data cannot be migrated from Freshdesk to Dixa?

Automations, dispatch rules, canned responses, SLA policies, time tracking entries, forum content, agent shift schedules, and ticket views cannot be migrated. These must be rebuilt manually in Dixa's flow builder, templates, queue settings, and analytics.

### What Dixa plan do I need for API-based migration?

You need the Ultimate plan ($139/agent/month annual) or Prime plan ($179/agent/month annual). The Growth plan does not include API access. All Dixa plans require a 7-seat minimum.

### How long does a Freshdesk to Dixa migration take?

A small team with fewer than 10,000 email-only tickets can complete the migration in 3–5 days. Mid-market migrations (10K–100K tickets) typically take 1–2 weeks. Enterprise migrations with 100K+ tickets, multi-brand setups, and attachments take 2–4 weeks. These timelines include mapping, test loads, validation, and cutover.

### Can I keep Freshdesk ticket IDs in Dixa?

Not as native Dixa conversation IDs — Dixa uses UUIDs. The standard approach is to store the old Freshdesk ticket ID in Dixa's externalId field or a custom attribute so agents can search legacy references after cutover.
