---
title: "Dixa to Salesforce Service Cloud Migration: Technical Guide"
slug: dixa-to-salesforce-service-cloud-migration-technical-guide
date: 2026-08-05
author: Nachi
categories: [Dixa, Salesforce Service Cloud, Migration Guide]
excerpt: "Technical guide to migrating from Dixa to Salesforce Service Cloud — covering API extraction, data mapping, field limits, Bulk API loading, and workflow rebuild."
tldr: "Dixa conversations extract via Exports API (31-day windows, 10 req/sec). Load into Salesforce as Cases + EmailMessages via Bulk API 2.0. The workflow rebuild — Dixa Flows to Salesforce routing and rules — takes 40–60% of total effort."
canonical: https://clonepartner.com/blog/dixa-to-salesforce-service-cloud-migration-technical-guide/
---

# Dixa to Salesforce Service Cloud Migration: Technical Guide


# Dixa to Salesforce Service Cloud Migration: Technical Guide

> [!NOTE]
> **TL;DR — Dixa to Salesforce Service Cloud Migration**
>
> Dixa conversations export via the Exports API (31-day query windows, 10 requests/second per token). The critical mapping decision: store conversation history as **EmailMessages** (up to 131,072 characters by default, configurable to 384,000) rather than **CaseComments** (hard 4,000-character truncation — silent, no error returned). Dixa's flat conversation model must be translated into Salesforce's Account → Contact → Case hierarchy. Preserving historical timestamps requires enabling "Set Audit Fields upon Record Creation" (org-level Setup) **and** assigning the "Set Audit Fields" user permission to the API user's profile or permission set — both steps are required. Dixa's Flow Builder logic must be rebuilt across Salesforce's distributed configuration model (Assignment Rules, Omnichannel Routing, Entitlement Processes, Flow Builder). Voice recordings should be offloaded to external storage (AWS S3) with URLs mapped to Cases. Use Salesforce Bulk API 2.0 for the data load — it handles up to 100 million records per 24-hour period and doesn't consume your org's REST API quota. Realistic timeline: **3–6 weeks** depending on volume and Flow complexity.

A Dixa to Salesforce Service Cloud migration moves your operations from a specialized, real-time routing platform into an enterprise CRM. Teams undertake this because the rest of the organization already runs on Salesforce, and maintaining a separate data silo for support creates reporting blind spots, duplicate contact records, and integration overhead.

The data transfer is manageable — Dixa's APIs stream conversation and message data in JSON. But the target side has real constraints: CaseComment bodies cap at 4,000 characters with silent truncation, CreatedDate is read-only by default and requires two separate configuration steps to override, and Salesforce governor limits affect large-scale inserts in ways that aren't obvious until you hit them. The workflow redesign is the harder half: Dixa's single-canvas Flow Builder must be decomposed into Salesforce triggers, assignment rules, escalation rules, SLA policies, and Omnichannel Routing configurations.

This guide covers the architectural differences, API constraints, data mapping, transformation logic, load strategy, failure modes, and cutover plan required to execute this migration accurately.

