Skip to content

Dixa to Zendesk Migration: The CTO's Technical Guide

A technical guide to migrating from Dixa to Zendesk: API extraction, data mapping, rate limits, edge cases, and step-by-step implementation.

Rishabh Rishabh · · 30 min read
Dixa to Zendesk Migration: The CTO's Technical Guide
TALK TO AN ENGINEER

Planning a migration?

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

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

Migrating from Dixa to Zendesk moves your support operation from a conversation-centric, offer-based routing platform to a ticket-lifecycle, view-based system. Dixa routes conversations in real-time based on agent presence and skills; Zendesk relies on views, triggers, and automations to move tickets through a state machine. This architectural difference means you cannot copy and paste data — you must translate your data model and rebuild your operational workflows.

The data transfer path is well-defined. Dixa's Exports API streams conversations and messages by time range, and Zendesk's Ticket Import API accepts historical tickets with preserved timestamps. The hard part is the workflow redesign: translating Dixa's visual Flow Builder into Zendesk's combination of triggers, automations, views, and SLA policies, and accepting that Dixa's native voice and push-based routing have no direct Zendesk equivalent without additional configuration.

Info

TL;DR Conversation history, contacts, tags, and custom attributes extract cleanly from Dixa via API and load into Zendesk via the Ticket Import API with timestamp preservation. Dixa's Exports API caps at 10 conversation requests per minute and limits each query to a 31-day window — plan extraction accordingly. Zendesk's import endpoint accepts batches of 100 tickets and does not fire triggers or automations on imported records. The workflow redesign (Dixa Flows and Queues → Zendesk triggers, views, and Omnichannel Routing) is the most time-consuming task. Realistic timeline for ~30 agents and 100K conversations: 3–6 weeks including planning, test migration, workflow rebuild, and validation.

For Dixa-side extraction details, see How to Export Data from Dixa: Methods, API Limits & Data Mapping. For post-migration testing, see Post-Migration QA: 20 Tests to Run After Your Help Desk Data Migration.

Why Teams Migrate from Dixa to Zendesk

Teams move from Dixa to Zendesk for platform-specific reasons, not because one is universally better. The friction points are architectural.

  • Marketplace ecosystem. Zendesk's marketplace lists over 1,500 apps (zendesk.com/marketplace). Dixa's integration library is significantly smaller — under 100 native integrations as of 2025. If your stack depends on deep third-party connections (Jira, Salesforce, Shopify analytics), Zendesk covers more ground.
  • Reporting depth. Zendesk Explore provides custom report building with a drag-and-drop query builder, pre-built dashboards, scheduled delivery, and cross-channel analytics including custom metrics and calculated attributes (support.zendesk.com/hc/en-us/articles/4408821475098). Dixa's native reporting supports standard metrics but lacks comparable customization and drill-down capability.
  • Knowledge base maturity. Zendesk Guide supports categories, sections, community forums, content versioning, and multi-brand knowledge bases. Dixa Knowledge (acquired via Elevio) has fewer content hierarchy features for complex documentation structures.
  • Enterprise compliance. Zendesk offers FedRAMP LI-SaaS authorization and a HIPAA BAA path on Suite Enterprise and above (zendesk.com/trust). Dixa holds SOC 2 Type II and is GDPR-compliant but does not publicly advertise HIPAA compliance or ISO 27001 certification as of mid-2025.
  • Platform consolidation. When the broader org already runs Zendesk for other teams, maintaining a separate Dixa instance creates data silos, duplicate reporting, and integration overhead.

Core Architectural Differences

Three design differences make this migration non-trivial:

Offer-based routing vs. view-based pulling. Dixa pushes conversations to agents based on real-time availability, skills, and priority scores. Zendesk uses views, groups, and Omnichannel Routing rules to surface work — a fundamentally different approach to workload distribution. Zendesk's Omnichannel Routing (available on Suite Professional and above) can approximate Dixa's push model using auto-routing with agent status and skill-based assignment, but requires explicit configuration of skills, agent unified statuses, and routing rules (support.zendesk.com/hc/en-us/articles/5066691498650).

Visual Flow Builder vs. flat business rules. Dixa's Flow Builder is a single drag-and-drop canvas handling queue assignment, IVR, auto-replies, priority, and escalation with branching logic. Zendesk distributes the same behavior across triggers (event-based rules that fire on ticket creation or update), automations (time-based rules), SLA policies, groups, views, macros, and Talk settings. There is no automated migration path between these systems. A complex Dixa Flow with 15–20 branches typically translates into 8–15 Zendesk triggers plus 2–4 automations plus SLA policies.

Native omnichannel vs. add-on voice. Dixa includes phone, IVR, callback, and recording natively in every plan. Zendesk Talk is a separate product with its own pricing (starting at $49/agent/month for Talk Partner Edition, or usage-based for Zendesk Talk) and configuration layer (zendesk.com/talk).

Migration Approaches

There are five viable methods to move data from Dixa to Zendesk. The right choice depends on data volume, engineering bandwidth, and whether you need a one-time transfer or ongoing sync.

1. CSV Export / Import

How it works: Export conversation data from Dixa's built-in CSV export, restructure the CSV to match Zendesk's bulk import format, and upload via Zendesk Admin Center.

When to use it: Small datasets (<5,000 conversations), minimal custom fields, teams without developer resources. Never for full production migrations.

Pros: No code required for initial export. Zendesk's UI bulk importer handles up to 2,000 users per upload.

Cons: Dixa's CSV export includes conversation metadata but not full message threads — you get summary data, not the complete conversation body. Attachments are lost. Timestamps default to import date unless you use the API. Manual field mapping is error-prone at scale.

Complexity: Low

2. API-Based Migration

How it works: Use Dixa's Exports API (docs.dixa.io/docs/exports-api) and API v1 (docs.dixa.io/openapi) to extract conversations, messages, contacts, tags, and custom attributes. Transform the data to match Zendesk's schema. Load into Zendesk using the Ticket Import API (developer.zendesk.com/api-reference/ticketing/tickets/ticket_import), Users API, and Organizations API.

