---
title: "FuseDesk to Enchant Migration: A Technical Guide"
slug: fusedesk-to-enchant-migration-a-technical-guide
date: 2026-08-02
author: Abdul
categories: [Enchant, Migration Guide, Help Desk]
excerpt: "A technical guide to migrating from FuseDesk to Enchant — covering API constraints, object mapping, dependency order, rate limits, and edge cases."
tldr: "FuseDesk to Enchant migration requires mapping Cases to Tickets, Departments to Inboxes, and Reps to Users, while navigating dual API rate limits (1,800/hr and 100/min) and the loss of CRM-linked data."
canonical: https://clonepartner.com/blog/fusedesk-to-enchant-migration-a-technical-guide/
---

# FuseDesk to Enchant Migration: A Technical Guide


Moving from [FuseDesk](https://clonepartner.com/help-desk-data-migration/fusedesk) to [Enchant](https://clonepartner.com/help-desk-data-migration/enchant) means shifting from a CRM-centric helpdesk — built around Keap/Infusionsoft contact records, departments, and case history — to a lightweight, inbox-centric shared inbox where tickets, labels, and customers are the organizing primitives. While both platforms resolve customer issues, their data models, API behaviors, and structural dependencies are entirely different.

The core engineering challenge is extracting FuseDesk's tightly coupled CRM data through its API and restructuring it for Enchant's flatter, more minimal data model without losing conversation history or customer context.

At ClonePartner, we've executed over 1,500 migrations, and we consistently see teams underestimate the complexity of decoupling helpdesk data from a CRM. Enchant is intentionally minimal — it focuses on speed, conversation flow, and inbox management rather than functioning as a pseudo-CRM. This guide covers the object mapping, extraction strategy, [dependency order](https://clonepartner.com/blog/blog/freshdesk-to-enchant-migration-guide/), API constraints on both sides, and the edge cases that break naive migrations.

## Why Teams Move from FuseDesk to Enchant

FuseDesk is purpose-built for the Keap and Infusionsoft ecosystem. If your team is leaving that CRM ecosystem — or simply wants a standalone helpdesk without the CRM dependency — Enchant's multi-channel shared inbox is a natural fit. Enchant supports email, live chat, SMS, WhatsApp, social messaging, and a knowledge base, all without requiring a specific CRM backend.

The typical trigger: the team has outgrown Keap, switched CRMs, or wants a helpdesk that works independently of any specific CRM vendor.

## Define Your Migration Scope

Before writing any code, map out what moves programmatically, what gets rebuilt manually, and what you leave behind.

**Migrate via API:**
- Departments → Inboxes
- Reps → Users (manual invite + ID mapping)
- Contacts → Customers
- Cases → Tickets
- Case history (emails, notes, calls) → Messages
- Case Tags → Labels

**Rebuild manually in Enchant:**
- Canned responses / email templates / note templates
- Automation rules and workflows
- Knowledge base content
- SLA policies
- Business hours

**Will not transfer:**
- CRM-specific data (Infusionsoft Contact IDs, Company IDs, CRM tags, campaign links)
- FuseDesk snippets and template merge fields
- Webhook configurations
- Chat widget settings
- Third-party app integrations (Zapier zaps, WordPress plugin config)

> [!WARNING]
> **CRM data loss is the biggest risk.** FuseDesk stores Infusionsoft/Keap Contact IDs and Company IDs on every case and contact. Enchant has no equivalent CRM linkage. If you need to preserve this association, write the CRM IDs into the Enchant customer `summary` field or maintain an external mapping table before you begin.

Check your FuseDesk data retention settings before starting. FuseDesk PRO and Enterprise plans support automatic archival, anonymization, and deletion of cases, chats, contacts, and emails. Anonymized records will have PII scrubbed — names, emails, and phone numbers are irreversibly removed. If your data has been anonymized, those records cannot be meaningfully migrated.

## Object Mapping: FuseDesk → Enchant

The data models are structurally different. Here is the field-level mapping for each core object.

### Departments → Inboxes

| FuseDesk Field | Enchant Field | Notes |
|---|---|---|
| `departmentid` | `inbox_id` | Store mapping for ticket import |
| `name` | Inbox name | Set during Enchant inbox setup |
| `repids` | — | Enchant doesn't restrict users to inboxes via API |

FuseDesk departments include a list of assigned rep IDs. Enchant inboxes don't enforce rep membership via the API — any user can be assigned to a ticket in any inbox. Create your Enchant inboxes through the admin UI before migration and build a `departmentid → inbox_id` lookup.

### Reps → Users

| FuseDesk Field | Enchant Field | Notes |
|---|---|---|
| `repid` | `user_id` | Map for ticket assignment |
| Rep name | `first_name`, `last_name` | |
| Rep email | `email` | |

Enchant does not expose a user creation endpoint in its public API. Invite agents manually through the Enchant admin UI, then pull the user list via `GET /api/v1/users` and build a `repid → user_id` mapping table. This step must happen before any ticket import.

> [!WARNING]
> **Identity mapping is non-negotiable.** When you create a ticket or message in Enchant via the API, you must specify the `user_id` of the author. If you fail to map a former FuseDesk Rep who is no longer with the company, your script will either fail or default to assigning those historical replies to your API admin account, destroying historical accuracy. For deleted reps, create a placeholder "Legacy Agent" user in Enchant and map their ID to preserve the visual context of a staff reply.

### Contacts → Customers

| FuseDesk Field | Enchant Field | Notes |
|---|---|---|
| `contactid` / `contactUuid` | `customer_id` | |
| Name (from CRM) | `first_name`, `last_name` | |
| Email | `contacts [].value` (type: `email`) | |
| Phone | `contacts [].value` (type: `phone`) | |
| Infusionsoft Contact ID | `summary` | Preserve as reference |
| Company ID | `summary` | No native company field in Enchant |

FuseDesk contacts are deeply tied to your CRM. In Enchant, customers are standalone records with a `summary` free-text field — use this to stash CRM IDs or other metadata you need to preserve.

Enchant supports `email`, `twitter`, and `phone` contact types. Any FuseDesk contact channels outside these three (SMS handles, social media IDs stored in the CRM) will need to be stored in the `summary` field or dropped.

### Cases → Tickets

| FuseDesk Field | Enchant Field | Notes |
|---|---|---|
| `caseid` | `client_id` | Use for idempotency |
| `summary` | `subject` | |
| `status` (new, open, closed) | `state` (open, hold, closed) | Map `new` → `open` |
| `depid` | `inbox_id` | Use department mapping |
| `repid` | `user_id` | Use rep mapping |
| `contactid` | `customer_id` | Use contact mapping |
| `date_opened` | `created_at` | Override default timestamp |
| `casetags` | `label_ids` | Use label mapping |

Enchant's API only allows ticket creation with `type` set to `email`. Other FuseDesk case origins (phone calls, live chat) will all be imported as email-type tickets. Preserve the original channel in a label (e.g., `original:phone`) or as a note on the ticket if you need to track it.

> [!NOTE]
> **Status mapping detail:** FuseDesk uses three statuses — `new`, `open`, and `closed`. Enchant supports `open`, `hold`, `closed`, `snoozed`, and `archived`. Map FuseDesk `new` and `open` to Enchant `open`, and `closed` to `closed`. If you want to distinguish "waiting on customer" cases, use Enchant's `hold` state, but FuseDesk doesn't have a native equivalent — you'd need to identify these from case tags or CRM data.

### Case History → Messages

FuseDesk case history is a mix of emails, notes, and call logs. Enchant messages are either `reply` (inbound or outbound) or `note`.

| FuseDesk History Type | Enchant Message Type | Notes |
|---|---|---|
| `email` (inbound) | `reply` (direction: `in`) | |
| `email` (outbound) | `reply` (direction: `out`) | Requires `user_id` |
| `note` | `note` | Requires `user_id` |
| `call` | `note` | No call type in Enchant — prepend " [Phone Call]" to body |

For outbound replies and notes, `user_id` is required. Sort messages strictly by their original creation date (oldest first). If you insert them out of order, the conversation history will be unreadable.

### Case Tags → Labels

FuseDesk case tags map directly to Enchant labels. Fetch all case tags via FuseDesk's `/api/v1/casetags/` endpoint. Enchant does not expose a label creation endpoint in the public API — create them through the Enchant admin UI, then retrieve their IDs via the API for use during ticket import.

For a migration, it is generally safer to create labels as account-wide rather than inbox-specific.

## Extraction: Getting Data Out of FuseDesk

FuseDesk's API authenticates via API key passed in the `X-FuseDesk-API-Key` header. You'll need admin access to create a key with full read permissions under **Settings → API Keys**.

### FuseDesk Rate Limits

FuseDesk enforces an hourly rate limit. The API response headers include `X-FuseDesk-Usage-Limit` (typically 1,800 calls/hour) and `X-FuseDesk-Usage-Remaining`. Build a backoff strategy that checks remaining calls and pauses before hitting zero.

### Extraction Order

1. **Departments** — `GET /api/v1/departments/all` (returns active and archived)
2. **Reps** — `GET /api/v1/reps/`
3. **Case Tags** — `GET /api/v1/casetags/`
4. **Cases** — `GET /api/v1/cases/` with pagination (limit max 500, offset-based)
5. **Case detail + history** — `GET /api/v1/cases/{CASEID}` per case
6. **Contacts** — Extracted from case data (linked via `contactid`)

### Pagination and Extraction Code

FuseDesk case search supports `limit` (max 500) and `offset` parameters. Page through all cases:

```python
import requests
import time

FUSEDESK_APP = "yourappname"
API_KEY = "your_api_key"
BASE_URL = f"https://{FUSEDESK_APP}.fusedesk.com/api/v1"
HEADERS = {"X-FuseDesk-API-Key": API_KEY}

def fetch_all_cases():
    all_cases = []
    offset = 0
    limit = 500
    while True:
        resp = requests.get(
            f"{BASE_URL}/cases",
            headers=HEADERS,
            params={"limit": limit, "offset": offset, "status": "all"}
        )
        resp.raise_for_status()
        remaining = int(resp.headers.get("X-FuseDesk-Usage-Remaining", 100))
        if remaining < 50:
            time.sleep(120)  # back off before exhausting limit
        cases = resp.json()
        if not cases:
            break
        all_cases.extend(cases)
        offset += limit
    return all_cases
```

Each case's conversation history is returned when you `GET /api/v1/cases/{CASEID}`. The response includes the full history array with emails, notes, and calls. This is where most of your API calls go — one per case — so plan for rate limiting on large accounts.

> [!TIP]
> **Batch extraction tip:** If you have 5,000+ cases, the per-case detail fetch alone consumes 5,000+ API calls. At 1,800/hour, that's nearly 3 hours just for extraction. Run extraction overnight and store results locally as JSON before starting the import.

## Loading: Importing Data into Enchant

Enchant's REST API authenticates via bearer token. Get your token by installing the API app from the Enchant settings panel.

### Enchant Rate Limits

Enchant enforces **100 credits per minute** across all endpoints, tokens, and users for the entire account. A basic request costs 1 credit. There's also a **burst limit of 6 requests per second**. At full throughput, you can sustain roughly 90–95 meaningful requests per minute.

For a migration of 10,000 tickets with an average of 3 messages each, you're looking at:
- 10,000 customer creates/lookups
- 10,000 ticket creates
- 30,000 message creates
- Attachment uploads on top of that

That's 50,000+ API calls at ~90/minute — about 9+ hours of import time.

Monitor the HTTP headers in Enchant's responses:
- `X-RateLimit-Limit`: Total requests allowed in the current window
- `X-RateLimit-Remaining`: Requests left
- `X-RateLimit-Reset`: Unix timestamp when the limit resets

If you hit a `429 Too Many Requests` error, your script must catch the exception, read the `X-RateLimit-Reset` header, pause execution, and retry the exact same request. Do not drop the request, or you will have missing data.

### Import Order (Dependency Chain)

Helpdesk migrations are strictly hierarchical. You cannot create a ticket until the customer exists. You cannot create a message until the ticket exists. Follow this order:

1. **Users** — Invite manually, then fetch IDs via `GET /api/v1/users`
2. **Labels** — Create in Enchant admin UI
3. **Inboxes** — Create in admin UI, then get IDs
4. **Customers** — `POST /api/v1/customers`
5. **Tickets with initial messages** — `POST /api/v1/tickets` with inline `messages` array
6. **Remaining messages** — `POST /api/v1/tickets/{id}/messages`
7. **Ticket state update** — `PATCH /api/v1/tickets/{id}` to set final status and labels

### Creating Customers

Query FuseDesk contacts and push each to Enchant:

```json
{
  "first_name": "Jane",
  "last_name": "Doe",
  "contact_points": [
    {
      "type": "email",
      "value": "jane.doe@example.com"
    }
  ]
}
```

Store the returned Enchant `customer_id` against the FuseDesk `contactid` in your mapping table.

### Creating Tickets with Messages

Enchant supports creating a ticket with an initial set of messages in a single API call — your most efficient import path:

```python
import requests

ENCHANT_SITE = "yoursite"
ENCHANT_TOKEN = "your_bearer_token"
ENCHANT_BASE = f"https://{ENCHANT_SITE}.enchant.com/api/v1"
ENCHANT_HEADERS = {
    "Authorization": f"Bearer {ENCHANT_TOKEN}",
    "Content-Type": "application/json"
}

def create_ticket(customer_id, inbox_id, subject, messages, user_id=None, label_ids=None):
    payload = {
        "type": "email",
        "subject": subject,
        "customer_id": customer_id,
        "inbox_id": inbox_id,
        "messages": messages
    }
    if user_id:
        payload["user_id"] = user_id
    resp = requests.post(
        f"{ENCHANT_BASE}/tickets",
        headers=ENCHANT_HEADERS,
        json=payload
    )
    resp.raise_for_status()
    ticket = resp.json()
    if label_ids:
        requests.patch(
            f"{ENCHANT_BASE}/tickets/{ticket['id']}",
            headers=ENCHANT_HEADERS,
            json={"label_ids": label_ids}
        )
    return ticket
```

### Preserving Timestamps

By default, creating a ticket via API uses the current server time as the creation date. This ruins historical reporting. Pass the `created_at` parameter in your ticket and message payloads to override this with the original FuseDesk timestamps.

### Idempotency

Network requests fail. If your script crashes halfway through 50,000 tickets, you need to restart without creating duplicates. Enchant supports idempotency via the `client_id` parameter — pass the FuseDesk `caseid` as the `client_id`. If Enchant sees a creation request with a `client_id` it already has, it will return the existing ticket instead of creating a duplicate.

### Handling Attachments

Attachments are the most resource-intensive part of any migration. You cannot pass a FuseDesk URL to Enchant — those URLs will break once you deprecate FuseDesk or if they require authentication.

FuseDesk's API does not expose a dedicated attachment download endpoint for case history items. You may need to extract attachments from your CRM or email system directly.

On the Enchant side, upload attachments via `POST /api/v1/attachments` as Base64-encoded data, then reference the returned ID when creating the message:

```python
import base64

def upload_attachment(file_path, file_name, mime_type):
    with open(file_path, "rb") as f:
        encoded = base64.b64encode(f.read()).decode("utf-8")
    resp = requests.post(
        f"{ENCHANT_BASE}/attachments",
        headers=ENCHANT_HEADERS,
        json={"name": file_name, "type": mime_type, "data": encoded}
    )
    resp.raise_for_status()
    return resp.json()["id"]
```

> [!WARNING]
> **Base64 encoding inflates file size by ~33%.** Large attachments will hit HTTP payload limits. Test with your largest files early. Write exception handling to catch upload errors, log the failed attachment, and append a text note to the ticket indicating an attachment was dropped.

## The Custom Field Workaround

[Enchant does not support custom fields on tickets](https://clonepartner.com/blog/blog/enchant-to-deskpro-migration-a-technical-guide/). If your FuseDesk instance relies on custom fields pulled from Keap or ActiveCampaign (e.g., "Subscription Tier", "Churn Risk", "Last Order Date"), you have two options:

**Option A: The Label Method.**
If the custom field has a limited set of discrete values (e.g., "Tier: Gold", "Tier: Silver"), map these to Enchant Labels. This preserves filterability.

**Option B: The Internal Note Method.**
If the custom field contains unique string data (e.g., "Order ID: 12345"), compile all custom fields into a single formatted HTML block and inject it as the very first **internal note** on the Enchant ticket. This keeps the data searchable and visible to the agent without requiring native custom fields.

## Edge Cases That Break Migrations

**Deleted or anonymized FuseDesk data.** If FuseDesk's data retention settings have anonymized records, PII is irreversibly scrubbed. Email addresses and names are gone. These contacts can't be matched or meaningfully recreated in Enchant.

**HTML vs. plain text.** FuseDesk case history emails may include `body` as plain text. Enchant messages support HTML via the `htmlized` field. Set `htmlized: false` for plain text imports, or `htmlized: true` if you have stored HTML versions.

**Tickets over 10,000.** Enchant's ticket listing endpoint warns that retrieving more than 10,000 total tickets requires iterating using `since_created_at` instead of page-based pagination. This applies during verification — not import — but plan your validation queries accordingly.

**CRM merge fields in templates.** FuseDesk email templates and note templates use CRM merge fields (e.g., Keap contact fields). These will not function in Enchant. Rebuild all templates from scratch.

**Channel type loss.** Enchant's API only allows ticket creation with `type` set to `email`. Phone calls and live chat cases from FuseDesk will all become email-type tickets. Add a label like `original:phone` or `original:chat` to preserve the original channel.

**CRM integrations do not carry over.** Because Enchant is a separate platform, you will need to re-authenticate and configure any Keap, ActiveCampaign, or other CRM integrations natively within Enchant after the migration is complete.

## Delta Migration: The Cutover Strategy

Moving tens of thousands of tickets takes time — often several days due to rate limits and attachment downloads. You cannot freeze support operations while waiting.

The solution is a **delta migration**:

1. **Initial sync**: Run the full migration script up to the current date. Your team continues working in FuseDesk.
2. **The delta**: Once the initial sync completes, run a modified script that queries FuseDesk only for cases created or modified *after* the start date of your initial sync.
3. **Cutover**: Pick a low-traffic window (e.g., Friday night). Run the final delta sync. Change your DNS/email forwarding rules to point to Enchant.
4. **Go live**: Your team logs into Enchant. All historical data is present, and new emails are flowing in.

## Validation and Verification

Do not rely on "script finished successfully." Validate the data.

1. **Ticket counts** — Compare total cases extracted from FuseDesk against total tickets in Enchant using `GET /api/v1/tickets?count=true`.
2. **Message counts** — Spot-check 50+ tickets across different size buckets. Verify message counts match case history lengths.
3. **Attachment integrity** — Can files be downloaded from Enchant?
4. **Customer deduplication** — Verify no duplicate customer records were created.
5. **Label accuracy** — Confirm case tags mapped correctly to labels.
6. **State accuracy** — Verify closed FuseDesk cases show as `closed` in Enchant, not left `open` from the creation step.
7. **Author accuracy** — Did messages map to the correct users, or did they fall back to the API admin?

> [!TIP]
> **Run a dry-run first.** Import 50–100 cases into a test Enchant instance before doing the full migration. This catches mapping errors, encoding issues, and rate-limit surprises before they affect production data.

## Migration Timeline Estimate

| Account Size | Cases | Estimated Extraction | Estimated Import | Total |
|---|---|---|---|---|
| Small | < 1,000 | < 1 hour | 2–3 hours | Half a day |
| Medium | 1,000–10,000 | 1–6 hours | 10–20 hours | 1–2 days |
| Large | 10,000+ | 6+ hours | 2–4 days | 3–5 days |

These estimates assume rate-limit-aware scripting with proper backoff. Attachments can double the import time.

## When to Call in Help

If your FuseDesk account has deep Keap/Infusionsoft integration with thousands of contacts, heavy case history, and compliance requirements around data completeness, this is not a weekend project. The dual rate-limit bottleneck (1,800/hour on FuseDesk, 100/minute on Enchant) makes large migrations slow and error-prone without purpose-built tooling.

At ClonePartner, we've handled [1,500+ helpdesk migrations](https://clonepartner.com/blog/blog/best-practices-for-help-desk-data-migration/) and built reusable extraction and loading pipelines that handle rate limiting, deduplication, attachment transfer, and data validation automatically.

> Need help migrating from FuseDesk to Enchant? Our engineers handle the extraction, mapping, and import — with zero downtime and full data verification. Book a free 30-minute call.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## Frequently asked questions

### Can I migrate FuseDesk cases to Enchant automatically?

Yes, but only via custom scripts using both APIs. There is no native import tool. You extract cases from FuseDesk's REST API and create tickets in Enchant's REST API, respecting both platforms' rate limits.

### What data is lost when migrating from FuseDesk to Enchant?

CRM-specific data is the biggest loss — Infusionsoft/Keap Contact IDs, Company IDs, CRM tags, campaign links, and merge-field templates have no Enchant equivalent. Chat widget configs, Zapier integrations, and automation workflows also don't transfer.

### Can I migrate custom fields from FuseDesk to Enchant?

Enchant does not support custom fields on tickets. You must either map discrete custom field values to Enchant Labels or inject the custom data as an internal note on the migrated ticket.

### How long does a FuseDesk to Enchant migration take?

A small account (under 1,000 cases) can be migrated in half a day. Medium accounts (1,000–10,000 cases) typically take 1-2 days. Large accounts with 10,000+ cases and attachments can take 3-5 days due to API rate limits on both sides.

### How do I handle attachments during the migration?

FuseDesk doesn't expose a dedicated attachment download endpoint, so you may need to extract files from your CRM or email system. On the Enchant side, upload files as Base64-encoded data via the attachments API, then reference the returned ID when creating the message.
