Skip to content

SolarWinds Service Desk to Dixa Migration: Technical Guide

Technical guide for migrating from SolarWinds Service Desk to Dixa. Covers ITSM-to-conversation data mapping, API extraction, rate limits, and edge cases.

Abdul Abdul · · 20 min read
SolarWinds Service Desk to Dixa Migration: 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

SolarWinds Service Desk to Dixa Migration: Technical Guide

Info

TL;DR — SolarWinds Service Desk to Dixa Migration

Migrating from SolarWinds Service Desk (SWSD) to Dixa is a structural transformation: you're flattening an ITIL-centric service management platform into a conversation-first omnichannel routing system. Only SWSD incidents (and their comments) map to Dixa conversations. Problems, changes, releases, assets, CMDB records, and service catalog items have no Dixa equivalent and must be archived or left behind. The SWSD REST API (api.samanage.com) uses offset pagination with a max page size of 200 and does not publicly document rate-limit thresholds. Dixa's import endpoint supports only email and genericapimessaging channel types, enforces 10 requests/second per token, and has no idempotency — duplicate submissions create duplicate conversations. Dixa API access requires the Ultimate or Prime plan. A typical migration for 50,000–150,000 incidents takes 3–5 weeks including mapping, test runs, and cutover.

Written 2025. Targets SWSD API v2.1 and Dixa API v1.

What Is a SolarWinds Service Desk to Dixa Migration?

A SolarWinds Service Desk to Dixa migration extracts incidents, users, comments, attachments, and custom fields from SWSD and loads them into Dixa's conversation-based data model. The goal is to preserve customer interaction history so agents in Dixa can reference prior exchanges.

This is not a like-for-like helpdesk swap. SWSD is built on an ITIL framework — the core object is the Incident, linked to a relational database of assets (CMDB), problems, changes, and approval workflows. Dixa is a conversation-centric routing engine. Its core object is the Conversation, which prioritizes chronological message history and real-time agent routing over rigid categorizations and state-machine approvals.

Every technical decision in this migration stems from this structural mismatch. You must flatten SWSD's relational incident data into linear conversation threads and accept that the ITSM objects around them cannot follow.

For a detailed guide on getting data out of SWSD, see How to Export Data from SolarWinds Service Desk: Methods & Limits.

Platform Capability Delta: SWSD vs. Dixa

Before committing to this migration, review the capability gap. This table is a prerequisite check, not a migration mapping — it answers whether Dixa can replace SWSD for your use case.

Capability SWSD Dixa
Incident/ticket management ✅ (as Conversations)
CMDB / Asset management
Problem management
Change management
Release management
Service catalog with approval workflows
ITIL-compliant state machine
Omnichannel push routing (phone, email, chat, social)
Visual conversation flow builder ✅ (Flows)
Unified agent workspace (all channels, one view)
Intelligent queue-based routing Limited
Native voice (telephony)
Knowledge base
SLA management ✅ (rebuild required)
Automation rules ✅ (rebuild as Flows)
API access on base plan No (Advanced+ only) No (Ultimate/Prime only)

Decision threshold: If your team uses CMDB, problem-incident linking, change advisory boards, or multi-stage service catalog approvals — Dixa is not a viable target. These are hard capability gaps, not configuration differences.

Data Model Mapping: SWSD → Dixa

The structural gap between these platforms is the defining challenge. Here's what maps, what doesn't, and what requires transformation.