When to use it: The default choice for most production migrations where you need full message history, timestamp preservation, and attachment migration.

Pros: Full control over extraction and transformation. Preserves created_at, updated_at, and solved_at timestamps. Handles attachments, internal notes, tags, and custom fields. Repeatable — run test migrations before cutover.

Cons: Requires significant engineering effort (80–160 hours depending on complexity). Dixa's Exports API rate limits are tight: 10 requests/min for conversations, 3 requests/min for messages. Must handle ID mapping, error recovery, and retry logic.

Complexity: High

3. Third-Party Migration Tools

How it works: Services like Help Desk Migration provide a GUI-based wizard that connects to both Dixa and Zendesk via API, maps fields, and transfers data.

When to use it: Mid-size migrations (10K–100K conversations) where you want to avoid writing custom code.

Pros: Pre-built connectors reduce development time. Visual field mapping. Built-in deduplication and validation.

Cons: Per-record pricing can be expensive at scale (typically $1–$5 per 100 records depending on provider and data complexity). Limited control over transformation logic. May not handle edge cases (linked conversations, nested custom attribute hierarchies, call recordings). Verify the vendor uses Dixa API v1, not the deprecated Integrations API.

Complexity: Medium

4. Custom ETL Pipeline

How it works: Extract Dixa data into a data warehouse (e.g., BigQuery, Snowflake), transform with dbt or custom scripts, and load into Zendesk with worker queues and persistent state tables.

When to use it: Enterprise volume (500K+ conversations), complex data transformations, regulatory requirements demanding an auditable pipeline, or migrations that also feed BI and archival systems.

Pros: Maximum flexibility and control. Auditable transformation logic. Can be reused for ongoing sync or future migrations.

Cons: Highest engineering investment (200+ hours). Requires infrastructure setup and maintenance. Overkill for most helpdesk migrations.

Complexity: High

5. Middleware / Integration Platforms (Zapier, Make)

How it works: Use iPaaS platforms to connect Dixa triggers (e.g., conversation closed) to Zendesk actions (create ticket). Event-driven rather than bulk historical.

When to use it: Ongoing sync of new conversations during a transition period, or very small historical transfers.

Pros: No-code setup. Good for real-time delta sync during a parallel-run cutover.

Cons: Not designed for bulk historical migration. Per-task pricing becomes expensive at volume (Zapier charges per task; 100K conversations with 5 messages each = 500K+ tasks). Cannot preserve original timestamps on historical data. Limited error handling and retry logic.

Complexity: Low

Migration Approach Comparison

Approach Best For Timestamp Preservation Attachments Engineering Effort Complexity
CSV Export/Import <5K conversations Requires API No Low Low
API-Based Any volume (default) Yes Yes High (80–160 hrs) High
Third-Party Tools 10K–100K conversations Yes Partial Low Medium
Custom ETL >500K conversations Yes Yes Very High (200+ hrs) High
Middleware (Zapier/Make) Ongoing sync only No (new records only) Limited Low Low

Scenario-Based Recommendations

  • Small business (<10K conversations, no dev team): Use a third-party migration tool or managed service. The per-record cost is justified by the time saved.
  • Mid-market (10K–200K conversations, some engineering bandwidth): API-based migration with custom scripts, or a managed migration service.
  • Enterprise (>200K conversations, dedicated dev team): Custom ETL pipeline or managed service. Dixa's Exports API rate limits make bulk extraction slow — plan for multi-day extraction windows. At 3 req/min for messages with pagination, extracting 500K conversations with an average of 6 messages each can take 40+ hours of continuous API calls.
  • Ongoing sync during transition: Use Zapier/Make for real-time forwarding of new conversations while historical data migrates via API.

Estimated Migration Costs

Scenario Engineering Hours Tooling/Service Cost Zendesk Plan Delta (annual, est.) Total Estimated Cost
Small (<10K convos, third-party tool) 10–20 hrs $500–$2,000 Varies by plan $2,500–$5,000
Mid-market (50K convos, API-based) 80–120 hrs Minimal (hosting) Varies by plan $12,000–$24,000 in eng time
Enterprise (500K convos, ETL pipeline) 200–300 hrs $1,000–$5,000 infra Varies by plan $40,000–$60,000+ in eng time
Managed service (any volume) 5–15 hrs internal $3,000–$15,000 service fee Varies by plan $5,000–$20,000

Engineering hours valued at $150/hr (blended rate for mid-senior engineers). Actual costs vary by region, team structure, and data complexity.

When to Use a Managed Migration Service

Building a migration script sounds like a weekend project. In practice, handling nested JSON payloads, undocumented API behaviors, and attachment extraction takes weeks of iterative debugging. The real risks are not the happy path — they are the edge cases.

Risks of DIY migration:

  • Broken relationships. Conversations reference contacts by ID. If contacts are not loaded first, or if ID mapping fails, conversations become orphaned. There is no undo button on the Zendesk import API.
  • Silent data loss. Dixa's export messages endpoint does not include internal notes — those live under conversation_wrapup_notes on the conversation object, or require a separate call to GET /v1/conversations/{id}/notes. Miss this and you lose all agent context.
  • Rate limit math. At 3 requests per minute for message export with a 31-day query window, extracting 3 years of data requires dozens of sequential API calls with careful pagination. One malformed request can derail your extraction schedule.
  • Attachment handling. Each attachment must be downloaded from Dixa, uploaded to Zendesk's Upload API to get a token, then attached to the ticket comment. Upload tokens expire after 60 minutes (developer.zendesk.com/api-reference/ticketing/tickets/ticket-attachments). This is a separate pipeline with its own failure modes.

Hidden costs of in-house migration:

  • 80–200+ engineering hours diverted from product work
  • 2–3 full test migrations before production is realistic
  • Workflow redesign (Dixa Flows → Zendesk triggers/automations) is manual regardless
  • Post-migration bug fixing and data patching typically adds 20–40 hours

Pre-Migration Planning

Data Audit Checklist