For a deep dive into extracting data from Dixa, see [How to Export Data from Dixa: Methods, API Limits & Data Mapping](https://clonepartner.com/blog/blog/how-to-export-data-from-dixa-methods-api-limits-data-mapping/). For Salesforce import strategies, see [How to Export Data from Salesforce Service Cloud: Methods & Limits](https://clonepartner.com/blog/blog/how-to-export-data-from-salesforce-service-cloud-methods-limits/). If you are evaluating Zendesk as an alternative target, see our [Dixa to Zendesk Migration Guide](https://clonepartner.com/blog/blog/how-to-migrate-from-dixa-to-zendesk-the-complete-guide/).

## Why Teams Migrate from Dixa to Salesforce Service Cloud

The move is driven by concrete architectural constraints, not preference:

- **CRM consolidation.** Running Dixa alongside Salesforce creates duplicate contact records, broken pipeline-to-support reporting, and manual data syncing. Service Cloud resolves this by putting support, sales, and success data on a single customer record.
- **Enterprise reporting.** Salesforce Reports and Dashboards support cross-object joins and custom report types. Dixa's analytics are conversation-scoped; they cannot join to opportunity or account data without an external integration.
- **Compliance requirements.** Salesforce offers HIPAA BAA eligibility, FedRAMP authorization (Government Cloud), and Shield Platform Encryption. Dixa holds SOC 2 Type II and GDPR compliance but does not publicly offer HIPAA or FedRAMP paths.
- **Platform extensibility.** Salesforce AppExchange offers thousands of managed packages with native data access. Dixa's integration ecosystem is smaller and requires webhook-based data extraction.
- **AI depth.** Salesforce Einstein for Service — case classification, next-best-action, article recommendations — operates across your full CRM dataset. Dixa's automation is strong within conversations but doesn't extend to CRM-wide context.

## Architectural Differences That Shape the Migration

Three structural gaps between Dixa and Salesforce define the migration complexity.

### Offer-Based Routing vs. Omnichannel Routing

Dixa pushes conversations to agents in real time based on availability, skills, and priority. Salesforce Omnichannel Routing is conceptually similar but requires explicit setup: Service Channels, Routing Configurations, Presence Statuses, and either queue-based or skill-based routing rules.

Omnichannel supports two routing models:
- **Least Active** — Routes to the agent with the fewest open work items. Best for chat and case workloads.
- **Most Available** — Routes to the agent with the most remaining capacity relative to their configured capacity. Better for high-volume environments where capacity weighting matters.

To replicate Dixa's priority-weighted routing, set the Priority value on each Routing Configuration (lower number = higher priority) and configure queue capacity limits to control maximum concurrent work items per agent. Dixa's automatic priority escalation (conversations that age in queue gain priority) maps to Salesforce's Escalation Rules combined with flow-based field updates on the Case's `Priority` field.

### Flow Builder vs. Distributed Configuration

Dixa's Flow Builder is a visual canvas where queue assignment, IVR trees, auto-replies, priority rules, and escalation paths exist in a single interface. In Salesforce, the same logic spans multiple objects: Assignment Rules, Escalation Rules, Entitlement Processes, Salesforce Flow Builder, Apex Triggers, and Omnichannel Routing Configurations. Expect the workflow rebuild to consume 40–60% of your total migration effort — this estimate reflects the decomposition of a single Dixa Flow that may contain 15–20 decision nodes into 4–6 separate Salesforce configuration objects.

### Native Voice vs. Service Cloud Voice

Dixa includes native telephony — phone, IVR, callback queuing, and call recording built in. Salesforce requires **Service Cloud Voice** (an add-on SKU built on Amazon Connect) or a third-party CTI adapter. You cannot natively play back historical Dixa call recordings inside a Salesforce Case without custom development. Budget for Service Cloud Voice setup and licensing separately if your team uses Dixa telephony.

### Data Hierarchy: Flat vs. Relational

Dixa is flat: a User has Conversations. Salesforce is relational: an Account has Contacts, Contacts have Cases, Cases have CaseComments, EmailMessages, and ContentVersions. Every data mapping decision flows from this structural difference—a challenge common to other flat-to-relational moves like [migrating from Intercom to Salesforce Service Cloud](https://clonepartner.com/blog/blog/how-to-migrate-from-intercom-to-salesforce-service-cloud-2026/).

## Dixa to Salesforce Data Mapping

| Dixa Object | Salesforce Object | Notes |
|---|---|---|
| Conversation | Case | One conversation = one Case. Status mapping required (open/pending/closed → picklist values). |
| Message (inbound/outbound) | EmailMessage | Preferred over CaseComment — supports HTML, up to 131K characters default, preserves sender/recipient. |
| Internal Note | CaseComment (IsPublished=false) | Or FeedItem on Case (Chatter). 4,000-character limit on CaseComment applies here too. |
| End User (contact) | Contact | Map email, phone, name. Link to Account if org uses Account hierarchy. |
| Agent | User | Match by email. Salesforce Users must exist before Case import. |
| Queue | Queue | Configured in Setup. Map Dixa queue names to Salesforce Queue DeveloperNames. |
| Tag | Case Topic or Custom Field | Topics allow multiple tags per record. Tags indicating specific processes (e.g., "Refund Requested") should map to custom fields for reporting. |
| Custom Attribute (conversation) | Custom Field on Case | Text → Text, Select → Picklist. |
| Custom Attribute (end user) | Custom Field on Contact | Same approach. |
| CSAT Rating | Custom Number Field on Case | Salesforce has no native CSAT field. Create `CSAT_Score__c` (Number) and `CSAT_Date__c` (Date). |
| Conversation Wrap-Up Note | CaseComment or Custom Field | Wrap-up notes are separate from message-level internal notes in Dixa's data model. |
| Attachment | ContentVersion → ContentDocumentLink | Files use the ContentVersion/ContentDocument model. Link via ContentDocumentLink to parent Case. |
| Knowledge Article | Knowledge__kav | Requires Record Types and Data Categories setup before import. PublishStatus must be set explicitly or articles import as Drafts. |

### Users to Contacts and Accounts

Dixa `End Users` map to Salesforce `Contacts`. Salesforce Contacts must belong to `Accounts`. If your Dixa instance lacks company-level data, you have two options:

- Create a generic "Unclassified" Account to house orphaned Contacts.
- Enable Person Accounts (a one-way, irreversible org change — recommended only for B2C organizations with no B2B use cases).

### CaseComment vs. EmailMessage: The Correct Choice

`CaseComment.CommentBody` has a hard limit of **4,000 characters**. Salesforce silently truncates content that exceeds this — no API error, no warning, no truncation flag in the response. Content is permanently lost with no indication it happened. If you're loading 18-message email threads concatenated into a single CaseComment, you will lose data without knowing it.

Map Dixa messages to **`EmailMessage`** instead. It supports `HtmlBody` and `TextBody` up to **131,072 characters by default**, configurable to **384,000 characters** at the org level. It preserves sender/recipient addresses, headers, and HTML formatting. Use `CaseComment` with `IsPublished=false` for internal notes, accepting the 4,000-character limit (internal notes are typically shorter).

**What broken CaseComment data looks like in production:** A 6,200-character email thread appears in Salesforce as 4,000 characters ending mid-sentence. Agents see a complete message in the UI. There is no visual indicator of truncation. You discover the loss during a customer dispute when the agent cannot find context that existed in Dixa. Post-migration validation queries (see below) are the only reliable way to detect this before it matters.

> [!WARNING]
> **Check your org's EmailMessage limit before migration.** The default `HtmlBody` limit is 131,072 characters. Orgs with very large historical email threads should verify this limit via a test insert before running bulk loads.

## How to Extract Data from Dixa

### Extraction Timing: The Math

Before writing code, calculate your extraction timeline. With a 31-day query window and 10 requests/second rate limit:

- **3 years of history** = 36+ sequential API calls per endpoint (conversations + messages = 72+ calls minimum)
- **At 10 req/sec with typical response times of 2–4 seconds per call** (network + server processing), a full historical export takes approximately 5–15 minutes of wall-clock time for the API calls themselves
- **The bottleneck is data volume per call**, not request rate. A call returning 50,000 conversations may take 8–12 seconds. At 100K conversations across 3 years, plan for 30–90 minutes of extraction time including pagination and retry overhead
- **Attachments are separate.** Binary file downloads from Dixa's CDN URLs are not subject to the same rate limit but add significant time proportional to file count and size

### Exports API (Recommended for Bulk Extraction)

The Dixa Exports API (`exports.dixa.io`) streams conversation and message data as JSON arrays.

- **`/v1/conversation_export`** — Returns conversation metadata: IDs, status, channel, queue, agent, timestamps, tags, custom attributes, wrap-up notes.
- **`/v1/message_export`** — Returns individual messages with content, direction, author, and timestamps.

Key constraints:
- **31-day query window.** Each request requires `created_after` and `created_before` parameters spanning no more than 31 days.
- **Internal notes are not in the message export.** They live under `conversation_wrapup_notes` in the conversations endpoint, or via `GET /v1/conversations/{id}/notes` on the REST API.
- **Rate limit: 10 requests/second per token**, burst allowance of 4, daily ceiling of 864,000 requests per token. No `Retry-After` header on HTTP 429 responses — implement exponential backoff starting at 1 second, doubling to a max of 30 seconds.
- **Rate limits are per token, not per organization.** Splitting work across multiple API tokens increases total throughput proportionally.

```bash
curl -u "bearer:<API_TOKEN>" \
  "https://exports.dixa.io/v1/conversation_export?created_after=2025-01-01&created_before=2025-01-31"
```

**What a Dixa 429 response looks like:**
```json
HTTP/1.1 429 Too Many Requests
Content-Type: application/json

{"error": "rate_limit_exceeded", "message": "Too many requests"}
```
No `Retry-After` header is included. Your script must track its own request cadence and implement backoff independently.

### REST API (For Record Hydration)

The Dixa REST API at `https://dev.dixa.io/v1` (not `app.dixa.io` — that returns 404) provides per-conversation retrieval: `GET /v1/conversations/{id}/messages`, internal notes, ratings, tags, and custom attributes. Use this to hydrate individual conversations with data the Exports API omits.

Pagination is cursor-based (`pageToken` and `limit`, max 100 per page).

### CSV Export (Validation Only)

Dixa's in-app CSV export provides conversation metadata — queue, agent, timestamps, ratings, tags — but **does not include message content**. Use it to validate record counts before and after migration, not as a primary extraction path.

### Handling Attachments and Inline Images

Dixa stores attachments as CDN URLs within conversation parts. Migration process:

1. Parse Dixa message bodies for attachment URLs.
2. Download binary files to your migration server.
3. Upload to Salesforce as `ContentVersion` records.
4. Salesforce automatically generates a `ContentDocument`.
5. Create `ContentDocumentLink` records to tie files to Cases or EmailMessages.

**Do not migrate Dixa URLs as plain text into Salesforce fields.** Dixa CDN URLs expire or become inaccessible after contract termination.

**Inline base64 images require special handling.** Dixa occasionally stores inline images as base64-encoded strings in HTML message bodies. If loaded as-is into `EmailMessage.HtmlBody`, these strings can push individual records over the 131,072-character limit, causing the API call to fail with:

```json
{"errorCode": "STRING_TOO_LONG", "message": "HtmlBody: data value too large"}
```

Your transformation layer must: parse the HTML body for `<img src="data:image/...;base64,...">` tags, extract and decode the base64 string, save it as a binary file, upload it as a `ContentVersion`, and rewrite the `<img>` tag to reference the new Salesforce file URL.

## Transformation Layer: JSON to Salesforce

The extraction scripts produce JSON. The Salesforce Bulk API 2.0 expects CSV. The transformation layer between them is where most migration bugs occur.

### Conversation to Case + EmailMessages

```python
# Pseudocode: transform Dixa conversation JSON to Salesforce load format

def transform_conversation(conv, messages, queue_map, user_map):
    case = {
        "Dixa_Conversation_Id__c": conv["id"],          # External ID
        "Subject": conv.get("subject", f"Conversation {conv['id']}"),
        "Status": map_status(conv["status"]),            # "open" → "New", "closed" → "Closed"
        "Origin": map_channel(conv["channel"]),          # "email" → "Email", "chat" → "Chat"
        "OwnerId": queue_map.get(conv["queue_id"]),      # Salesforce Queue ID
        "ContactId": user_map.get(conv["end_user_id"]), # Salesforce Contact ID
        "CreatedDate": conv["created_at"],               # Requires "Set Audit Fields" permission
        "ClosedDate": conv.get("ended_at"),
        "CSAT_Score__c": conv.get("csat_rating"),
        "Description": conv.get("wrap_up_note", "")[:32768]  # Case description limit
    }

    email_messages = []
    for msg in messages:
        body_html = clean_inline_images(msg.get("html_body", ""))
        body_text = msg.get("text_body", "")

        # Enforce character limits before load
        if len(body_html) > 131072:
            body_html = body_html[:131072]  # Log truncation for review
        
        email_messages.append({
            "Dixa_Message_Id__c": msg["id"],             # External ID on EmailMessage
            "ParentId": None,                            # Populated after Case insert
            "FromAddress": msg["author_email"],
            "ToAddress": msg.get("recipient_email", ""),
            "Subject": conv.get("subject", ""),
            "HtmlBody": body_html,
            "TextBody": body_text[:32768],
            "MessageDate": msg["created_at"],
            "Incoming": msg["direction"] == "inbound",
            "Status": "0"                                # 0 = New
        })

    return case, email_messages
```

### Salesforce CSV Format for EmailMessage Bulk Upsert

```csv
Dixa_Message_Id__c,ParentId,FromAddress,ToAddress,Subject,TextBody,MessageDate,Incoming,Status
msg_001,5001A00001XyzABC,customer@example.com,support@yourcompany.com,Order #1234,Message content here,2024-01-15T14:23:11Z,true,0
```

The `ParentId` column uses the Salesforce Case `Id` — not the External ID — because EmailMessage does not support polymorphic External ID references in Bulk API 2.0. Insert Cases first, store the returned Salesforce IDs in your mapping database, then populate `ParentId` before loading EmailMessages.

## How to Load Data into Salesforce Service Cloud

### Step 1: Prepare the Salesforce Org

Before loading any data:

- **Create custom fields** on Case and Contact: `Dixa_Conversation_Id__c` (Text, External ID, Unique), `Dixa_EndUser_Id__c` (Text, External ID, Unique), `CSAT_Score__c` (Number), `CSAT_Date__c` (Date).
- **Create a `Dixa_Message_Id__c` External ID field on EmailMessage** for idempotent message upserts.
- **Set up Queues** in Salesforce matching your Dixa queue structure.
- **Enable "Set Audit Fields upon Record Creation"** in Setup → User Interface → **and** assign the "Set Audit Fields" permission to the API user's profile or a dedicated permission set. Both steps are required — enabling the org setting without the user permission produces no error but `CreatedDate` remains today's date.
- **Disable automation temporarily.** Turn off assignment rules, escalation rules, auto-response rules, and Apex triggers that fire on Case insert. 100K Case inserts triggering email notifications will exhaust your org's daily email sending limits and create noise in your monitoring.

> [!TIP]
> **Use a sandbox first.** Always run the full migration in a Salesforce sandbox before touching production. Sandbox orgs get the same API limits as production, including Bulk API 2.0 capacity and governor limits.

### Step 2: Load in Strict Relational Order

Salesforce enforces referential integrity at insert time. Load order is non-negotiable:

1. **Accounts** — Store returned Salesforce `Id` values in your mapping database.
2. **Contacts** — Upsert on `Dixa_EndUser_Id__c`. Map to Account `Id`.
3. **Cases** — Upsert on `Dixa_Conversation_Id__c`. Map to Contact `Id` and Account `Id`.
4. **EmailMessages** — Insert with `ParentId` = Salesforce Case `Id` (from step 3 results).
5. **CaseComments** — Insert internal notes with `ParentId` = Salesforce Case `Id`, `IsPublished = false`.
6. **ContentVersions** — Insert attachment files.
7. **ContentDocumentLinks** — Link ContentDocuments to Cases or EmailMessages.

### Salesforce Governor Limits That Affect Migration

Beyond daily API quotas, these governor limits affect large-scale inserts and cause failures that aren't obvious until you hit them:

- **Heap size limit: 6 MB (synchronous), 12 MB (asynchronous).** Apex triggers firing during insert (even disabled ones that escape your shutdown) will fail if they attempt to process large record sets in a single transaction. Verify all triggers are disabled before bulk loads.
- **CPU time limit: 10,000ms (synchronous), 60,000ms (asynchronous).** Complex before/after insert triggers on Case can hit CPU limits during Bulk API jobs. Bulk API 2.0 processes records in chunks of 10,000 — each chunk is subject to governor limits independently.
- **DML statements per transaction: 150.** Relevant if any active triggers perform additional DML on Case insert.
- **SOQL queries per transaction: 100.** Triggers querying related records on each Case insert hit this quickly in bulk contexts.

Bulk API 2.0 itself bypasses most synchronous governor limits by executing asynchronously, but any Apex triggers that remain active during the load are subject to them.

For any migration exceeding 10,000 records, use **Salesforce Bulk API 2.0**:
- Processes up to 100 million records per 24-hour period
- Automatically chunks data into internal batches of 10,000 records
- Does **not** count against the org's REST/SOAP daily API limit (Enterprise Edition: 100,000 + 1,000 per user license)
- Supports upsert operations against External ID fields for idempotency

```bash
# Create a Bulk API 2.0 upsert job for Cases
curl -X POST https://yourorg.my.salesforce.com/services/data/v61.0/jobs/ingest \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "object": "Case",
    "operation": "upsert",
    "externalIdFieldName": "Dixa_Conversation_Id__c",
    "contentType": "CSV"
  }'
```

**Bulk API 2.0 error response format** — failed records are returned in a results file, not as API errors:

```csv
sf__Id,sf__Error,Dixa_Conversation_Id__c,Subject
,FIELD_INTEGRITY_EXCEPTION:ContactId does not exist,conv_12345,Order #789
```

Check the results file after every job. A job that reports "Completed" may still have thousands of failed records — completion status reflects job processing, not record success rate.

Bulk API 2.0 ContentVersion jobs are capped at **150 MB** of CSV payload per job. Split attachment-heavy migrations across multiple jobs.

> [!WARNING]
> **CreatedDate requires two configuration steps.** Enable "Set Audit Fields upon Record Creation" in Setup **and** assign the "Set Audit Fields" permission to the API user. Enabling only the org setting produces no error — the API call succeeds, but `CreatedDate` is silently set to the insert timestamp. You will not discover this until you query historical records and find every 2021 ticket shows today's date.

## Post-Migration Validation Queries

Run these SOQL queries after each load phase to verify data integrity before proceeding to the next phase.

```sql
-- Verify Case count matches Dixa export count
SELECT COUNT(Id) FROM Case WHERE Dixa_Conversation_Id__c != null

-- Find Cases with no linked EmailMessages (potential extraction gaps)
SELECT Id, CaseNumber, Dixa_Conversation_Id__c
FROM Case
WHERE Id NOT IN (SELECT ParentId FROM EmailMessage)
AND Status != 'New'
LIMIT 200

-- Detect suspiciously short EmailMessages (possible truncation)
SELECT Id, ParentId, MessageDate, LEN(TextBody)
FROM EmailMessage
WHERE LEN(TextBody) < 100 AND Incoming = true
ORDER BY MessageDate DESC
LIMIT 100

-- Check CreatedDate preservation (sample: Cases should span historical date range)
SELECT MIN(CreatedDate), MAX(CreatedDate), COUNT(Id)
FROM Case
WHERE Dixa_Conversation_Id__c != null

-- Find ContentDocumentLinks missing their parent Case
SELECT Id, LinkedEntityId, ContentDocumentId
FROM ContentDocumentLink
WHERE LinkedEntityId IN (
  SELECT Id FROM Case WHERE Dixa_Conversation_Id__c != null
)
AND ContentDocumentId NOT IN (SELECT Id FROM ContentDocument)
```

Use the Dixa CSV export counts as your baseline. If the CSV shows 87,432 conversations and your Case query returns 87,201, investigate the 231 missing records before cutover.

## Field-Level Constraints and Known Failure Modes

| Constraint | Value | Failure Mode |
|---|---|---|
| CaseComment.CommentBody | 4,000 characters | Silent truncation — no API error, no warning |
| EmailMessage.HtmlBody (default) | 131,072 characters | `STRING_TOO_LONG` API error on insert |
| EmailMessage.HtmlBody (max configurable) | 384,000 characters | Configurable at org level |
| Salesforce daily REST API limit (Enterprise, 50 users) | 150,000 requests | `REQUEST_LIMIT_EXCEEDED` — Bulk API 2.0 uses a separate pool |
| Bulk API 2.0 daily limit | 100M records / 15,000 batches | Separate from REST API quota |
| Bulk API 2.0 ContentVersion job | 150 MB CSV payload | Split into multiple jobs for attachment-heavy loads |
| Dixa Exports API window | 31 days per request | Sequential requests required for multi-year history |
| Dixa rate limit | 10 req/sec per token, 864,000/day | No Retry-After header — implement own backoff |
| Apex synchronous heap size | 6 MB | Triggers fail on large in-memory datasets during insert |
| Apex DML statements per transaction | 150 | Cascading triggers on Case insert can exhaust quickly |

### Additional Edge Cases

- **Agent @mentions.** Dixa allows agents to `@mention` each other using internal Dixa user IDs. When migrated to Salesforce CaseComment, these appear as plain text (`@User1234`). Re-linking to Salesforce Chatter mentions requires regex parsing and Dixa ID → Salesforce User ID mapping during transformation.
- **Call recordings.** Salesforce cannot efficiently store audio files natively. Upload `.wav` or `.mp3` files to AWS S3 and write the secure S3 URL into a custom URL field (`Dixa_Recording_URL__c`) on the Salesforce Case.
- **Agent matching.** If Dixa agents don't exist as Salesforce Users, Cases cannot be assigned to them. Create all agent User records first, or map unresolved agents to a "Migration Import" user and store the original agent name in a custom text field.
- **Side conversations.** Map to related Cases (use a lookup relationship) or to EmailMessages with a custom field flagging them as side conversations.

## Workflow Rebuild: Dixa Flows → Salesforce Configuration

There is no automated translation tool for this. Document every Dixa Flow before touching Salesforce — the visual canvas often obscures nested conditions that aren't obvious until you're rebuilding them.

### Queue Assignment and Routing

Map Dixa Flow routing logic to:
- **Case Assignment Rules** — Route Cases to Queues based on field criteria (origin, priority, custom fields). Handles straightforward branching.
- **Record-Triggered Flows** — For conditional logic that assignment rules can't handle. Consolidate multiple Dixa Flows into a single Record-Triggered Flow on Case using Decision elements.
- **Omnichannel Routing Configurations** — Configure Priority (lower number = higher priority), Capacity, and Routing Model (Least Active or Most Available) per queue.
- **Email-to-Case** — Replaces Dixa's inbound email parsing and creates Cases automatically from inbound email.

### Escalation and SLAs

Dixa's time-based escalation → **Entitlement Processes** and **Milestones** for SLA targets, plus **Escalation Rules** for time-based reassignment and notification when SLAs are at risk.

### IVR Rebuild in Amazon Connect

If using Service Cloud Voice, Dixa IVR nodes map to Amazon Connect Contact Flows:
- **Dixa IVR menu node** → Amazon Connect `Get Customer Input` block
- **Dixa queue transfer node** → Amazon Connect `Transfer to Queue` block
- **Dixa business hours node** → Amazon Connect `Check Hours of Operation` block
- **Dixa callback node** → Amazon Connect `Set Callback Number` + `Transfer to Queue` with callback enabled
- **Dixa text-to-speech prompt** → Amazon Connect `Play Prompt` block with Amazon Polly

Each Dixa IVR tree must be rebuilt as an Amazon Connect Contact Flow. Export Dixa IVR screenshots or documentation before decommissioning.

### Auto-Replies and Macros

Dixa's auto-reply nodes → Salesforce **Auto-Response Rules** (for email channel). Agent shortcut templates → **Quick Text** or **Macros**. Dixa chatbot logic → **Einstein Bots** or a third-party platform (Einstein Bots require a separate license).

### Knowledge Migration

Salesforce Knowledge (`Knowledge__kav`) requires setup before import:
1. Enable Salesforce Knowledge in Setup.
2. Create article Record Types (maps to Dixa knowledge categories).
3. Configure Data Categories and assign them to Knowledge — articles without Data Category assignments are not surfaced in search.
4. Export Dixa articles as HTML.
5. Sanitize HTML — Salesforce's rich text editor rejects malformed tags, unescaped characters, and certain inline styles. Common failures: unclosed `<div>` tags, `style` attributes with unsupported CSS, and `<script>` tags (stripped silently).
6. Set `PublishStatus = 'Online'` explicitly in your load file. Omitting this field or setting it to `null` results in all articles importing as Drafts — not searchable by agents or the self-service portal.

## The Delta Sync and Cutover Strategy

1. **Initial Sync.** Two weeks before go-live, extract all historical Dixa data up to a specific timestamp. Load into Salesforce sandbox for UAT, then production. Captures ~95% of total volume.
2. **Delta Sync.** On cutover weekend, query Dixa for conversations created or modified after the initial sync timestamp. Load the gap data.
3. **Cutover.** Reroute support email addresses (MX record changes — allow 24–48 hours for DNS propagation). Update chat widget endpoints. Reconfigure phone routing. Re-enable assignment rules, escalation rules, and automation. Run the post-migration validation queries. Deactivate Dixa API tokens to prevent split-brain data entry.

For a deeper look at zero-downtime strategies, see [Zero-Downtime Help Desk Data Migration: How to Keep Support Running During the Move](https://clonepartner.com/blog/blog/zero-downtime-help-desk-data-migration/).

## Migration Timeline

| Phase | Duration | Key Activities |
|---|---|---|
| Discovery & Mapping | 3–5 days | Audit Dixa Flows, tags, custom attributes. Map to Salesforce objects/fields. Identify gaps. |
| Salesforce Org Prep | 3–5 days | Create custom fields, queues, assignment rules, permission sets. Configure Omnichannel. |
| Extraction Script Build | 3–5 days | Build Exports API extraction, REST API hydration for messages/notes/attachments. |
| Test Migration (Sandbox) | 3–5 days | Full load into sandbox. Validate counts, content integrity, timestamps, attachments. Run validation SOQL. |
| Workflow Rebuild | 5–10 days | Rebuild Dixa Flows as Salesforce assignment rules, escalation rules, Omnichannel config, IVR. |
| UAT & Validation | 2–3 days | Agent testing, CSAT spot checks, attachment verification, routing validation. |
| Production Cutover | 1–2 days | Delta sync, final load, DNS/email routing changes, go-live. |

**Total: 3–6 weeks** for a team of ~30 agents with 100K conversations. Complex Dixa Flows, heavy attachment volumes, or zero-downtime requirements push toward the longer end.

## What Cannot Be Migrated

| Item | Why | Recommended Workaround |
|---|---|---|
| Dixa Flow Builder logic | No export format exists — must be reverse-engineered from the visual canvas | Document each Flow as a decision tree before decommissioning; rebuild as Salesforce Assignment Rules, Flows, and Omnichannel config |
| IVR trees | Dixa IVR configuration is proprietary and has no standard export | Screenshot all IVR nodes; rebuild in Amazon Connect Contact Flows (see IVR node mapping above) |
| Chatbot configurations | Dixa bot logic is not exportable | Rebuild in Einstein Bots or a third-party platform; treat as a net-new bot implementation |
| Real-time analytics dashboards | Dixa dashboard configuration is not transferable | Rebuild as Salesforce Reports/Dashboards; cross-object reporting in Salesforce is more powerful once configured |
| Conversation offer history | Which agent was offered a conversation, accept/decline patterns — no Salesforce equivalent object | Archive as CSV for compliance; not actionable in Salesforce without custom development |
| Side conversations | Dixa side conversations have no direct Salesforce equivalent | Map to related Cases or EmailMessages with a custom `Is_Side_Conversation__c` flag |

## When to DIY vs. Use a Managed Service

**Build it yourself when:**
- Fewer than 20K conversations
- Minimal attachments (< 1,000 files)
- Simple Dixa Flows (1–2 queues, no IVR, no chatbot)
- In-house Salesforce admin and a developer comfortable with Bulk API 2.0 and Python or Node.js data pipelines
- Cutover window of 4+ hours acceptable

**Use a managed migration service when:**
- Conversation volumes exceed 50K with full message history
- Heavy attachment loads (voice recordings, file shares)
- Complex Dixa Flows with multiple queues, IVR, or chatbot paths
- Zero-downtime requirement requiring live sync during cutover
- No in-house Salesforce developer bandwidth
- Compliance requirements demand audit-grade data integrity documentation

## Making the Right Call

A Dixa to Salesforce Service Cloud migration is a medium-to-high complexity project. The data layer is manageable if you respect the constraints on both sides: Dixa's 31-day query windows, 10 req/sec rate limit, and internal notes endpoint; Salesforce's CaseComment truncation, the two-step CreatedDate permission requirement, and governor limits that activate during bulk inserts. The workflow layer is where the real effort lives — rebuilding Dixa Flows into Salesforce's distributed configuration model consumes 40–60% of total project time and requires thorough documentation of the source before you begin.

Start with a sandbox test migration using one month of data. Run the post-migration validation SOQL queries before touching production. Validate record counts, message content integrity (especially truncation), timestamp preservation, and attachment links. Only then plan production cutover.

For a broader view of Salesforce Service Cloud migration planning, see our [Salesforce Service Cloud Migration Checklist](https://clonepartner.com/blog/blog/salesforce-service-cloud-migration-checklist/).

> ClonePartner handles Dixa-to-Salesforce migrations including extraction pipeline build, transformation logic, Bulk API loading, timestamp preservation, and delta sync. Book a 30-minute technical scoping call to get a realistic timeline and cost estimate for your data volume and Flow complexity.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## Frequently asked questions

### Should I use CaseComment or EmailMessage for Dixa conversation history in Salesforce?

Use EmailMessage in almost all cases. CaseComment has a hard 4,000-character limit on CommentBody that silently truncates content. EmailMessage supports up to 131,072 characters by default (configurable to 384,000), preserves HTML formatting, and retains sender/recipient metadata.

### How do I preserve original Dixa timestamps when migrating to Salesforce?

Enable 'Set Audit Fields upon Record Creation' in Salesforce Setup and grant the API user the 'Set Audit Fields' permission. Without this, all migrated Cases will show the import date as their CreatedDate, destroying your historical timeline and SLA reporting.

### Can Dixa Flows be migrated to Salesforce automatically?

No. Dixa Flows use proprietary visual routing logic with no export format. You must reverse-engineer each Flow from the visual canvas and rebuild the logic manually using Salesforce Assignment Rules, Escalation Rules, Omnichannel Routing, and Flow Builder.

### How long does a Dixa to Salesforce Service Cloud migration take?

A typical migration takes 3–6 weeks, including data mapping, Salesforce org prep, test migration in a sandbox, workflow rebuild, UAT, and production cutover. The workflow redesign (Dixa Flows → Salesforce configuration) is usually the longest phase at 5–10 days.

### Can I migrate Dixa call recordings to Salesforce?

Salesforce is not designed to store large audio files natively. The standard practice is to extract Dixa recordings, host them in AWS S3 or similar external storage, and write the secure URL into a custom URL field on the Salesforce Case.