SWSD Object Dixa Equivalent Migration Path
Incidents Conversations Core migration target. Each incident becomes one conversation.
Incident comments Messages Public comments → inbound/outbound messages. Private comments → internal notes (post-import).
Users (requesters) End Users Create via POST /v1/endusers before importing conversations.
Users (technicians) Agents Must exist in Dixa before import. Provision manually or via SCIM.
Groups Queues / Teams Queues for routing; Teams for organizational grouping.
Categories Tags Flatten SWSD's category hierarchy into Dixa tags.
Custom fields Custom Attributes SWSD multi-level dropdowns become flat custom attributes.
Attachments Attachment URLs Dixa downloads from URLs in the import payload — must be persistent.
Problems ❌ No equivalent Archive to CSV/database. Not importable.
Changes ❌ No equivalent Archive to CSV/database. Not importable.
Releases ❌ No equivalent Archive to CSV/database. Not importable.
Assets / CMDB ❌ No equivalent Archive to CSV/database. Not importable.
Service Catalog ❌ No equivalent Rebuild relevant items as Dixa contact forms if needed.
Solutions (KB) Dixa Knowledge Base Must be recreated manually — no bulk import API for KB.
SLA Policies Dixa SLAs Rebuild manually. Not migrated via API.
Automations Dixa Flows Rebuild manually. No export/import path.
Danger

What you lose permanently: SWSD's problem-incident linking, change approval workflows, release tracking, CMDB dependencies, and asset lifecycle management have zero representation in Dixa. If your team relies on these, Dixa is not the right target platform. If you need to move ITSM data to another ITSM platform, see How to Migrate from SolarWinds Service Desk to ServiceNow.

Extracting Data from SolarWinds Service Desk

The primary extraction path is the SWSD REST API (Samanage API). The base URL depends on your region:

  • US: https://api.samanage.com
  • EU: https://apieu.samanage.com
  • APJ: https://apiau.samanage.com

API access on SWSD requires the Advanced ($79/tech/month) or Premier ($99/tech/month) plan. The Essentials plan ($39/tech/month) does not include API access.

Authentication

SWSD uses bearer token authentication via JSON Web Tokens (JWT). Only administrators can generate tokens — navigate to Setup → Users & Groups → Users, select the admin user, then Actions → Generate JSON Web Token. The token inherits the permissions of the generating user.

curl -H "Accept: application/vnd.samanage.v2.1+json" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     "https://api.samanage.com/incidents.json?per_page=100&page=1&sort_by=updated_at&sort_order=ASC"

Pagination and Rate Limits

SWSD uses offset-based pagination with page and per_page query parameters. The maximum page size is 200 records. There is no cursor-based pagination, so deep pages on large datasets slow down as the database must scan and skip earlier rows on each request. Sort by updated_at ascending to ensure you can resume extraction if your script fails mid-run — any records updated after your last successful page can be re-queried with a updated_at_gte filter.

SWSD does not publicly document specific rate-limit thresholds and does not return standard rate-limit response headers (X-RateLimit-Remaining, Retry-After). In practice, sustained calls at 2–3 requests/second are typically stable, but this is operational experience, not a documented guarantee. Build in backoff logic and monitor for 429 responses. If you hit a 429, implement exponential backoff starting at 5 seconds — there is no header to tell you how long to wait.

Key Extraction Endpoints

Endpoint Method Purpose
/incidents.json GET List all incidents (paginated)
/incidents/{id}.json GET Single incident with full detail
/incidents/{id}/comments.json GET Comments (messages) for an incident
/users.json GET All users (requesters + technicians)
/groups.json GET Agent groups
/categories.json GET Category tree
/custom_fields.json GET Custom field definitions
/attachments/{id}.json GET Attachment metadata

Extract in this order: users, groups, categories, custom field definitions, incidents, comments per incident, and attachments. Store raw JSON in a staging database (PostgreSQL, SQLite, or flat files) for transformation. This sequencing matters — you need user and category lookups before you can transform incident payloads.

import requests
import time
 
BASE_URL = "https://api.samanage.com"
HEADERS = {
    "Accept": "application/vnd.samanage.v2.1+json",
    "Authorization": "Bearer YOUR_JWT_TOKEN"
}
 