Data Category What to Count Notes
Conversations Total count by channel (email, chat, phone, social) Phone conversations may only contain metadata + recording URLs
Messages Total messages across all conversations Internal notes are separate from messages
End Users (Contacts) Active and archived contacts Check for duplicates by email
Agents Active and deactivated agents Deactivated agents still own historical conversations
Tags Active and deactivated tags Deactivated tags may still appear on historical conversations
Custom Attributes Conversation-level and end-user-level Note data types: text, dropdown, number, date
Teams & Queues Team structure and queue routing rules Queues map to Zendesk Groups + Views
Knowledge Base Articles, categories, sections Dixa Knowledge → Zendesk Guide is a separate migration
Flows Active Flows and their routing logic Must be rebuilt manually in Zendesk
Attachments Estimate total size Zendesk caps at 50MB per attachment for most plans

Define Migration Scope

Not everything needs to migrate. Common exclusions:

  • Abandoned conversations with no agent response — often 20–40% of chat volume
  • Test conversations from staging environments
  • Spam / junk conversations already filtered by Dixa
  • Conversations older than N years — check your data retention policy and any contractual or regulatory retention requirements
  • Inactive users who have not submitted a ticket in 2+ years

Reducing payload size speeds up the migration, simplifies QA, and lowers Zendesk storage costs.

GDPR and Data Residency Considerations

Moving customer data between two SaaS platforms has compliance implications:

  • Data Processing Agreements (DPAs). Ensure you have valid DPAs with both Dixa and Zendesk. Zendesk's DPA is available at zendesk.com/company/privacy-and-data-protection. Dixa's DPA is available upon request.
  • Data residency. Dixa hosts data in the EU (AWS eu-west-1). Zendesk offers regional data hosting in the US, EU (Germany), and Australia on Suite Enterprise plans with the Advanced Data Privacy and Protection add-on (zendesk.com/trust). If you are migrating from EU-hosted Dixa to a US-hosted Zendesk instance, this constitutes a cross-border data transfer requiring appropriate safeguards (Standard Contractual Clauses or adequacy decisions).
  • Right to deletion. If any data subjects have pending or fulfilled deletion requests in Dixa, verify those records are excluded from the migration payload. Importing previously deleted personal data into Zendesk creates a GDPR violation.
  • Data minimization. The migration is an opportunity to purge data you no longer need. Migrating 5 years of conversation history when your retention policy is 3 years is unnecessary and increases compliance surface area.
  • Temporary storage. If your ETL pipeline stores extracted data in an intermediate location (local disk, S3 bucket, data warehouse), that storage location must also comply with your DPA and data residency requirements. Encrypt data at rest and delete intermediate files after migration validation.

Migration Strategy

Strategy Best For Risk Level
Big bang <50K conversations, small teams, weekend cutover window Medium — all-or-nothing
Phased Large datasets, multiple teams/brands Low — migrate by channel or team, but requires coordination to prevent data silos
Incremental Active environments with high daily volume Low — historical first, validate, then delta sync

For most Dixa-to-Zendesk migrations, incremental is the safest approach: load historical data first, validate, then run a delta migration for conversations created between the first load and cutover.

Data Model & Object Mapping

Dixa and Zendesk use fundamentally different data models. Dixa is conversation-centric with a flat structure. Zendesk is ticket-centric with nested relationships (organizations → users → tickets → comments).

Object-Level Mapping

Dixa Object Zendesk Equivalent Notes
Conversation Ticket 1:1 mapping. Status maps to ticket status.
End User User (end-user role) Match on email. Create if not exists.
Agent User (agent role) Must exist in Zendesk before ticket import. Map Dixa agent roles to Zendesk roles: Agent, Admin, or Light Agent (read-only, available on Suite Growth+).
Company / Account Organization Normalize name, domains, custom attributes.
Team Group Similar purpose, different routing model.
Queue Group + View + Omnichannel Routing Rule Dixa queues combine routing + visibility + priority. Zendesk separates these into three distinct configuration layers.
Tag Tag Dixa tags may have spaces and colors; Zendesk tags are plain text, lowercase with underscores.
Custom Attribute (Conversation) Custom Ticket Field Type mapping required (see below).
Custom Attribute (End User) Custom User Field Same type mapping.
Message (inbound) Ticket Comment (public, author = requester) Preserve created_at.
Message (outbound) Ticket Comment (public, author = agent) Agent must exist as Zendesk user.
Internal Note / Wrap-up Note Ticket Comment (private) Wrap-up notes live on the conversation object, not in messages.
Conversation Rating Ticket Satisfaction Rating Zendesk CSAT is binary (good/bad); Dixa may use different scales.
Flow Triggers + Automations + SLA Policies + Omnichannel Routing Config No automated migration path. Manual rebuild required.
Knowledge Article Zendesk Guide Article Separate migration project.

Dixa Agent Roles → Zendesk Roles

Dixa Role Zendesk Equivalent Notes
Admin Admin Full configuration access
Agent Agent Standard ticket handling
Agent (read-only / limited) Light Agent or Contributor Light Agents can add private comments but cannot be assigned tickets. Available on Suite Growth and above. Contributor role replaces Light Agent on some newer plans.

Field-Level Mapping

Dixa Field Zendesk Field Type Transformation
conversation.id (csid) ticket.external_id String Store for traceability and delta syncs
conversation.created_at ticket.created_at DateTime ISO 8601 — pass via Ticket Import API
conversation.status ticket.status Enum Map: open→open, pending→pending, closed→solved
conversation.channel ticket.via.channel Enum widget_chat→chat, phone→voice, email→email
conversation.requester_id ticket.requester_id Integer Requires ID mapping table
conversation.assigned_to ticket.assignee_id Integer Requires agent ID mapping
conversation.queue_id ticket.group_id Integer Requires queue→group mapping
conversation.tags [] ticket.tags [] String [] Lowercase, replace spaces with underscores
conversation.customAttributes{} ticket.custom_fields [] Object→Array Map attribute UUID → Zendesk field ID
message.content.value comment.body or comment.html_body String Handle HTML vs plain text
conversation_wrapup_notes Comment (private) String Create as last private comment
End User displayName User name String Direct mapping
End User email User email String Primary deduplication key
Rating score Satisfaction Rating Enum Map to good/bad binary
Warning

