Enchant to Puzzel Case Management Migration: Technical Guide
Technical guide for migrating data from Enchant to Puzzel Case Management. Covers API extraction, data model mapping, rate limits, edge cases, and validation.
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
Enchant to Puzzel Case Management Migration: Technical Guide
Last updated: July 2025. This guide targets Enchant API v1 and Puzzel Case Management (current release as of H1 2025).
Migrating from Enchant to Puzzel Case Management means moving from a lightweight shared inbox into a contact-centre-grade ticketing system with skill-based routing, multi-channel queuing, and deep integration with the broader Puzzel CX ecosystem. This is not a straight CSV transfer — it is an API-led data remodel. Enchant exposes a public REST API for tickets, customers, messages, and attachments. Puzzel's ticket operations live in an account-enabled API that must be activated on your tenant. (dev.enchant.com)
This guide covers every technical decision involved — from API extraction to data model mapping to validation — so your team lands on Puzzel with full conversation history and zero gaps.
Why Teams Migrate from Enchant to Puzzel Case Management
Enchant is a solid shared inbox for small teams. It handles email, chat, SMS, and social channels with a clean interface and low learning curve. But once a support operation outgrows basic label-based routing or needs to integrate ticketing with a contact centre platform, Enchant's architecture starts to constrain.
Puzzel Case Management is the ticketing and case management module inside the Puzzel CX Platform. It supports skill-based ticket routing, structured categories and forms, organisation-level grouping, SLA tracking, and direct integration with Puzzel Contact Centre for voice and omnichannel queuing. Teams typically migrate for three reasons:
- Contact centre integration: Unifying voice, SMS, email, and social cases into a single CCaaS routing engine.
- Structured case classification: Puzzel's category, form, and team system is significantly more powerful than Enchant's flat label and inbox model.
- Enterprise compliance and reporting: Puzzel offers granular, multi-tier SLA tracking, custom report builders, and organisation-level data segmentation that Enchant does not support.
Relative Migration Complexity
For context, Enchant-to-Puzzel is a moderate-to-high complexity migration compared to other common Enchant migration paths. Migrating Enchant to Zendesk or Freshdesk is typically simpler because those platforms have publicly documented APIs, well-known import tools, and flatter data models. Puzzel's in-app-only API documentation, team-centric data model, and lack of a public bulk import endpoint add friction that does not exist with other targets. If you are evaluating whether to migrate to Puzzel vs another platform, factor in the additional development overhead documented in this guide.
Core Data Model Differences
The two platforms organise data differently, and understanding this is the single most important step before writing any migration code.
Enchant uses a flat structure: Inboxes contain Tickets, Tickets have Messages, and Customers link to Tickets via contact records. Labels are flat strings applied to tickets.
Puzzel Case Management uses a hierarchical model with Teams, Organisations, Categories, Tags, Forms, and Form Fields as first-class ticket attributes. Tickets belong to Teams, and Teams define which Categories and Forms are available. Puzzel also groups contacts under Organisations — a concept that does not exist natively in Enchant. (help.enchant.com)
Migration Approaches
There is no native one-click migration path between Enchant and Puzzel. You have several options, each with different trade-offs.
1. API-to-API Migration (Recommended)
Extract data from Enchant's REST API and load it into Puzzel Case Management's REST API.
How it works: Write a custom script that paginates through Enchant's /api/v1/tickets, /api/v1/customers, and /api/v1/users endpoints, transforms each record to match Puzzel's schema, and POSTs it via Puzzel's API ticket channel.
When to use it: Any migration where you need to preserve ticket-to-customer relationships, message threading, and attachments.
Pros:
- Full control over data transformation
- Preserves relationships between tickets, customers, and messages
- Supports incremental runs for delta sync
Cons:
- Enchant's rate limit of 100 credits/minute and 6 requests/second burst limit makes large extractions slow
- Requires development effort — error handling, retry logic, and pagination must be built from scratch
- Puzzel's API must be enabled on your tenant
Complexity: High
2. CSV Export + API Import (Hybrid)
Export Enchant data via API to CSV, then transform and import into Puzzel via API.
How it works: Use Enchant's API to dump tickets, customers, and messages into structured CSV files. Clean and map the data offline. Then use Puzzel's API to create tickets with the transformed data. Puzzel's documented CSV imports cover customers and address-book contacts, not full ticket history replay. (help.enchant.com)
When to use it: When you want to inspect and clean data manually between extraction and loading, or when non-technical stakeholders need to review the mapping before final import.
Pros:
- Data can be audited and cleaned before import
- Easier to involve non-technical stakeholders in mapping review
Cons:
- Two-phase process doubles the work
- CSV flattens nested data (messages, attachments) which must be reconstructed
- Attachments cannot be represented in CSV — still need the API for those
- Enchant's CSV export is report-oriented, not a full data dump
Complexity: Medium
3. Middleware Platforms (Zapier, Make)
Use an integration platform to connect Enchant triggers to Puzzel actions.
When to use it: Only for ongoing sync of new tickets after migration, not for historical data. These platforms are not designed for bulk historical transfers. (help.enchant.com)
Pros:
- Low-code setup
- Good for post-migration live sync if you run both platforms in parallel
Cons:
- Cannot backfill historical data at scale
- Per-task pricing gets expensive fast (e.g., Zapier charges per task; a 50K ticket migration would cost hundreds of dollars in task fees alone, and would take days due to execution throttling)
- Limited error handling and retry logic
- Attachment handling is unreliable
Complexity: Low (but limited scope)
4. Custom ETL Pipeline
Deploy enterprise ETL tools (Airbyte, Fivetran, or custom Airflow DAGs) to move data through a staging layer before pushing to Puzzel.
When to use it: When you have compliance-heavy requirements, are already centralising support data for BI, or need non-standard transformation logic.
Pros:
- Highly scalable, creates a permanent backup in your staging layer
- Full audit trail
Cons:
- Overkill for a standard point-to-point migration
- Highest engineering cost and infrastructure overhead
Complexity: High
5. Managed Migration Service
Hand the entire process to a team that has done it before.
When to use it: When your engineering team cannot absorb the project, when data integrity is paramount, or when you have complex data (large attachment volumes, multi-inbox structures, custom label taxonomies) and cannot afford data loss.
Pros:
- Fastest time to completion
- Built-in error handling, validation, and rollback
- No internal engineering hours consumed
Cons:
- External cost
Complexity: Low (for your team)
Migration Approach Comparison
| Approach | Historical Data | Attachments | Relationships | Scalability | Complexity |
|---|---|---|---|---|---|
| API-to-API | ✅ Full | ✅ Yes | ✅ Preserved | Medium (rate limits) | High |
| CSV + API Hybrid | ✅ Full | ⚠️ Separate step | ⚠️ Manual rebuild | Medium | Medium |
| Middleware (Zapier/Make) | ❌ New only | ⚠️ Limited | ⚠️ Partial | Low | Low |
| Custom ETL | ✅ Full | ✅ Yes | ✅ Preserved | High | High |
| Managed Service | ✅ Full | ✅ Yes | ✅ Preserved | High | Low (for you) |
Estimated Development Hours by Approach
| Approach | 1K Tickets | 10K Tickets | 50K Tickets | 100K+ Tickets |
|---|---|---|---|---|
| API-to-API | 20–30 hrs | 30–50 hrs | 40–80 hrs | 60–120 hrs |
| CSV + API Hybrid | 15–25 hrs | 25–40 hrs | 35–60 hrs | 50–90 hrs |
| Custom ETL | 30–50 hrs | 40–60 hrs | 50–90 hrs | 70–130 hrs |
Estimates include development, testing, and validation. The primary scaling factor is not code complexity but error handling, retry logic, and validation — which grow disproportionately with volume.
Recommendations by scenario:
- Small team, history doesn't matter: CSV for contacts, skip old tickets.
- Any team that needs history: API-to-API or managed service.
- Enterprise / high volume: Managed migration service to ensure zero data loss and strict compliance.
- Ongoing sync during phased rollout: Middleware for new records only.
Pre-Migration Planning
A successful migration is mostly planning. Before extracting data, complete this checklist.
Data Audit
Run counts against Enchant's API using the count=true parameter:
- Tickets — total count by state (
open,hold,closed,snoozed,archived) - Customers — total count, check for duplicates by email
- Users (agents) — list all, note which are active
- Labels — full list with IDs, map to Puzzel Categories or Tags
- Inboxes — list all, map to Puzzel Teams
- Attachments — estimate total volume (each must be downloaded and re-uploaded)
What to Leave Behind
Not everything deserves migration. Spam tickets, trashed tickets, and test data should stay behind. Enchant lets you filter these with spam=true and trash=true query parameters — exclude them from your extraction.
Tickets older than your retention policy can be exported to CSV for archival compliance rather than loaded into your active Puzzel environment.
Do not skip the data audit. Discovering you have 500,000 closed tickets instead of the expected 50,000 will fundamentally alter your rate limit strategy and timeline.
Data Residency and GDPR Considerations
For enterprise migrations, especially those involving EU customer data, plan for data residency compliance:
- Staging layer jurisdiction: If you use an intermediate database or file store during transformation, that staging layer processes personal data (names, emails, message content). Ensure it is hosted in a region compliant with your GDPR obligations.
- Data minimisation: Only extract and stage the fields you actually need in Puzzel. If Enchant contains data you will not migrate (e.g., CSAT free-text comments), do not extract it.
- Processing agreement: Both Enchant and Puzzel act as data processors. Confirm your DPA with Puzzel is in place before loading any personal data.
- Right to erasure backlog: If you have pending GDPR deletion requests in Enchant, process them before migration. Do not migrate data that should have been deleted.
- Transit encryption: All API calls to both Enchant and Puzzel use HTTPS/TLS. If you stage data on disk, encrypt at rest.
Migration Strategy
- Big bang: Migrate everything in a single cutover window. Works for small datasets (<10K tickets). Risk: if something breaks, all data is affected.
- Phased: Migrate by inbox/team. Lower risk, but requires running both systems temporarily.
- Incremental: Migrate historical data first, then run a final delta sync before cutover using
since_updated_atfilters. Best for large datasets.
For most help desks, a big bang cutover backed by a final delta sync is the safest path to avoid split-brain data issues.
Data Model and Object Mapping
This is where migrations succeed or fail. Enchant and Puzzel organise data differently, and you cannot do a 1:1 copy.
Object Mapping Table
| Enchant Object | Puzzel Case Management Object | Notes |
|---|---|---|
| Inbox | Team | Each Enchant Inbox maps to a Puzzel Team. Configure Teams before import. |
| User (agent) | User/Agent | Create agents in Puzzel first. Map by email address. |
| Customer | Contact / Organisation | Puzzel groups contacts under Organisations. Enchant has no org concept — you may need to infer it from email domain. |
| Ticket | Ticket (Case) | Core record. Map state, subject, timestamps. |
| Message (reply) | Ticket message (timeline) | Preserve direction (in/out), body, timestamps. |
| Message (note) | Ticket note | Internal notes. Map the public/private flag carefully to prevent accidental data exposure. |
| Label | Tag or Category | Enchant labels are flat. Puzzel Categories are structured with parent-child choices. Decide which labels become Tags (free-form) vs Categories (structured). |
| Attachment | Attachment | Download from Enchant, re-upload to Puzzel. |
| CSAT response | No direct equivalent | Puzzel handles satisfaction through separate reporting. Store CSAT data as a custom form field or internal note. |
| Webhook | Event Rule / Outbound Integration | Enchant webhooks fire on ticket events. Puzzel's equivalent is Event Rules combined with Outbound Integrations — both may require activation by Puzzel support. |
Field-Level Mapping
| Enchant Field | Type | Puzzel Field | Transformation |
|---|---|---|---|
ticket.id |
string | externalId or migration log |
Store for cross-reference. Puzzel assigns its own ID. |
ticket.number |
integer | Tag or form field | Store as a tag or custom field for cross-reference. |
ticket.subject |
string | Ticket subject | Direct map. Check max length. |
ticket.state |
string | Ticket status | Map: open→Open, closed→Resolved, hold→On Hold. See callout below for snoozed/archived. |
ticket.type |
string | Channel | Map email→Email, sms→SMS. Other types may need API channel. |
ticket.inbox_id |
string | Team | Map via your Inbox→Team mapping table. |
ticket.user_id |
string | Assigned user | Map via your User mapping table. |
ticket.label_ids |
array | Tags / Categories | Per your label mapping decisions. |
ticket.created_at |
timestamp | Created date | Direct map (both use ISO 8601). |
customer.first_name |
string | Contact first name | Direct map. |
customer.last_name |
string | Contact last name | Direct map. |
customer.contacts [].value |
string | Contact email/phone | Direct map. Lowercase and trim email before dedupe. |
message.body |
string | Message body | Check htmlized flag for HTML vs plain text. Sanitize HTML; rewrite inline image URLs. |
message.direction |
string | Message direction | in→inbound, out→outbound. |
Enchant's snoozed and archived ticket states have no direct Puzzel equivalent. Import these as Resolved tickets and add an internal note with the original state and snooze date for audit purposes. Critically, ensure you map these to a terminal Puzzel status — if you accidentally import them as "Open" or "In Progress," they will trigger SLA breach alerts and pollute agent queues.
Handling Custom Fields and Labels
Puzzel's custom fields are often tied to specific Categories. If you have custom fields on an Enchant Ticket, ensure the corresponding Puzzel Category is configured to accept those fields before initiating the import.
For labels, the mapping decision is the most debated part of the project. Use this decision framework:
- Operational labels (e.g., "urgent", "escalated", "VIP") → Puzzel Tags (free-form, searchable, no hierarchy needed)
- Classification labels (e.g., "Billing - Refund", "Shipping - Delayed") → Puzzel Categories with parent-child structure (Category: "Billing", Sub-choice: "Refund")
- Workflow labels (e.g., "needs-review", "waiting-on-vendor") → Puzzel Status or Event Rules (automate rather than tag)
- Deprecated or unused labels → Do not migrate. Clean up the taxonomy before migration.
Get stakeholder sign-off on the mapping table before writing any transformation logic. This step typically takes 1–3 days for teams with fewer than 50 labels and up to a week for teams with 200+.
Import Dependency Order
The critical dependency chain is: Users → Teams → Organisations → Customers → Tickets → Messages → Attachments.
Import in that order. If you create tickets before their associated customers exist in Puzzel, the relationship will be lost.
Migration Architecture
Enchant Extraction
Enchant's API is straightforward but slow at scale. Key constraints: (dev.enchant.com)
- Rate limit: 100 credits per minute, 6 requests per second burst limit
- Pagination: Max 100 records per page. For >10,000 tickets you must use
since_created_atinstead of page offsets — standard page-based pagination breaks at that threshold - Embedding: Use
embed=messages,customer,labelsto reduce round trips, but each embed type costs an additional rate limit credit - Webhooks: Enchant supports webhooks that fire on ticket creation, update, reply, label changes, and assignment changes. During the transition period, you can use these for near-real-time delta sync rather than polling with
since_updated_at. Configure a webhook endpoint that captures events and queues them for transformation and loading into Puzzel.
Extraction Time Estimates
| Dataset Size | Estimated Extraction Time | Notes |
|---|---|---|
| 1K tickets | ~30 minutes | Single-threaded, with embeds |
| 10K tickets | ~2–3 hours | Must switch to since_created_at pagination |
| 50K tickets | 10–15 hours | Schedule during off-hours |
| 100K tickets | 20–30 hours | Consider multi-day extraction with checkpointing |
These estimates assume embed=messages,customer,labels on every request (which costs 4 credits per request) and no other API consumers competing for your 100 credits/minute budget. If other integrations are hitting Enchant's API simultaneously, your budget shrinks proportionally.
Puzzel Loading
Puzzel's API supports ticket creation via the API ticket channel. You create an API channel in Settings → Ticket Channels → API, choose your authentication type (Basic Token or OAuth), and use that channel to POST tickets. (help.puzzel.com)
Authentication details:
- Basic Token: A static API key generated in the Puzzel admin interface. Sent as a Bearer token in the
Authorizationheader. Simplest option for migration scripts. - OAuth 2.0: Uses client credentials flow. Obtain
client_idandclient_secretfrom your Puzzel admin. Request a token from Puzzel's OAuth endpoint; tokens typically expire after 1 hour and must be refreshed. Implement token caching and automatic refresh in your migration script to avoid auth failures mid-run.
Key constraints:
- Puzzel's API documentation is served via Swagger UI from within the application (Help → API Documentation) — there is no publicly browsable API reference outside it
- Rate limit specifics are instance-dependent. The public sources do not publish numeric throughput limits, so benchmark safely in a pilot. Start with 1 request/second and increase until you observe
429responses, then back off 20%. - Ticket creation requires the team, channel, and organisation to already exist
- Attachments must be uploaded as part of the ticket creation payload or as a subsequent multipart/form-data POST to the message endpoint
- No publicly documented bulk import endpoint — tickets are created one at a time
Request Puzzel API access and documentation early — ideally 2–4 weeks before you plan to start development. The in-app-only documentation makes pre-integration planning harder than with most platforms. Navigate to Help → API Documentation within the Case Management interface. Export or screenshot the Swagger schemas for offline reference during development.
Data Transformation
Enchant returns timestamps in ISO 8601, which Puzzel also expects. HTML message bodies from Enchant must be sanitized to ensure they render correctly in Puzzel's UI. Lowercase and trim all email addresses before loading — Puzzel has previously fixed CSV-import duplication issues caused by case differences in email addresses. (help.puzzel.com)
Step-by-Step Migration Process
Step 1: Extract Data from Enchant
The code samples below are illustrative pseudocode showing the extraction, transformation, and loading patterns. They are not production-ready — you will need to add proper error handling, logging, connection pooling, and configuration management. The Puzzel API endpoint URLs are representative; verify exact paths from Puzzel's in-app Swagger documentation.
import requests
import time
import json
BASE_URL = "https://yoursite.enchant.com/api/v1"
HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}
def extract_tickets(since=None):
tickets = []
params = {
"per_page": 100,
"sort": "created_at",
"embed": "messages,customer,labels",
"count": "true"
}
if since:
params["since_created_at"] = since
page = 1
while True:
params["page"] = page
resp = requests.get(f"{BASE_URL}/tickets", headers=HEADERS, params=params)
if resp.status_code == 429:
wait = int(resp.headers.get("Rate-Limit-Reset", 20))
time.sleep(wait)
continue
data = resp.json()
if not data:
break
tickets.extend(data)
page += 1
# For >10K tickets, switch to since_created_at pagination
if page > 100:
last_created = data[-1]["created_at"]
return tickets + extract_tickets(since=last_created)
return ticketsStep 2: Transform Data
Build a transformation layer that maps Enchant records to Puzzel's expected schema:
STATE_MAP = {
"open": "Open",
"hold": "On Hold",
"closed": "Resolved",
"snoozed": "Resolved",
"archived": "Resolved"
}
def transform_ticket(enchant_ticket, user_map, team_map, label_map):
return {
"subject": enchant_ticket["subject"],
"status": STATE_MAP.get(enchant_ticket["state"], "Open"),
"team": team_map.get(enchant_ticket["inbox_id"]),
"assigned_user": user_map.get(enchant_ticket.get("user_id")),
"customer_email": extract_customer_email(enchant_ticket),
"created_at": enchant_ticket["created_at"],
"messages": [
transform_message(m) for m in enchant_ticket.get("messages", [])
],
"tags": [
label_map.get(lid) for lid in enchant_ticket.get("label_ids", [])
],
"notes": build_migration_notes(enchant_ticket)
}Step 3: Load into Puzzel Case Management
Use Puzzel's API ticket channel to create each ticket with its full message history. Follow the dependency order: create Organisations and Customers first, then Tickets, then replay Messages in chronological order, then upload Attachments.
def migrate_ticket(enchant_ticket, id_map):
puzzel_payload = {
"subject": enchant_ticket["subject"],
"contactId": id_map["contacts"].get(enchant_ticket["customer_id"]),
"assignedUserId": id_map["users"].get(enchant_ticket["assigned_to"]),
"status": map_status(enchant_ticket["state"]),
"categoryId": map_inbox_to_category(enchant_ticket["inbox_id"])
}
# Note: verify this endpoint from Puzzel's in-app Swagger docs.
# The URL below is illustrative.
response = requests.post(
"https://api.puzzel.com/case-management/v1/cases",
json=puzzel_payload,
headers={"Authorization": f"Bearer {PUZZEL_TOKEN}"}
)
if response.status_code == 201:
return response.json()["id"]
else:
log_error("Case Creation Failed", response.text)
return NoneFor every successfully created case, iterate through its Enchant message thread and push each reply and private note sequentially to preserve the timeline. Then download each attachment from Enchant, convert it to a multipart/form-data payload, and upload it to the corresponding Puzzel message.
Step 4: Validate
Run record count comparisons and field-level spot checks (see Validation section below).
Common Error Codes and Troubleshooting
Enchant API Errors
| HTTP Status | Meaning | Action |
|---|---|---|
401 Unauthorized |
Invalid or expired API token | Regenerate token in Enchant settings |
403 Forbidden |
Insufficient permissions | Ensure API user has admin access |
404 Not Found |
Invalid endpoint or deleted resource | Verify endpoint path; skip deleted records |
429 Too Many Requests |
Rate limit exceeded | Read Rate-Limit-Reset header; wait and retry |
500 Internal Server Error |
Enchant server issue | Retry with exponential backoff (max 3 retries) |
Puzzel API Errors
| HTTP Status | Likely Cause | Action |
|---|---|---|
400 Bad Request |
Malformed payload, missing required field | Log payload; check required fields (team, channel, contact) |
401 Unauthorized |
Expired OAuth token or invalid API key | Refresh token; verify API channel is active |
403 Forbidden |
API channel not enabled or feature not activated | Contact Puzzel support to enable API channel |
404 Not Found |
Referenced team, category, or contact does not exist | Verify dependency chain was loaded first |
409 Conflict |
Duplicate record (e.g., contact with same email) | Check existing records; merge or skip |
413 Payload Too Large |
Attachment exceeds size limit | Puzzel blocks payloads over 40 MB. Split or archive oversized attachments |
ERROR status on email payloads |
Attachment contains blocked file extension | See attachment constraints below; archive unsupported file types separately |
Implement structured error logging that captures the full request payload, response body, HTTP status, and timestamp for every failed API call. Without this, debugging failures across tens of thousands of records becomes impossible.
Edge Cases and Challenges
-
Inline images: Images pasted directly into Enchant emails are often hosted on Enchant's CDN. If you only migrate the HTML text, the
<img>tags will break when Enchant is decommissioned. Parse the HTML, download each image, upload it to Puzzel, and rewrite thesrcattribute in the HTML body. -
Duplicate customers: Enchant allows multiple customer records with the same email. Puzzel auto-creates customers from email/mobile identifiers on inbound ticket creation. De-duplicate before loading, or you will create duplicate Organisations. Normalize email case and phone format (E.164 for phone numbers) before import. (help.puzzel.com)
-
Multi-contact customers: An Enchant customer can have email, phone, and Twitter contacts. Puzzel's contact model may not support all three as first-class identifiers — test which fields are available on your Puzzel instance before writing the loader. For unsupported contact types (e.g., Twitter handles), store them as a custom field or internal note.
-
Status mapping: Enchant has a simple state model (
open,hold,closed,snoozed,archived). Puzzel often has granular SLA-driven states (New, In Progress, Waiting on Customer, Resolved). Map closed Enchant tickets to a terminal Puzzel state to prevent them from triggering SLA breach alerts upon import. -
Label-to-Category mapping: Enchant labels are flat strings. Puzzel Categories are structured hierarchies. A label like "Billing - Refund" needs to become Category "Billing" with sub-choice "Refund" — parse and split during transformation.
-
HTML message bodies: Enchant's
htmlizedflag indicates whether the body is HTML. Puzzel may strip or reformat HTML — test with representative samples (especially emails with tables, embedded CSS, and signature blocks) before the full migration. -
Attachments at scale: Enchant serves attachments as Base64 via the API. Each file must be downloaded, stored temporarily, and re-uploaded to Puzzel. Puzzel blocks many executable and script extensions (
.exe,.bat,.js,.vbs, and others) and returnsERRORstatus for email payloads over 40 MB. For large attachment volumes (10K+ files), this is the slowest part of the migration. Unsupported file types need an archive strategy — store them in cloud storage and link from an internal note. (help.puzzel.com) -
Author override: When creating historical messages via the API, Puzzel may default the author to the API user rather than the historical agent. Check Puzzel's in-app API documentation for author override or impersonation parameters. If no override exists, add an internal note on each message stating the original author and timestamp.
-
Private notes and Customer Hub visibility: Puzzel can expose notes and forwarded content through authenticated API channels or Customer Hub if those settings are enabled. This is a significant data exposure risk: if Customer Hub is active on your Puzzel instance, migrated internal notes may become visible to end customers unless explicitly marked as private. Verify visibility settings in Settings → Customer Hub → Ticket Visibility before loading any data. Keep internal notes private by default. (help.puzzel.com)
-
Multi-recipient threads: Enchant handles CCs and BCCs natively. Ensure Puzzel's case configuration captures secondary email addresses so historical context is not lost if a CC'd user replies to an old thread.
-
CSAT data: Enchant stores satisfaction ratings on tickets. Puzzel has no equivalent field in the standard ticket schema. Store CSAT scores as a custom form field (if you need to report on them) or internal note (if archival only). Include the rating value, any free-text comment, and the timestamp.
Limitations and Constraints
Enchant side:
- No bulk export API — every record must be paginated through the REST API
- Page-based pagination breaks after 10,000 records; must switch to
since_created_at - The API only creates email type tickets on write. If you need temporary bi-directional coexistence across non-email channels, the source side cannot be mirrored 1:1. (dev.enchant.com)
- Rate limit (100 credits/minute) is shared across all API consumers on your account
- Webhooks support ticket creation, update, reply, label, and assignment events — useful for delta sync but not for bulk historical extraction
Puzzel side:
- API documentation is only accessible from within the application (Help → API Documentation), making pre-planning difficult
- Some features (Outbound Integrations, Event Rules, Response Mappings) require activation by Puzzel's support team — request these early
- Data model is team-centric — tickets belong to Teams, and Teams define which Categories and Forms are available. Teams must be configured exactly right before import.
- No publicly documented bulk import API — tickets are created one at a time
- Puzzel's public model does not expose a generic custom-object framework. This is the biggest structural limitation if your Enchant data includes non-standard structures. (help.puzzel.com)
- API rate limits are instance-dependent; benchmark safely in a pilot
- Customer Hub may expose migrated data to end customers if not configured correctly (see edge cases above)
Validation and Testing
Validation is not optional. A 200 OK response does not mean the data is correct. Run these checks before declaring the migration complete:
- Record count comparison: Total tickets in Enchant (by state) vs total tickets in Puzzel (by status). They must match exactly. Any discrepancy must be traced to a specific skipped, failed, or duplicated record.
- Customer count comparison: Total unique customers in Enchant vs total contacts/organisations in Puzzel. Account for de-duplication reducing the count.
- Message count per ticket: Sample 50–100 tickets across different sizes (1 message, 5 messages, 20+ messages) and verify message counts match.
- Attachment spot check: Sample 20 tickets with attachments. Verify files open correctly in Puzzel and are associated with the correct message.
- Field-level validation: Check that subject, status, timestamps, and assigned agent match for a random sample of at least 50 tickets.
- Relationship integrity: Verify that tickets are linked to the correct customer and team in Puzzel.
- Private note visibility: Verify that internal notes are not visible to customers via Customer Hub or public-facing channels.
- SLA state check: Confirm that migrated closed/resolved tickets are not triggering SLA breach alerts.
- Delta sync test: Run a test delta sync to ensure tickets updated in Enchant after the initial bulk load correctly update the corresponding Puzzel case.
- Inline image rendering: Open 10 tickets with inline images and verify all images render in Puzzel's UI.
The single most useful artifact in validation is a source-to-target ID mapping table stored in a database (SQLite minimum, Postgres recommended) with columns for: Enchant ID, Puzzel ID, object type, migration status (success/fail/skipped), error message, and timestamp. This table is your single source of truth for reconciliation, rollback, and audit.
Rollback Plan
Before you start loading data into Puzzel, document your rollback procedure:
-
Fresh Puzzel instance: Rollback is straightforward — wipe the instance and start over. Confirm with Puzzel support that a full tenant reset is available and understand the turnaround time.
-
Active Puzzel instance: Tag all migrated tickets with a
migration-batch-001tag (or similar) and all migrated contacts with a corresponding tag. If rollback is needed, you can identify and isolate migrated records. However, note that Puzzel does not publicly document a bulk delete API endpoint. Rollback on an active instance may require:- Using Puzzel's in-app bulk actions to close/delete tagged tickets (verify available bulk actions in your instance)
- Requesting Puzzel support to perform a bulk deletion from their side
- Accepting that some migrated data may need to be manually cleaned
-
Partial rollback: If only specific inboxes/teams failed, you can re-run the migration for those teams only, using your ID mapping table to skip already-successful records.
Test your rollback procedure on 100 records before running the full migration.
Post-Migration Tasks
Once the data is in Puzzel Case Management:
- Rebuild automations: Enchant's trigger and automation rules do not migrate. Recreate them as Event Rules and Inbound Rules in Puzzel. Map each Enchant automation to its Puzzel equivalent before cutover.
- Configure SLAs: Puzzel's SLA engine is more granular than Enchant's. Set response and resolution time targets per team. Ensure migrated closed tickets do not count against SLA metrics.
- Update integrations: Any third-party tools connected to Enchant (Slack, CRM, e-commerce) must be reconnected to Puzzel. Document every Enchant integration endpoint and its Puzzel equivalent.
- Train agents: Puzzel's interface is significantly different from Enchant's shared inbox. Plan at least one training session focused on the ticket view, category selection, and team queue workflows. Budget 2–4 hours per agent.
- Monitor for 2 weeks: Watch for missing data, broken customer links, or tickets that landed in the wrong team. Puzzel's integration activity logs can help catch drift early. (help.puzzel.com)
- Decommission Enchant: Once you have verified the delta sync is complete and all email forwarding rules point to Puzzel, revoke user access to Enchant and export a final compliance backup. Keep the Enchant account active (read-only) for 30–90 days in case you need to reference original records.
Best Practices
- Back up everything first. Extract a full dump from Enchant's API before starting. Store it in versioned JSON files with checksums. This is your insurance policy.
- Run a test migration. Migrate one inbox (100–500 tickets) into a Puzzel sandbox and validate before doing the full run. This test will surface 80% of your edge cases.
- Map labels before you code. The label→category/tag mapping is the most debated part of the project. Get stakeholder sign-off on the mapping table before writing transformation logic.
- Freeze configuration. Implement a change freeze in Enchant two weeks before the migration. No new custom fields, no new users, no altered inbox structures.
- Migrate in batches. Do not attempt to push 500,000 records in a single script execution. Batch them by year or by inbox to isolate errors and enable targeted re-runs.
- Use incremental extraction. Enchant's
since_updated_atparameter lets you pull only changed records. Use it for delta syncs during the transition period. Alternatively, configure Enchant webhooks for near-real-time event capture. - Log everything. Every API call, every transformation decision, every error. Maintain a structured database (SQLite minimum, Postgres recommended) of every request, response, source ID, target ID, and outcome. Without this log, rollback and reconciliation become guesswork.
- Schedule extraction during off-hours. Enchant's 100 credits/minute limit is shared across all API consumers on your account. Running extraction during business hours will degrade performance for agents using Enchant.
- Version-lock your scripts. Tag your migration code in version control before each run. If you need to re-run or debug, you need to know exactly which code produced each batch.
When to Use a Managed Migration Service
Building a custom API-to-API migration between Enchant and Puzzel is feasible, but it absorbs real engineering time. For a 50K-ticket migration, expect 40–80 hours of development, testing, and validation work — not counting the time spent learning Puzzel's API from within the application.
The hidden cost of DIY is rarely extraction. It is mapping decisions, retry logic, reconciliation, UAT, re-runs, and go-live support. Teams consistently underestimate the time spent on edge cases (inline images, duplicate customers, attachment failures) relative to the "happy path" development.
Consider outsourcing when:
- Your engineering team is already at capacity
- You have complex label taxonomies that need careful mapping to Puzzel's category system
- Attachment volumes are high (10K+ files)
- You need the migration completed in days, not weeks
- You cannot afford data loss or extended downtime
- GDPR or data residency requirements demand a documented, auditable migration process
Frequently Asked Questions
- Can I migrate historical tickets from Enchant to Puzzel Case Management?
- Yes, but there is no native import tool. You must extract tickets via Enchant's REST API and load them into Puzzel using its API ticket channel. Both platforms use JSON-based REST APIs, so an API-to-API migration script is the most reliable approach. CSV imports only cover customers and contacts, not full ticket history.
- What are Enchant's API rate limits for data extraction?
- Enchant's API is limited to 100 credits per minute per account with a secondary burst limit of 6 requests per second. Embedding related resources (messages, customers, labels) costs additional credits per embed type. For large datasets (50K+ tickets), expect extraction to take 10+ hours.
- How do Enchant labels map to Puzzel Case Management?
- Enchant uses flat labels on tickets. Puzzel Case Management has both Tags (free-form) and Categories (structured, hierarchical choices). Simple labels can map to Tags. Labels that represent structured classification (e.g., 'Billing - Refund') should be split into Puzzel Categories with parent-child choices.
- Does Puzzel Case Management have a bulk import API?
- Puzzel Case Management does not publicly document a bulk import endpoint. Tickets are created individually via the API ticket channel. For large migrations, this means building a script that creates tickets one at a time with proper rate limiting and error handling.
- How long does an Enchant to Puzzel migration take?
- It depends on data volume. A small migration (under 5,000 tickets) can be completed in 1–2 days. Larger datasets (50K+ tickets with attachments) may take 1–2 weeks including extraction, transformation, loading, and validation. A managed migration service can compress this timeline.