def extract_incidents(per_page=100):
    page = 1
    all_incidents = []
    while True:
        resp = requests.get(
            f"{BASE_URL}/incidents.json",
            headers=HEADERS,
            params={"per_page": per_page, "page": page,
                    "sort_by": "updated_at", "sort_order": "ASC"}
        )
        if resp.status_code == 429:
            time.sleep(5)
            continue
        resp.raise_for_status()
        data = resp.json()
        if not data:
            break
        all_incidents.extend(data)
        page += 1
        time.sleep(0.5)  # conservative pacing at ~2 req/s
    return all_incidents

The Attachment Trap

One of the most common failure points in a SWSD migration involves attachments. When you query an incident, the API returns URLs for attached files. SWSD serves attachments from AWS S3 using pre-signed URLs with expiration windows — in practice, these URLs expire within 60 minutes of generation. If you extract all your incident JSON first and attempt to download attachments a day later, every URL will return HTTP 403 Forbidden.

This behavior is consistent across SWSD accounts but is not explicitly documented in the official API reference. The URL pattern (amazonaws.com with X-Amz-Expires or Expires query parameters) confirms the signed URL mechanism.

The fix: Your extraction script must download each attachment file immediately upon parsing the incident JSON — in the same extraction pass, not a subsequent one. Store files in your own intermediate storage (S3, GCS, or Azure Blob) and map the new persistent URL to your Dixa import payload. Dixa downloads attachments from the URLs you provide during import, so those URLs must remain accessible for the full duration of the migration window.

Inline Images in Incident Descriptions

SWSD incident descriptions and comments may contain inline images embedded as base64-encoded <img> tags (e.g., <img src="data:image/png;base64,...">). These will not render in Dixa when submitted via the import API — Dixa does not decode base64 image data in message bodies.

Your transform script must:

  1. Parse the HTML content for <img> tags with base64 src attributes
  2. Decode and upload the image to persistent storage (S3, GCS, etc.)
  3. Replace the src attribute with the new public URL before passing the content to Dixa

Failing to handle this results in broken image placeholders visible to agents in every affected conversation.

Tip

Alternative extraction: SWSD supports CSV export from index pages (Analytics → Data Export) for incidents, users, and assets. This is useful for row count validation and cross-referencing, but it does not include comments, internal notes, or attachments. Use the API for the full dataset.

Data Transformation

The transformation layer converts SWSD's incident schema into Dixa's conversation import format. Processing must happen in strict dependency order: users and agents must exist in Dixa before you can reference their IDs in conversation payloads.

Status Mapping

SWSD uses customizable states. Dixa enforces a simplified three-state model. Map accordingly:

SWSD Status Dixa Status
New Open
Assigned Open
In Progress Open
Awaiting Input Pending
On Hold Pending
Resolved Closed
Closed Closed

Incident → Conversation

  • Map SWSD incident.name → Dixa conversation subject
  • Map SWSD incident.description_body → first inbound message (treat as HTML content)
  • Determine channel type: use email for email-originated incidents; use genericapimessaging for portal, phone, and API-originated incidents (see channel type definition below)

Comments → Messages

The SWSD API returns comment visibility via the is_private field on each comment object (boolean). Verify this field name in your specific SWSD instance against a known private comment — SWSD has changed field names between versions and your API response is the ground truth.

  • SWSD comments with is_private: true → Dixa internal notes (added after import via POST /v1/conversations/{id}/notes — do not include in the initial import payload)
  • SWSD comments from requesters (is_private: false) → inbound messages
  • SWSD comments from technicians (is_private: false) → outbound messages
Danger

Private comment leak risk: If you include SWSD private comments as regular messages in your import payload rather than using the separate notes endpoint post-import, those comments will be visible to end users in Dixa. Always handle private comments in a separate post-import pass.

Categories → Tags

SWSD uses a hierarchical category model (Category → Subcategory). Dixa tags are flat strings. Concatenate the full path (e.g., "Hardware > Laptop") to preserve the hierarchy in a queryable form, or create separate tags for each level if you need to filter by top-level category independently.