Critical: Dixa's Exports API message endpoint does not contain internal notes. Wrap-up notes are found under conversation_wrapup_notes on the conversation object, or via GET /v1/conversations/{id}/notes. If your extraction script only pulls from the messages endpoint, you will lose all internal agent notes.

Custom Attribute Type Mapping

Dixa Type Zendesk Type Notes
Text Text Direct mapping
Dropdown (single select) Drop-down Recreate all option values in Zendesk first
Dropdown (nested) Drop-down Zendesk does not support nested dropdowns — flatten to single level (e.g., "Payment - Card - Visa")
Number Decimal or Integer Choose based on whether decimals are needed
Date Date Verify format compatibility
Boolean Checkbox Map true/false

Zendesk Custom Objects

If you built complex relational data in Dixa that does not map to standard ticket, user, or organization fields, you may need Zendesk Custom Objects (Sunshine). Be aware of plan-level limits: 3/5/30/50 custom objects by plan, 100 fields per object, 5–10 lookup fields per object, and 32 KB per record. Sandboxes do not copy custom object records or lookup-based triggers automatically — seed them deliberately during testing. Legacy custom objects are being removed starting July 27, 2026; use the new custom objects platform only. (developer.zendesk.com/api-reference/custom-data/introduction/)

Warning

Zendesk Sell is being retired. Zendesk announced on June 19, 2026 that Sell will retire on August 31, 2027. If your migration plan includes CRM data going to Zendesk Sell, consider alternative targets. Companies, leads, and deals are Sell-specific objects — treat Support and Sell as separate scoping exercises. (support.zendesk.com)

Migration Architecture

Your migration infrastructure must handle Extract, Transform, and Load phases independently to allow for failure recovery at each stage.

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│   DIXA       │────▶│  TRANSFORM   │────▶│  ZENDESK    │
│              │     │              │     │             │
│ Exports API  │     │ ID mapping   │     │ Users API   │
│ Dixa API v1  │     │ Field mapping│     │ Orgs API    │
│              │     │ Type convert │     │ Ticket      │
│              │     │ Dedup        │     │ Import API  │
└─────────────┘     └──────────────┘     └─────────────┘

Dixa API Extraction Details

Exports API (for bulk conversation/message extraction):

  • Host: exports.dixa.io
  • Rate limit: Conversations 10 req/min, Messages 3 req/min
  • Query constraint: each request spans max 31 days (use _after and _before parameters)
  • Returns streamed JSON arrays
  • Does not include internal notes
  • Documentation: docs.dixa.io/docs/exports-api

Dixa API v1 (for contacts, tags, custom attributes, agents):

  • Host: dev.dixa.io
  • Rate limit: 10 requests/second per token with a burst allowance of 4, daily ceiling of 864,000 per token
  • Authentication: Bearer token (organization-scoped)
  • Pagination: cursor-based with pageToken and limit (max 100 per page)
  • No Retry-After header on 429 responses — implement your own exponential backoff
  • Documentation: docs.dixa.io/openapi

Extraction Throughput Benchmarks

Dataset Size Extraction Component Estimated Duration Bottleneck
10K conversations Conversations export ~17 minutes 10 req/min limit
10K conversations Messages export (avg 5 msgs/convo) ~2.8 hours 3 req/min limit, pagination
100K conversations Conversations export ~2.8 hours 10 req/min limit
100K conversations Messages export ~28 hours 3 req/min limit
500K conversations Conversations export ~14 hours 10 req/min limit
500K conversations Messages export ~5.8 days 3 req/min limit

Estimates assume single-token extraction, average 5 messages per conversation, and no errors requiring retries. Actual times will be higher due to pagination overhead, 429 retries, and network latency. Using multiple API tokens (if available) can parallelize extraction.

Zendesk API Loading Details

Ticket Import API:

  • Endpoint: POST /api/v2/imports/tickets/create_many (developer.zendesk.com/api-reference/ticketing/tickets/ticket_import)
  • Batch size: up to 100 tickets per request
  • Preserves created_at, updated_at, solved_at, and per-comment created_at
  • Does not fire triggers or automations on imported tickets
  • No notifications sent to customers or CC'd users on import
  • Comments with empty bodies are rejected — add placeholder text like "(Attachment only)"
  • Closed historical tickets can use archive_immediately to skip the active ticket pool on very large imports

Do not use the standard Tickets API for historical imports. The standard API overwrites creation dates with the import date, fires triggers, and sends email notifications to customers about years-old closed tickets.

Zendesk rate limits by plan (developer.zendesk.com/api-reference/introduction/rate-limits):

Zendesk Plan Rate Limit (req/min)
Team 200
Growth 400
Professional 400
Enterprise 700
Enterprise Plus 2,500

Zendesk enforces a 30-job concurrent limit for bulk operations. If you exceed rate limits, Zendesk returns a 429 Too Many Requests error with a Retry-After header — your script must detect this, sleep for the requested duration, and retry.

Tip

Throughput math: At 700 req/min (Enterprise) with 100 tickets per batch, you can theoretically import 70,000 tickets per minute. In practice, factor in user creation, attachment uploads, and error handling — realistic throughput is 5,000–15,000 tickets per hour.

Common Error Responses

When building your migration script, handle these specific failure modes:

Zendesk 422 (Unprocessable Entity) — empty comment body:

{
  "error": "RecordInvalid",
  "description": "Record validation errors",
  "details": {
    "base": [{"description": "Comment body is empty", "error": "BlankValue"}]
  }
}

Fix: Add placeholder text like "(Attachment only)" to comment bodies that contain only attachments.

Zendesk 422 — missing requester:

{
  "error": "RecordInvalid",
  "description": "Record validation errors",
  "details": {
    "requester_id": [{"description": "Requester not found", "error": "InvalidValue"}]
  }
}

Fix: Ensure all users are loaded (Step 2) before ticket import. Check your ID mapping table for gaps.

Dixa 429 (Rate Limited) — no Retry-After header:

{
  "error": "rate_limit_exceeded",
  "message": "Too many requests"
}

