The Complete Guide to Migrating from Enchant to Zendesk
Migrating from Enchant to Zendesk? Learn the exact API sequence to map users, move ticket history, and handle attachments while preserving data integrity.
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
Making the move from Enchant to Zendesk requires careful data mapping, sequenced API calls, and handling several non-obvious edge cases. This guide covers the full migration path: what maps, what doesn't, and what breaks silently if you get the order wrong.
Define Your Migration Scope
Decide what moves via API, what gets rebuilt manually, and what gets archived before you write any code.
Migrate via API to preserve customer-conversation relationships:
- Agents and admins (Users)
- Customers (End-users)
- User Identities (secondary emails, phone numbers, social handles)
- Tickets and full message history
- Attachments
- CSAT responses
Rebuild manually — these cannot be automated and need a fresh configuration in Zendesk:
- Triggers and automations
- Macros
- Views
- Help Center structure
Archive instead of migrate — tickets older than your retention policy are better kept as a static export for compliance than imported into a live environment where they add noise.
What Cannot Be Migrated Programmatically
The following categories will be lost or must be rebuilt manually. There is no API path that preserves them:
| Data Category | Status | Notes |
|---|---|---|
| Triggers / Automations | Must rebuild | Logic does not transfer between platforms |
| Macros / Saved replies | Must rebuild | Format is incompatible |
| Views | Must rebuild | Zendesk view logic differs from Enchant |
| Help Center articles | Must rebuild or manually export | No direct migration path |
| Workflow routing rules | Must rebuild | Enchant inbox routing ≠ Zendesk trigger logic |
Prepare Zendesk for Data Import
Zendesk must have its destination objects in place before any data arrives. Importing tickets into a Zendesk instance that lacks the right Groups or Custom Fields will produce orphaned records or silent field loss.
Groups (from Enchant Inboxes): Every Enchant Inbox needs a corresponding Zendesk Group. Tickets will be assigned to these Groups on arrival.
Custom Fields: Create all Ticket Fields and User Fields in Zendesk before migration. Any Enchant metadata that does not map to a native Zendesk field needs a custom field as its destination or it will be dropped.
Organizations: If you plan to group customers by email domain, configure your Organization structure now. Customers must be assigned to Organizations during import — you cannot batch-assign them after tickets are already in place without breaking relationships.
Migrate Objects
The migration must follow a strict dependency order. Importing out of sequence will cause relational failures — a ticket cannot reference a user who does not exist yet.
Field Mapping: Enchant → Zendesk
| Enchant Object | Enchant Field | Zendesk Equivalent | Notes |
|---|---|---|---|
| Inbox | name | Group > name | Create Groups before any ticket import |
| Agent/Admin | first_name + last_name | User > name | Concatenate; watch for double spaces |
| Agent/Admin | User > email | Must be unique | |
| Customer | first_name + last_name | User > name | Same concatenation rule applies |
| Customer | User Identities > value | Primary identity | |
| Customer | phone | User Identities > value | type: phone_number |
| Conversation | subject | Ticket > subject | |
| Conversation | status | Ticket > status | Map open/closed/pending explicitly |
| Reply | body | Comment > body (public: true) | Public comment |
| Note | body | Comment > body (public: false) | Internal note |
| Attachment | file | Upload token → Comment > uploads [] | Token expires in 60 min |
| CSAT rating | value | Ticket > satisfaction_rating > score | Map Enchant scale to Zendesk values |
| CSAT comment | text | Ticket > satisfaction_rating > comment | |
| Label | name | Ticket > tags [] | Flatten to tag strings |
Migration Sequence
- Groups — Must exist before tickets are created.
- Agents and Admins — Required before tickets can have an assignee.
- End-users (Customers) — Required before tickets can have a requester.
- User Identities — Secondary emails, phones. Add after user records exist.
- Attachments — Upload files and collect tokens. Tokens expire in 60 minutes; see note below.
- Tickets and Messages — Create ticket shells, then import comments with attachment tokens.
- CSAT Responses — Link to existing tickets last.
Code Sample: Attachment Upload and Token Handling
Tokens expire 60 minutes after generation. If your ticket migration is slow, generate tokens immediately before the comment import, not in a separate pre-pass.
import requests
import time
def upload_attachment(file_path, filename, zendesk_subdomain, auth):
url = f"https://{zendesk_subdomain}.zendesk.com/api/v2/uploads.json?filename={filename}"
headers = {"Content-Type": "application/binary"}
with open(file_path, "rb") as f:
response = requests.post(url, headers=headers, data=f, auth=auth)
response.raise_for_status()
token = response.json()["upload"]["token"]
return token
def create_comment_with_attachment(ticket_id, body, upload_token, is_public, zendesk_subdomain, auth):
url = f"https://{zendesk_subdomain}.zendesk.com/api/v2/tickets/{ticket_id}.json"
payload = {
"ticket": {
"comment": {
"body": body,
"public": is_public,
"uploads": [upload_token] # token must be used within 60 min of generation
}
}
}
response = requests.put(url, json=payload, auth=auth)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
time.sleep(retry_after)
return create_comment_with_attachment(ticket_id, body, upload_token, is_public, zendesk_subdomain, auth)
response.raise_for_status()
return response.json()API Rate Limits
Both APIs impose limits that will determine your migration throughput.
| Platform | Endpoint | Rate Limit | Notes |
|---|---|---|---|
| Enchant | All API calls | 100 credits/minute (account-wide) | Each embedded resource (label, message) costs +1 credit |
| Zendesk | Tickets (Create/Update) | 700 requests/minute (Enterprise); lower on lower plans | Check your plan tier |
| Zendesk | Users | 700 requests/minute (Enterprise) | Shared with ticket pool on some plans |
| Zendesk | Uploads (Attachments) | 400 requests/minute | Separate from ticket limit |
When Zendesk returns HTTP 429, the response includes a Retry-After header with the number of seconds to wait. Build this into every write loop — do not use a fixed sleep value.
Enchant's 100 credits/minute limit is account-wide, meaning a single embedded response that includes labels and messages can consume multiple credits per request. If you are paginating through large inboxes with embedded resources, you will hit this limit faster than you expect.
Post-Migration Configuration
Once data is imported, rebuild your operational layer manually:
- Triggers — Handle incoming mail routing and status changes.
- Automations — Manage ticket lifecycle (e.g., close solved tickets after N days).
- Macros — Recreate canned responses for agents.
- Views — Configure queue visibility for each team.
- Email forwarding — Redirect inbound mail from Enchant to Zendesk before going live.
Post-Migration Validation Checklist
Run these checks before decommissioning Enchant. Each check should produce a number you compare against your Enchant export.
- Ticket count — Total tickets in Zendesk matches total conversations exported from Enchant
- Comment count — Total public comments + internal notes per ticket matches Enchant replies + notes
- Attachment count — Files present on migrated tickets match the source count; open a sample of 20–30 tickets and verify files load
- User count — Agent and end-user counts match
- CSAT count — Satisfaction rating records match the number of rated conversations in Enchant
- Organization assignments — Customers assigned to correct Organizations
- Custom field values — Spot-check 10–15 tickets for custom field data integrity
- No orphaned tickets — Every ticket has a valid requester and, if applicable, an assignee
- Email forwarding live — Confirm new tickets arrive in Zendesk, not Enchant
Insider Secrets
Token expiration is the most common attachment failure. Upload tokens are valid for 60 minutes. If your ticket migration loop is slow — due to rate limiting, large volumes, or retry delays — tokens generated in a pre-pass will expire before the comment is created. Generate tokens immediately before you use them, in the same batch as the comment creation, not in a separate pre-migration step.
Enchant's credit limit compounds with embedded resources. Each embedded resource (label, message, assignee) in an Enchant API response costs one additional credit. A single request that embeds messages and labels can cost 3–4 credits instead of 1. On a 10,000-ticket migration with full embedding, you will spend far more time throttled than you expect. Fetch only what you need for each migration step.
Concatenation creates silent dirty data. Enchant stores first_name and last_name as separate fields. Zendesk uses a single name field. A naive first_name + " " + last_name concatenation produces double spaces when either field is blank — e.g., " Smith" or "Jane ". Zendesk trims whitespace on Organizations but not always on Users. Validate and strip before import.
CSAT data requires explicit scale mapping. Enchant's rating values do not map 1:1 to Zendesk's satisfaction_rating score field. Zendesk accepts good, bad, and offered as score values. Map your Enchant rating scale to these explicitly — do not pass raw Enchant values and assume Zendesk will interpret them.
If you'd rather focus on your revenue instead of wrestling with mapping sheets and pagination loops, ClonePartner can handle the full migration for you. Every project gets a dedicated engineer who understands the nuances of both APIs and ensures zero downtime.