Custom Fields → Custom Attributes

SWSD supports dropdowns, multi-selects, date fields, and free text. Dixa custom attributes are flat key-value pairs. Multi-select fields must be serialized to a string format before import (e.g., comma-separated: "Windows,macOS"). Date fields should be converted to ISO 8601 format.

User Mapping and Cleaning

In SWSD, a Requester submits the incident. In Dixa, this maps to an End User. Extract all users from /users.json and create them in Dixa before importing conversations — the import payload requires a valid Dixa end user UUID (requesterId).

Watch for these edge cases:

  • Placeholder emails: SWSD requesters with addresses like user@local.domain or noreply@company.internal will fail Dixa's email validation. Normalize or replace these before import.
  • Duplicate emails: SWSD allows multiple users with the same email in some configurations. Dixa deduplicates end users by email — two SWSD users sharing an email collapse to a single Dixa end user. Audit for this before import and decide which user record is canonical.
  • Deleted users: SWSD incidents may reference deactivated or deleted users whose email addresses no longer exist. Create a fallback profile (e.g., deleted-user@migration.internal) and assign orphaned incidents to it. Log all affected incident IDs for post-migration review.

Creating End Users in Dixa Before Import

import requests
 
DIXA_BASE = "https://dev.dixa.io"
DIXA_TOKEN = "YOUR_DIXA_API_TOKEN"
DIXA_HEADERS = {
    "Authorization": f"Bearer {DIXA_TOKEN}",
    "Content-Type": "application/json"
}
 
def get_or_create_end_user(email, display_name):
    """Returns the Dixa end user UUID for the given email, creating if needed."""
    # Check if user already exists
    search_resp = requests.get(
        f"{DIXA_BASE}/v1/endusers",
        headers=DIXA_HEADERS,
        params={"email": email}
    )
    search_resp.raise_for_status()
    results = search_resp.json().get("data", [])
    if results:
        return results[0]["id"]
 
    # Create new end user
    create_resp = requests.post(
        f"{DIXA_BASE}/v1/endusers",
        headers=DIXA_HEADERS,
        json={
            "email": email,
            "displayName": display_name
        }
    )
    create_resp.raise_for_status()
    return create_resp.json()["data"]["id"]

Transformation: Incident → Dixa Import Payload

def transform_incident_to_dixa(incident, comments, user_map, agent_map):
    requester_email = incident["requester"]["email"]
    dixa_requester_id = user_map.get(requester_email)
 
    messages = []
    # First message from the incident description
    messages.append({
        "content": {"value": incident.get("description_body", ""), "_type": "Html"},
        "attachments": [],
        "_type": "Inbound",
        "createdAt": incident["created_at"]
    })
 
    for comment in sorted(comments, key=lambda c: c["created_at"]):
        if comment.get("is_private"):
            continue  # Handle as internal notes in a separate post-import pass
        is_agent = comment["user"]["email"] in agent_map
        msg = {
            "content": {"value": comment["body"], "_type": "Html"},
            "attachments": [],
            "_type": "Outbound" if is_agent else "Inbound",
            "createdAt": comment["created_at"]
        }
        if is_agent:
            msg["agentId"] = agent_map[comment["user"]["email"]]
        messages.append(msg)
 
    return {
        "requesterId": dixa_requester_id,
        "emailIntegrationId": "your-support@email.dixa.io",
        "subject": incident.get("name", "No subject"),
        "messages": messages,
        "language": "en",
        "_type": "Email",
        "createdAt": incident["created_at"],
        "updatedAt": incident["updated_at"]
    }

For reference on how user mapping works in structurally similar migrations, see Zendesk to Dixa Migration: The Complete Technical Guide.

Importing Data into Dixa