Fix: Dixa does not include a Retry-After header. Implement exponential backoff starting at 2 seconds, doubling on each retry, with a maximum of 5 retries.

Zendesk 429 — with Retry-After:

HTTP/1.1 429 Too Many Requests
Retry-After: 42

{"error": {"title": "Too Many Requests", "message": "You have exceeded the rate limit..."}}

Fix: Read the Retry-After header value and sleep for that many seconds before retrying.

Authentication: Zendesk OAuth Timeline

Zendesk is deprecating API token authentication. The timeline: automatic token deactivation begins July 28, 2026, new API token creation is blocked October 27, 2026, and remaining API tokens are permanently deactivated April 30, 2027. Plan your migration to use OAuth. If you use client-credentials OAuth, actions are attributed to the user who created the OAuth client — use a dedicated service account. (developer.zendesk.com/documentation/api-basics/authentication/oauth-migration/)

Step-by-Step Migration Process

Step 1: Set Up Zendesk Target Environment

Before loading any data:

  1. Create all custom ticket fields and custom user fields in Zendesk. Record their numeric IDs.
  2. Create groups that map to Dixa queues.
  3. Create agent accounts — agents must exist before you can assign tickets to them. Map Dixa agent roles to Zendesk roles (Admin, Agent, Light Agent/Contributor).
  4. Provision a Zendesk Sandbox for test migrations. Sandboxes are available on Suite Professional and above. On Professional plans, sandboxes have a 10K ticket limit and refresh weekly; Enterprise sandboxes support up to 100K tickets. Premium Sandboxes (Enterprise+) persist data and support longer test cycles (support.zendesk.com/hc/en-us/articles/4408832153114). Note: sandbox refreshes overwrite all data — complete each test cycle before the next refresh.
  5. Generate API credentials (OAuth preferred, noting the deprecation timeline above).

Step 2: Extract and Load Users

Tickets cannot exist without requesters. Extract all Dixa End Users via the API v1 GET /v1/endusers endpoint with cursor-based pagination, then load them into Zendesk.

import requests
import time
 
DIXA_TOKEN = "your_dixa_api_token"
BASE_URL = "https://dev.dixa.io/v1"
 
def extract_end_users():
    users = []
    page_token = None
    retries = 0
    while True:
        params = {"limit": 100}
        if page_token:
            params["pageToken"] = page_token
        resp = requests.get(
            f"{BASE_URL}/endusers",
            headers={"Authorization": f"Bearer {DIXA_TOKEN}"},
            params=params
        )
        if resp.status_code == 429:
            wait = min(2 ** retries, 60)  # Exponential backoff, max 60s
            time.sleep(wait)
            retries += 1
            if retries > 5:
                raise Exception("Max retries exceeded on Dixa API")
            continue
        resp.raise_for_status()
        retries = 0
        data = resp.json()
        users.extend(data.get("data", []))
        page_token = data.get("nextPageToken")
        if not page_token:
            break
    return users

Load users into Zendesk using POST /api/v2/users/create_or_update_many (100 users per batch). Store the mapping of Dixa_User_ID → Zendesk_User_ID in a persistent store (Redis, SQLite, or a database table) for fast lookups during ticket creation.

Zendesk's bulk user import may not be enabled by default on all accounts — it can return 403 until the account owner requests activation from Zendesk Support.

Step 3: Extract Conversations and Messages

The Exports API requires time-bounded queries with a maximum 31-day window. Loop through your data range in monthly chunks.

from datetime import datetime, timedelta
 
def extract_conversations(start_date, end_date):
    all_conversations = []
    current = start_date
    while current < end_date:
        window_end = min(current + timedelta(days=31), end_date)
        resp = requests.get(
            "https://exports.dixa.io/v1/conversation_export",
            headers={"Authorization": f"Bearer {DIXA_TOKEN}"},
            params={
                "_after": current.strftime("%Y-%m-%d"),
                "_before": window_end.strftime("%Y-%m-%d")
            }
        )
        if resp.status_code == 429:
            time.sleep(10)
            continue
        resp.raise_for_status()
        all_conversations.extend(resp.json())
        current = window_end
        time.sleep(6)  # Respect 10 req/min limit
    return all_conversations

For each conversation, fetch full message threads via the Dixa API v1, and separately fetch internal notes:

def get_messages(conversation_id):
    resp = requests.get(
        f"{BASE_URL}/conversations/{conversation_id}/messages",
        headers={"Authorization": f"Bearer {DIXA_TOKEN}"}
    )
    resp.raise_for_status()
    return resp.json().get("data", [])
 
def get_notes(conversation_id):
    resp = requests.get(
        f"{BASE_URL}/conversations/{conversation_id}/notes",
        headers={"Authorization": f"Bearer {DIXA_TOKEN}"}
    )
    resp.raise_for_status()
    return resp.json().get("data", [])

Store raw JSON payloads locally before transforming. Do not transform in flight — this allows recovery if the transform step fails.

Step 4: Handle Attachments

Zendesk requires attachments to be uploaded before the ticket comment is created.

  1. Download the file from the Dixa URL (private files require authenticated access).
  2. POST the binary data to Zendesk api/v2/uploads?filename=example.png.
  3. Save the returned upload_token.

Upload tokens expire after 60 minutes (developer.zendesk.com/api-reference/ticketing/tickets/ticket-attachments), so time your uploads close to ticket creation. Zendesk attachment size limit is 50MB per file — larger files (e.g., call recordings) should be hosted externally and linked from the ticket.

Step 5: Transform and Import Tickets

Using your locally stored user mappings and upload tokens, construct the ticket payload and push to Zendesk via the Ticket Import API.

ZENDESK_URL = "https://yoursubdomain.zendesk.com/api/v2/imports/tickets/create_many"
HEADERS = {"Content-Type": "application/json"}
AUTH = ("admin@company.com/token", "your_api_token")
 
# Example single ticket payload (batch up to 100)
ticket = {
    "ticket": {
        "requester_id": 123456789,   # Resolved from Step 2
        "assignee_id": 987654321,    # Resolved from Step 2
        "subject": "Historical Dixa Conversation",
        "external_id": "dixa-conv-abc123",
        "created_at": "2023-01-15T10:00:00Z",
        "status": "solved",
        "tags": ["imported_from_dixa", "billing_question"],
        "comments": [
            {
                "author_id": 123456789,
                "value": "I need help with my account.",
                "created_at": "2023-01-15T10:00:00Z",
                "public": True
            },
            {
                "author_id": 987654321,
                "value": "Fixed that for you.",
                "created_at": "2023-01-15T10:15:00Z",
                "public": True,
                "uploads": ["upload_token_from_step_4"]
            }
        ]
    }
}

Tag every imported ticket with imported_from_dixa — this enables validation queries, reporting exclusions, and rollback via bulk deletion if needed.

Step 6: Delta Sync

Run the extraction process again on cutover day, querying Dixa only for conversations created or updated since your initial extraction timestamp. The external_id field (populated with the original Dixa Conversation ID) makes delta syncs and deduplication straightforward.

Step 7: Validate

After import, run validation checks before declaring the migration complete. See the full validation framework below.

Omnichannel Routing: Translating Dixa Queues

Dixa's queue-based routing is the hardest workflow component to translate. Here is how the concepts map:

Dixa Queue → Zendesk Omnichannel Routing

Dixa Queue Concept Zendesk Equivalent Configuration Location
Queue (skill-based assignment) Omnichannel Routing with skills Admin Center → Objects and rules → Omnichannel routing
Agent skills/competencies Skills (up to 10 per agent on Enterprise) Admin Center → People → Skills
Queue priority order Routing priority (urgent/high/normal/low mapped to ticket priority) Ticket priority field + routing configuration
Agent availability/presence Unified agent statuses Admin Center → People → Agent statuses
Queue capacity limits Omnichannel capacity rules (max tickets per agent per channel) Admin Center → Objects and rules → Capacity rules
Queue overflow/fallback Routing rules with fallback groups Trigger-based group reassignment on SLA breach

Configuration Steps

  1. Enable Omnichannel Routing in Admin Center → Objects and rules → Omnichannel routing. Available on Suite Professional and above.
  2. Define skills that match your Dixa queue competencies (e.g., "billing," "technical," "spanish-language"). Assign skills to agents.
  3. Create routing rules that match ticket attributes (tags, custom fields, channel) to required skills. This replaces Dixa's Flow-based queue assignment.
  4. Set capacity rules per channel: e.g., max 4 chats, 1 phone call, 12 emails simultaneously per agent.
  5. Configure unified agent statuses to map Dixa's presence states (available, away, offline) to Zendesk statuses.
  6. Set up SLA policies with response and resolution targets by priority and group, replacing Dixa's queue-level SLA settings.
Warning

Key difference: Dixa's offer-based routing presents one conversation at a time and waits for agent acceptance. Zendesk's Omnichannel Routing auto-assigns tickets to agents based on availability and capacity — there is no accept/reject step. This changes agent behavior and may require training to prevent cherry-picking via views.

SLA Migration

Imported historical tickets do not receive SLA metrics in Zendesk. SLA policies only apply to tickets created after the policy is activated. This means:

  • Historical first-response-time and resolution-time data from Dixa is not available in Zendesk Explore
  • If you need historical SLA reporting, export it from Dixa before decommissioning and store it separately (e.g., in a BI tool or data warehouse)
  • New SLA policies should be configured and tested in the sandbox before cutover

Edge Cases & Challenges

Phone Conversations

Dixa phone conversations contain call metadata (duration, recording URL, IVR path) but no text body. Create a ticket with a system note containing structured call metadata (duration, caller number, IVR selections). For call recordings:

  • If recordings are <50MB: Download from Dixa, upload to Zendesk as attachments.
  • If recordings are >50MB: Host on S3, GCS, or your existing storage with appropriate access controls and retention policies. Add the URL as a private comment on the ticket.
  • Retention: Set bucket lifecycle policies matching your call recording retention requirements (typically 90 days to 7 years depending on jurisdiction and industry).
  • Zendesk Talk recordings are stored separately from ticket attachments and have their own retention settings — imported call recordings attached to tickets behave differently from native Talk recordings.

Linked Conversations

Dixa supports linking conversations to parent conversations. Zendesk has no native equivalent. Options:

  1. Store the parent conversation ID in a custom field (simplest)
  2. Use Zendesk's side conversation feature as an approximation (Suite Professional+)
  3. Add a private comment with a link to the related ticket using the external_id to look up the parent

Duplicate Contacts

A single customer may exist in Dixa under multiple emails or phone numbers, while Zendesk matching is email-led. Define your match precedence before the first import. Use Zendesk's create_or_update endpoint with email as the matching key to deduplicate during import. For contacts with phone numbers but no email, create them with a placeholder identity and merge manually post-migration.

Nested Custom Attribute Dropdowns