Dixa provides a specific endpoint for historical migrations: POST /v1/conversations/import. This is distinct from the standard POST /v1/conversations endpoint — the import endpoint bypasses routing rules and SLA timers, preventing historical tickets from triggering agent notifications, queue assignments, or SLA breach alerts.

Plan Requirements

API access is only available on Dixa's Ultimate or Prime plans. The Growth plan does not include API access. Verify your contract before writing any import code — this is a hard prerequisite, not a configuration choice.

Channel Type Definitions

Dixa's import endpoint supports two channel types:

  • email: Use for incidents that originated via email. The payload requires an emailIntegrationId (the email address configured in Dixa). Messages render as an email thread in the agent UI.
  • genericapimessaging: A generic API-sourced channel type. Use for incidents that originated from the SWSD self-service portal, phone (if logged as incidents), or API integrations. Messages render as a chat-style timeline. Does not require an emailIntegrationId.

For most SWSD migrations, email is the appropriate default because the majority of incidents are email- or portal-originated and email rendering is more familiar to agents reviewing historical data. Use tags to preserve the original channel origin (e.g., source:phone, source:portal, source:service-catalog).

Rate Limits and Import Throughput

Dixa enforces a rate limit of 10 requests/second per API token, with a daily ceiling of 864,000 requests per token. Dixa does not return a Retry-After header on 429 responses — implement exponential backoff starting at 1–2 seconds.

Practical throughput math: At 10 req/s, you can submit 36,000 conversation payloads per hour. A migration of 100,000 incidents (each submitted as one request) takes a minimum of ~2.8 hours of import time at full throttle — not accounting for the separate post-import passes for notes, tags, and custom attributes. If each incident also requires a notes pass and a custom attributes patch, the effective request count triples: 300,000 requests across three passes = ~8.3 hours at full throttle. At a conservative 5 req/s to reduce error risk, that extends to ~16.7 hours. Plan for at least 2–3 days of import time for 100,000 incidents including all post-import passes.

Because the rate limit is per token (not per organization), you can parallelize import work across multiple API tokens — one token per migration job segment — to increase throughput proportionally.

No Idempotency

This is the most operationally dangerous constraint: Dixa's import endpoint has no idempotency key. Submitting the same payload twice creates two separate conversations with different IDs. Your migration pipeline must maintain a local mapping table (SWSD incident ID → Dixa conversation ID) and skip already-imported records on every retry. This is not optional — a single script crash without deduplication tracking will contaminate your Dixa environment with duplicate conversations that must be manually identified and deleted.

End Users Must Exist First

Dixa requires the end user's UUID (requesterId) for every imported conversation. If the end user doesn't exist at import time, the API returns HTTP 400. There is no lazy-creation path — you must pre-populate all end users before the import pass begins.

Timestamps Must Be Explicit

If you omit createdAt and updatedAt from the import payload, Dixa stamps every imported conversation with the import date, destroying historical analytics and reporting. Pass original SWSD timestamps explicitly on every payload. Validate timestamp preservation on a 10-conversation test batch before running the full migration — confirm in the Dixa UI that the displayed dates match the original SWSD dates, not the import date.

Import Script with Deduplication Tracking

import sqlite3
import requests
import time
 
DIXA_BASE = "https://dev.dixa.io"
DIXA_TOKEN = "YOUR_DIXA_API_TOKEN"
 
def import_to_dixa(payload, swsd_incident_id, db_conn):
    # Check if already imported
    cursor = db_conn.execute(
        "SELECT dixa_id FROM migration_log WHERE swsd_id = ?",
        (swsd_incident_id,)
    )
    if cursor.fetchone():
        return  # Already imported, skip
 
    resp = requests.post(
        f"{DIXA_BASE}/v1/conversations/import",
        headers={
            "Authorization": f"Bearer {DIXA_TOKEN}",
            "Content-Type": "application/json"
        },
        json=payload
    )
 
    if resp.status_code == 429:
        time.sleep(2)
        return import_to_dixa(payload, swsd_incident_id, db_conn)
 
    if resp.status_code == 201:
        dixa_id = resp.json()["data"]["id"]
        db_conn.execute(
            "INSERT INTO migration_log (swsd_id, dixa_id, status) VALUES (?, ?, 'success')",
            (swsd_incident_id, dixa_id)
        )
        db_conn.commit()
    else:
        db_conn.execute(
            "INSERT INTO migration_log (swsd_id, dixa_id, status, error) VALUES (?, NULL, 'failed', ?)",
            (swsd_incident_id, resp.text)
        )
        db_conn.commit()

Post-Import: Notes, Tags, and Custom Attributes

Three categories of data cannot be included in the initial import payload and require separate API passes after conversations exist in Dixa:

1. Internal Notes (Private Comments)

For each SWSD comment where is_private: true, call the notes endpoint after the conversation is created:

def add_internal_note(conversation_id, note_body, db_conn):
    resp = requests.post(
        f"{DIXA_BASE}/v1/conversations/{conversation_id}/notes",
        headers={
            "Authorization": f"Bearer {DIXA_TOKEN}",
            "Content-Type": "application/json"
        },
        json={
            "body": note_body,
            "_type": "Note"
        }
    )
    if resp.status_code != 201:
        db_conn.execute(
            "INSERT INTO notes_log (conversation_id, status, error) VALUES (?, 'failed', ?)",
            (conversation_id, resp.text)
        )
        db_conn.commit()
    return resp.status_code == 201

Internal notes are only visible to agents in Dixa — they are never exposed to end users. Confirm this behavior in your sandbox before running the production pass.

2. Tags

Apply tags via the Dixa tags endpoint after conversations are created. Map SWSD category paths to the tags you created during environment setup. This is also where you apply channel origin tags (e.g., source:phone, source:portal).

3. Custom Attributes

Patch custom attribute values per conversation using PATCH /v1/conversations/{conversationId}/custom-attributes. Each attribute must be defined in Dixa's admin settings before you can write values to it — attribute definitions are not auto-created by the API.

Rebuilding Workflows: SWSD Automations → Dixa Flows

SWSD automation rules follow a linear if-then structure: trigger condition → action. Dixa uses a visual node-based engine called Flows with branching logic, wait nodes, and queue routing steps. You cannot programmatically export or import automations between these platforms — every rule must be rebuilt manually.

Worked example — common SWSD automation converted to Dixa Flow:

SWSD Rule Dixa Flow Equivalent
If Category = "Hardware", assign to group "IT Ops" Flow node: Check tag = hardware → Route to queue "IT Ops"
If Priority = "Critical", send email to manager Flow node: Check custom attribute priority = critical → Trigger webhook or email notification action
If no response in 24h, send follow-up email Flow node: Wait 24h → Check conversation status → If open, send templated message
If requester submits from VIP account, set priority Flow node: Check end user custom attribute vip = true → Set conversation priority → Route to dedicated queue

Practical steps for the rebuild:

  1. Audit before rebuilding. Export your SWSD automation rules to a spreadsheet. Query the SWSD audit log or rule execution history and identify which rules have fired zero times in the last 90 days. Discard those entirely — they are operational debt, not requirements.
  2. Do not replicate ITIL approval chains. SWSD change and service catalog workflows contain multi-stage approval nodes that have no Dixa equivalent. These workflows must be redesigned from scratch — or dropped if the underlying use case doesn't exist in your post-migration support model.
  3. Consolidate assignment groups. SWSD instances commonly have 30–60 highly specific assignment groups. Dixa skill-based routing and broader queues (e.g., "Tier 1 Support", "Billing", "Technical") typically replace these more effectively than a 1:1 group rebuild.

Testing, Delta Sync, and Cutover

Sandbox Migration