Dixa supports nested dropdown options (e.g., "Payment → Card → Visa"). Zendesk dropdown fields are single-level only. Two approaches:

  1. Concatenate levels: "Payment - Card - Visa" in a single dropdown. Works if you have <200 total options (Zendesk's per-field option limit).
  2. Split into multiple fields: "Category" (Payment), "Subcategory" (Card), "Detail" (Visa). More structured but requires three custom fields instead of one.

Conversation Ratings

Dixa's satisfaction ratings may use a different scale than Zendesk's binary good/bad CSAT. Map scores ≥4 (on a 5-point scale) to "good" and <4 to "bad," or store the original numeric score in a custom field to preserve granularity. Document the mapping logic for future reporting accuracy.

Empty Comment Bodies

The Zendesk Ticket Import API rejects comments with empty bodies — even though Zendesk's own UI allows them (e.g., attachment-only messages). Add placeholder text like "(Attachment only)" for these cases. See the error response example above.

Deactivated and Suspended Users

Dixa conversations may be assigned to agents who are no longer active. These agents must exist in Zendesk (can be suspended) before import, or the assignee_id reference will fail. If Dixa contains deleted users that cannot be created in Zendesk, map them to a generic "Deactivated Agent" account and tag the ticket for manual review.

Inline Images

Images embedded directly in the HTML of a message body (not attached as files) will break if the Dixa source URL expires. Parse the HTML, download each image, upload it to Zendesk's Upload API, and rewrite the src tag in the HTML payload to use the new Zendesk URL. This is a separate extraction pipeline — budget 8–16 hours of engineering time if your conversations frequently contain inline images.

Multi-Channel Threads

Dixa allows switching channels (e.g., from email to chat) within a single conversation. Zendesk tickets are generally bound to a single primary channel (set via ticket.via). Append channel metadata to the comment body or store it in a custom field to preserve this context. Example: add [via chat] prefix to comments that originated on a different channel than the ticket's primary channel.

Limitations & Constraints

Constraint Impact
Dixa Exports API: 31-day max query window Multi-year extractions require dozens of sequential API calls
Dixa Exports API: 3 req/min for messages Message extraction is the bottleneck — 200K conversations may take 28+ hours
Dixa does not send Retry-After on 429 Must implement custom exponential backoff
Zendesk import: 100 tickets per batch Fine for most volumes, adds overhead for 1M+ ticket migrations
Zendesk import: no trigger execution Post-import automations will not fire — run manual workflows if needed
Zendesk import: no SLA/metric history Imported tickets do not receive SLA tracking — export historical SLA data from Dixa separately
Zendesk CSAT: binary only Dixa's richer rating data loses granularity unless stored in a custom field
Zendesk offset pagination: 10K record cap Use cursor pagination — offset pagination returns 400 past 10K records (developer.zendesk.com/api-reference/introduction/pagination)
Dixa Flows → Zendesk triggers: no migration path Manual rebuild required — budget 20–40 hours for complex Flow configurations
Dixa Knowledge → Zendesk Guide Separate migration project with its own mapping challenges
Zendesk API token deprecation API tokens being phased out starting July 2026 — use OAuth
Zendesk attachment limit: 50MB per file Call recordings or large files must be hosted externally
Zendesk dropdown options: 200 per field Flattened nested dropdowns may hit this limit

Validation & Testing

A 201 HTTP response confirms the record was accepted — not that the data is correct or complete.

Validation Framework

  1. Record count reconciliation: Compare Dixa conversation count (by status, by channel) against Zendesk ticket count with imported_from_dixa tag. Tolerance: 0% variance — every conversation should be accounted for (migrated, excluded by scope, or logged as error).
  2. Field-level validation: For a random sample of 100+ tickets, compare every mapped field — status, assignee, requester, timestamps, tags, custom fields — against the Dixa source. Automate this with a script that reads both APIs and diffs the values.
  3. Comment threading: Verify message count per ticket and chronological ordering for a sample set. Check that created_at timestamps on comments match the source within 1 second.
  4. Attachment verification: Download and verify file sizes and counts match on sample tickets. Check for broken inline image URLs.
  5. Agent assignment check: Verify assigned agents in Zendesk match the original Dixa assignment. Flag any tickets assigned to the "Deactivated Agent" placeholder.
  6. Private note integrity: Confirm internal notes (including wrap-up notes) migrated and are marked private. Verify they are not visible to end-users.
  7. Custom field values: Verify dropdown values, dates, and numeric fields transferred correctly. Check for empty custom fields that should have values.

Test Migration Protocol

Run at least two full test migrations before production:

  • Test 1: Small subset (1,000 conversations). Validate schema mapping, identify field-level issues. Use your Zendesk sandbox. Expected duration: 1–2 days.
  • Test 2: Full dataset on a Zendesk sandbox. Validate at scale, measure timing, identify rate limit bottlenecks. Expected duration: 3–5 days including extraction.
  • Production: Apply lessons from tests. Run during low-traffic hours (typically weekends or overnight). Have rollback plan ready.

Rollback Planning

Zendesk's Ticket Import API creates new records — there is no built-in rollback. Mitigate this:

  • Tag all imported tickets with imported_from_dixa
  • If rollback is needed, bulk-delete tickets by tag via the Zendesk API (DELETE /api/v2/tickets/destroy_many?ids=1,2,3 — batches of 100)
  • Keep Dixa in read-only mode during transition — do not decommission until validation passes
  • Document the rollback procedure and test it during Test 1

For a complete testing framework, review our Post-Migration QA Checklist.

Post-Migration Tasks

Data migration is half the project. Once the data is in Zendesk, you must configure the operational layer.

Rebuild Workflows

Dixa Flows do not migrate. You must manually recreate:

  • Triggers (based on ticket creation/update conditions) — replacing Dixa Flow branches that fire on conversation events
  • Automations (time-based actions) — replacing Dixa Flow timeout and escalation logic
  • SLA policies (response time targets by priority/group) — replacing Dixa's queue-level SLA settings
  • Views (agent-facing filtered ticket lists replacing Dixa queues)
  • Macros (replacing Dixa quick responses/canned replies)
  • Omnichannel Routing rules (replacing Dixa's offer-based queue assignment — see section above)

Knowledge Base Migration

If migrating Dixa Knowledge to Zendesk Guide, treat it as a separate project. Content and hierarchy must be restructured. Key considerations: category/section mapping, article URL redirects, embedded image re-hosting, and multi-language content. See Document360 to Zendesk Guide Migration for comparable KB migration patterns.

User Training

  • Agents need training on Zendesk's view-based workflow (vs. Dixa's offer-based routing). Key behavioral change: Zendesk auto-assigns via Omnichannel Routing rather than presenting conversations for acceptance.
  • Admins need training on trigger/automation creation (vs. Dixa's visual Flow Builder). Budget 4–8 hours for admin training.
  • Reporting users need orientation to Zendesk Explore (vs. Dixa Analytics). Explore uses a different query model — pre-built dashboards cover common metrics, but custom reports require learning the Explore query builder.

Post-Migration Monitoring

Monitor for 2–4 weeks after cutover:

  • Ticket creation rates (ensure nothing is being dropped)
  • Agent assignment distribution (verify Omnichannel Routing is distributing equitably)
  • Custom field population rates (low rates may indicate UI confusion or mapping errors)
  • Suspended Tickets view (catch misconfigured email forwarding — this is the #1 post-migration issue)
  • CSAT score trends (baseline comparison against Dixa historical averages)
  • Broken attachment links and requester mismatches
  • SLA breach rates (compare against Dixa baselines once sufficient new-ticket data accumulates)

If your application links to specific Dixa knowledge base URLs, set up 301 redirects to the new Zendesk Guide URLs. Create a redirect mapping table before decommissioning Dixa Knowledge.

Best Practices

  1. Back up everything first. Export a full Dixa data dump before starting. Store it independently of both platforms in a location that meets your data residency requirements.
  2. Always sandbox first. Run a full extraction and load tickets into a Zendesk Sandbox environment before touching production. Know your sandbox's ticket limit and refresh schedule.
  3. Create an ID mapping table. Persist every Dixa ID → Zendesk ID mapping. You need it for validation, debugging, delta syncs, and post-migration patching.
  4. Tag imported records. Add imported_from_dixa to every ticket. This enables validation queries, reporting exclusions, and rollback.
  5. Migrate contacts before conversations. Zendesk requires valid requester_id and assignee_id references. Load users first, build the ID map, then load tickets.
  6. Handle the message export bottleneck. Dixa's 3 req/min message export limit is the slowest part of extraction. Start this process days before your planned cutover.
  7. Freeze Dixa configuration. Impose a change freeze on Dixa tags, custom fields, and agent roles two weeks before the migration.
  8. Don't migrate everything. Abandoned conversations, spam, and test data add noise. Define scope filters early.
  9. Preserve Dixa access post-cutover. Keep Dixa in read-only mode for 30–90 days so agents can reference conversations that may not have migrated cleanly.
  10. Separate history migration from workflow redesign in your project plan. They are different workstreams with different owners.
  11. Validate incrementally after every batch instead of waiting for final cutover.
  12. Run a pilot batch with real, messy records — not clean demo data. The first test always surfaces mapping issues you did not anticipate.

Automation Script Structure

High-level directory structure for a production API-based migration:

extract/
  dixa_conversations.py
  dixa_messages.py
  dixa_notes.py
  dixa_files.py
 
transform/
  map_orgs.py
  map_users.py
  map_tickets.py
  normalize_tags.py
  build_crosswalk.py
 
load/
  zendesk_orgs.py
  zendesk_users.py
  zendesk_uploads.py
  zendesk_ticket_import.py
  poll_jobs.py
 
qa/
  counts.py
  field_diff.py
  attachment_check.py
  uat_samples.py
 
state/
  id_map.sqlite
  dead_letter.jsonl
  import_batches.json
Tip

This is a structural outline. A production implementation needs retry logic with exponential backoff, persistent state tracking (so you can resume after failures), concurrent extraction where rate limits allow, and comprehensive error logging. Budget 2–3 weeks of engineering time for a production-grade implementation.

Making the Right Call

A Dixa-to-Zendesk migration is a well-defined, moderate-complexity project. The data transfer path is clear: Dixa's APIs export cleanly, and Zendesk's Ticket Import API is purpose-built for historical ingestion. The challenges are the Dixa Exports API rate limits (which make extraction slow for large datasets — 100K conversations takes roughly 28+ hours for message extraction alone), the workflow redesign (which is entirely manual and typically requires 20–40 hours for complex Flow configurations), and the edge cases that surface only during test migrations — phone conversations without text bodies, nested dropdown flattening, empty comment bodies, inline image URL expiration, and deactivated agent references.

For teams with engineering bandwidth and <50K conversations, a custom API-based migration is achievable in 2–4 weeks. For larger datasets, complex Flow configurations, or tight timelines, a managed service compresses the timeline and reduces engineering risk.

For more on Zendesk migration planning, see Zendesk Migration Checklist and Best Zendesk Migration Service Providers in 2026.

Frequently Asked Questions

How long does a Dixa to Zendesk migration take?
For ~100K conversations, expect 3–6 weeks total: 1 week for planning and data audit, 1–2 weeks for test migrations and field mapping, and 1–2 weeks for production migration and validation. The Dixa Exports API rate limit (3 req/min for messages) is the primary time constraint for data extraction.
Can I preserve timestamps when migrating from Dixa to Zendesk?
Yes. Zendesk's Ticket Import API (POST /api/v2/imports/tickets/create_many) lets you set created_at, updated_at, solved_at on tickets and created_at on individual comments. The standard ticket creation API does not support this — you must use the import endpoint.
Does Zendesk run triggers on imported tickets?
No. Tickets created via the Ticket Import API do not fire triggers, automations, or notifications. This is by design and prevents duplicate emails during migration. Triggers only resume on subsequent updates to imported tickets that are not in closed status.
What Dixa data cannot be migrated to Zendesk?
Dixa Flows (routing logic) have no automated migration path and must be rebuilt as Zendesk triggers, automations, and SLA policies. Call recordings require external hosting. Nested custom attribute dropdowns must be flattened. Dixa's satisfaction rating granularity may be lost since Zendesk uses binary good/bad CSAT.
What are the Dixa API rate limits for data export?
The Dixa Exports API allows 10 requests per minute for conversations and 3 requests per minute for messages, with each query limited to a 31-day window. The Dixa API v1 (for contacts, tags, etc.) allows 10 requests per second per token with a daily ceiling of 864,000 requests. Dixa does not send a Retry-After header on 429 responses.

More from our Blog

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

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

Ensure your help desk migration is a success with this comprehensive 20-point post-migration QA checklist. This expert guide details the 20 essential tests needed to validate your data integrity, system functionality, user-friendliness, and performance . Learn exactly how to check everything from ticket data, attachments, and knowledge base articles to critical workflows, automations, and integrations before you go live. This process is your final line of defense against lost tickets, broken workflows, and unhappy customers.

Raaj Raaj · · 8 min read
Zendesk Migration Checklist
Checklist/Zendesk

Zendesk Migration Checklist

Complete Zendesk migration checklist with pre-migration planning, API-based data transfer, manual setup, and post-migration validation steps

Tejas Mondeeri Tejas Mondeeri · · 4 min read