Extract a representative sample (~5,000 incidents) from SWSD that includes edge cases: large attachments (>10MB), incidents with 50+ comments, rare custom field values, deleted requesters, private-only comment threads, and incidents with inline images. Import this sample into a Dixa sandbox environment. Have senior agents verify UI presentation — message chronological order, attachment accessibility, internal note visibility (agents only, not end users), and custom attribute values.

Full Historical Sync

Run the complete extraction and import for all closed tickets. At Dixa's 10 req/s limit with 100,000 incidents and three post-import passes (notes, tags, custom attributes), budget 2–3 calendar days for the import phase alone.

Delta Sync

Because agents continue working in SWSD during the historical sync, new incidents are created and open incidents are updated. Run a delta sync that queries SWSD for updated_at > [timestamp of initial extraction start] and imports only changed or new records. Sorting by updated_at ascending during extraction makes this straightforward — your resume point is the last successfully processed updated_at timestamp in your migration log table.

Cutover Sequence

  1. Select a low-traffic window (typically Friday evening)
  2. Freeze SWSD — put the account in read-only mode or communicate a freeze to agents
  3. Run final delta sync to capture the last few hours of activity
  4. Update MX records and inbound email routing to point to Dixa
  5. Update any outbound webhook configurations
  6. Confirm Dixa Flows are live and tested
  7. Agents log into Dixa on the next business day

For more on managing delta syncs during live migrations, see How to Migrate from Freshdesk to Dixa: The Complete Technical Guide.

Post-Migration Validation Checklist

Run this validation pass comparing source and target before declaring migration complete:

  • Count match: Total SWSD incidents exported vs. Dixa conversations created (check your migration_log table)
  • Message count: Verify comment counts per incident match message counts per conversation (spot-check 50+ records)
  • User mapping: Confirm requester emails in SWSD match end user emails in Dixa for a random sample of 100 conversations
  • Attachment integrity: Open 50–100 conversations in Dixa and confirm all attachments load successfully
  • Custom attributes: Verify values migrated correctly for each custom field type (dropdown, multi-select, date, text)
  • Internal notes: Confirm private SWSD comments appear as agent-only notes in Dixa, not as public messages
  • Timestamp preservation: Confirm original SWSD created_at dates appear in Dixa, not the import date
  • Duplicate conversations: Query your migration_log table for any SWSD incident ID appearing more than once — investigate immediately
  • Inline image rendering: Open several conversations with known inline images and confirm images display correctly

For a complete post-migration validation framework, see Best Practices for Help Desk Data Migration.

Edge Cases and Failure Modes

SWSD Rate Limiting Without Headers

SWSD does not return standard rate-limit headers. If you hit a 429, there is no header indicating how long to wait. Pace requests at 2 req/s and use exponential backoff starting at 5 seconds. Do not assume a 429 means you've exceeded a fixed limit — SWSD's limit may be dynamic based on account tier and concurrent usage.

Dixa Duplicate Conversations

If your import script crashes mid-run and restarts without checking the migration_log table, every re-submitted incident creates a duplicate conversation in Dixa. There is no bulk-delete endpoint in Dixa — duplicates must be identified and removed manually or via individual API calls. The SQLite/database tracking pattern in the import script above is not optional for production migrations.

Service Catalog Requests as Incidents

SWSD service catalog items submitted as incidents appear in the incidents endpoint and can be migrated as conversations. However, the multi-stage approval metadata (approval status, approver list, approval timestamps) will not have corresponding fields in Dixa. Flatten these into standard conversations, apply a source:service-catalog tag, and note the original approval status in the conversation subject or as a custom attribute.

SWSD Comment Visibility Field Verification

The field name is_private on SWSD comment objects is what appears in API responses for most account configurations, but field names can differ based on SWSD customization. Before processing comments at scale, retrieve one known private comment and one known public comment and inspect the raw JSON response to confirm the exact field name and its values in your instance.

Timeline and Effort Estimates

Scenario Volume Estimated Timeline Approach
Small team, basic incidents < 10,000 incidents 1–2 weeks Scripted DIY (~60–100 eng-hours)
Mid-market, custom fields 10,000–50,000 incidents 2–3 weeks Scripted DIY or managed service
Enterprise, active ITSM usage 50,000–200,000 incidents 3–5 weeks Managed service recommended
Complex: multi-department, heavy ITSM 200,000+ incidents 5–8 weeks Managed service + archival project

The largest time sinks are not the data transfer itself — they are the archival project for ITSM objects Dixa can't accept (problems, changes, assets), rebuilding automations as Dixa Flows, and recreating knowledge base content article by article.

As of 2025, no established third-party migration tool (Help Desk Migration, Import2, Trujay) offers a direct SolarWinds Service Desk → Dixa path. This is a custom scripting or managed service engagement.

DIY vs. Managed Migration

DIY is viable if:

  • Fewer than 10,000 incidents
  • Minimal custom fields, few attachments, no inline images
  • No ITSM objects to archive (problems, changes, assets are unused)
  • An engineer with Python/REST API scripting experience available for 1–2 full weeks
  • No private comments requiring a separate notes pass

A managed service is the safer choice if:

  • 50,000+ incidents with custom fields, attachments, private notes, or inline images
  • ITSM objects (CMDB, problems, changes) need to be archived in a structured, queryable format for compliance
  • You cannot tolerate duplicate conversations from failed retries
  • Your engineering team lacks bandwidth for extraction, transformation, deduplication, and validation scripting
  • You have a hard cutover deadline

Making It Stick

The SolarWinds Service Desk to Dixa migration is fundamentally an ITSM simplification project. You're trading a full ITIL platform for a fast, opinionated customer support tool. The data migration is the measurable part — incidents, users, comments, attachments — and it's solvable with the right API scripting, deduplication controls, and sequenced post-import passes. The harder part is accepting what you leave behind: CMDB, change management, problem linking, approval chains.

The non-negotiable technical constraints are: end users before conversations, no idempotency on the import endpoint, attachment URLs must be persistent, timestamps must be explicit, and private comments must go through the notes endpoint not the message payload. Get these right and the rest is sequencing.

If your team genuinely doesn't need ITSM capabilities, the move to Dixa delivers a faster agent experience and a simpler operational model. If you do need them, this isn't the right migration.

For other SWSD migration paths, see SolarWinds Service Desk to Enchant Migration: Technical Guide.

Frequently Asked Questions

Can you migrate SolarWinds Service Desk data to Dixa?
Yes, but only incidents and their comments map to Dixa conversations. SWSD problems, changes, releases, assets, and CMDB records have no Dixa equivalent and must be archived separately. The migration uses the SWSD REST API for extraction and Dixa's POST /v1/conversations/import endpoint for loading.
What Dixa plan do I need for API-based migration?
Dixa API access is only available on the Ultimate ($169/user/month) or Prime plans. The Growth plan does not include API access. Confirm your contract includes it before building any migration scripts.
How do I preserve original ticket creation dates in Dixa?
Pass the original SWSD created_at timestamps into the Dixa import payload. Test on a small batch first — if timestamps aren't preserved, all imported conversations will show the import date instead of the original date, destroying historical reporting.
How long does a SolarWinds Service Desk to Dixa migration take?
A typical migration takes 2–5 weeks for 50,000–150,000 incidents, including data mapping, test migrations, and cutover. Smaller datasets under 10,000 incidents can be completed in 1–2 weeks. The largest time sinks are rebuilding automations as Dixa Flows and archiving ITSM objects.
What SolarWinds Service Desk objects cannot be migrated to Dixa?
Problems, changes, releases, assets, CMDB records, service catalog items, approval workflows, and knowledge base articles cannot be migrated. SLA policies and automations must be rebuilt manually. Only incidents with their comments and attachments map to Dixa conversations.

More from our Blog