Skip to content

Desk365 to HappyFox Migration: A Technical Guide

Technical guide to migrating from Desk365 to HappyFox. Covers API extraction, field mapping, conversation history, attachments, rate limits, and what can't be migrated.

Raaj Raaj · · 22 min read
Desk365 to HappyFox Migration: A 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

What Is a Desk365 to HappyFox Migration?

Info

TL;DR: Desk365 → HappyFox Migration

A Desk365 to HappyFox migration is moderately complex and typically takes 5–15 business days for a mid-size dataset of 5,000–50,000 tickets. The single biggest risk is losing conversation history: Desk365's native CSV export includes ticket metadata but not reply threads or internal notes. You must use the Desk365 REST API v3 to extract full ticket data and HappyFox's REST API v1.1 to create tickets with preserved threads. Desk365's API caps extraction at 10,000 tickets per hour. HappyFox allows 300 POST requests per minute with a 10-minute lockout if exceeded. The migration also requires decoupling your identity model from Microsoft Entra ID (Azure AD) and mapping Desk365's Group + Category structure to HappyFox's single-layer Category model. Automation rules, SLAs, and canned responses cannot be migrated programmatically — they must be rebuilt manually. Teams with fewer than 5,000 tickets and flat custom fields can self-serve with API scripting. For larger datasets or zero-downtime requirements, a managed migration is the safer path.

A Desk365 to HappyFox migration is the extraction of tickets, contacts, custom fields, tags, knowledge base articles, and attachments from Desk365's Microsoft 365-tethered environment, and the structural transformation of that data for ingestion into HappyFox Help Desk while preserving conversation history, timestamps, and relational integrity.

This is not a CSV copy-paste operation. Desk365 stores data as discrete tickets with statuses, priorities, types, groups, and custom fields — a traditional ITSM-style model tied to Microsoft Entra ID for user identity. HappyFox uses a category-centric model where custom fields are associated with specific categories, contacts are indexed by email, and ticket updates reference internal IDs rather than human-readable values. Getting the mapping right between these two models is where most migrations succeed or fail.

For detailed guidance on extracting data from the source platform, see How to Export Data from Desk365: Methods, API Limits & Portability.

Why Teams Move from Desk365 to HappyFox

Desk365 is highly optimized for internal IT teams operating inside Microsoft Teams. Organizations typically outgrow it and move to HappyFox for three reasons:

  1. Unlimited-agent pricing. Desk365 charges per agent — $12/agent/month on Standard, $22 on Plus, $32 on Premium. HappyFox offers unlimited-agent plans starting at $1,499/month, which is cheaper for teams with 50+ agents (this flat-rate model is also a major driver for teams migrating from Zendesk to HappyFox). A 60-agent team on Desk365 Premium pays $1,920/month vs. HappyFox's $1,499 flat.

  2. Multi-brand, category-driven workflows and omnichannel support. HappyFox's category system lets teams run multiple support brands with distinct custom fields, SLAs, and agent visibility per category. It supports email, web portal, chat, and social channels natively. Desk365's group structure is flatter and oriented toward internal Teams-based ticket submission.

  3. Security certifications and platform independence. HappyFox holds SOC 2 Type II and HIPAA compliance certifications, which matters for regulated industries. Companies looking to decouple core operational tools from the Microsoft 365 ecosystem prefer HappyFox's standalone architecture.

Warning

Honest trade-off: If your team is small (under 20 agents), deeply integrated into Microsoft Teams, and relies on Desk365's native Teams ticketing, the move to HappyFox may not pay off. HappyFox's Teams integration is less native than Desk365's, which was purpose-built for the Microsoft 365 ecosystem.

Data Model Differences: Desk365 vs. HappyFox

Understanding the structural differences between these two platforms prevents most mapping errors.

Concept Desk365 HappyFox
Ticket container Groups + Categories/Sub-categories Categories (with prefix-based ticket IDs)
Custom fields cf_ prefix, scoped globally t-cf-{id} pattern, scoped per category
Ticket replies Threaded replies + internal notes Updates (staff reply, user reply, private note)
Contacts Contacts tied to Entra ID / UPN Contacts indexed by primary email
Agents Agents assigned to groups Staff assigned to categories
Automation Automation rules Smart Rules
SLAs SLA policies with business hours SLA policies per category
Knowledge base Articles in sections/categories Articles in sections within categories
Attachments Stored on ticket + replies Stored on ticket + updates

Identity and Contact Mapping

In Desk365, user identity is intrinsically linked to Microsoft Entra ID (formerly Azure AD)—a structural dependency that requires a complete identity model rebuild during any external move, such as a Desk365 to LiveChat migration. A user's profile relies on their User Principal Name (UPN) or Microsoft 365 email address.

HappyFox uses a traditional, independent contact database indexed by primary email address. Before migrating any tickets, extract the complete user list from Desk365 and use the Entra ID email as the primary key to create contacts in HappyFox via POST /api/1.1/json/users/. If your organization uses aliases or secondary domains, normalize these email addresses during extraction to prevent duplicate contact creation.

Groups + Categories → HappyFox Categories: The Flattening Decision

The biggest structural gap: Desk365's Groups do not map 1:1 to HappyFox Categories. In Desk365, groups determine agent assignment and visibility, while categories and sub-categories organize ticket types. In HappyFox, a single Category handles both — it controls agent visibility, ticket routing, custom field association, and SLA assignment.

You must decide how to flatten or merge Desk365's two-layer structure into HappyFox's single-layer category model before writing any migration scripts. Use this decision framework:

Option A: One HappyFox Category per Desk365 Group-Category combination

  • Choose when: Groups map to departments (IT, HR, Facilities) and Categories map to ticket types (Hardware, Software, Access). Each combination is meaningfully distinct.
  • Example: Desk365 IT / Hardware → HappyFox IT - Hardware, Desk365 IT / Software → HappyFox IT - Software
  • Result: Higher category count (potentially 20–50+ categories), but granular SLA and field control per category. Best for organizations that need different SLAs or custom fields per ticket type within a department.

Option B: One HappyFox Category per Desk365 Group

  • Choose when: Categories and Sub-categories are used loosely or inconsistently across agents, or when Desk365 categories overlap significantly across groups.
  • Example: Desk365 Groups IT, HR, Facilities → HappyFox Categories IT, HR, Facilities
  • Result: Fewer categories, simpler routing, but loss of sub-category granularity. Ticket type differentiation moves to a custom field.

Option C: Consolidate Groups into a single HappyFox Category with routing by custom field

  • Choose when: You have a flat support team with no meaningful per-group SLA differentiation, or when migrating into an existing HappyFox instance that already has established categories.
  • Result: Simplest setup, but requires a "Source Department" or "Ticket Type" custom field to preserve the routing metadata.

Define your HappyFox Categories before writing any migration scripts. Every ticket migrated requires a valid Category ID in the payload. Changing the category structure mid-migration requires remapping and re-importing affected tickets.

Three Migration Methods Compared

Method 1: CSV Export → CSV Import

How it works: Export tickets from Desk365 as CSV via the agent portal, then use HappyFox's built-in CSV import tool.

When to use: Datasets under 1,000 tickets where conversation history is not essential.

Limitations:

  • Desk365 CSV exports include ticket metadata (number, subject, description, status, priority, created time, contact info) but do not include full conversation threads — no reply content, no internal notes
  • HappyFox's CSV import creates tickets with a single "Text" entry as the first message; subsequent replies can only be combined into one private note
  • No attachment migration path via CSV
  • No timestamp preservation for original creation dates
Danger

CSV-to-CSV migration gives you ticket stubs, not complete ticket records. For any team that needs historical thread data for compliance or support continuity, this method is inadequate.

Method 2: API-to-API Scripted Migration

How it works: Extract tickets, contacts, and KB articles from Desk365 using the v3 REST API. Transform the data to match HappyFox's model. Load into HappyFox via the v1.1 REST API.

When to use: Any migration where conversation history, custom fields, and data integrity matter.

Key constraints:

  • Desk365 API v3 allows retrieval of 30, 50, or 100 tickets per call, capped at 10,000 tickets per hour
  • HappyFox API v1.1 allows 300 POST requests per minute, with a 10-minute lockout if exceeded (HTTP 429)
  • HappyFox supports bulk ticket creation — up to 100 tickets per request via the bulk endpoint
  • Attachments require multipart/form-data POST requests

Method 3: Managed Migration Service

How it works: A migration partner handles extraction, transformation, loading, validation, and delta sync.

When to use: Datasets over 10,000 tickets, complex custom field mappings, zero-downtime requirements, or compliance-sensitive environments.

For more on keeping support operations running during migration, see Zero-Downtime Help Desk Data Migration.

Extracting Data from Desk365

CSV Export Path

Desk365 offers export options from the agent portal: All Tickets, Current Ticket View, Custom View, Search Tickets, and Time Entries. Exports are delivered as CSV files to your email inbox.

Warning

To export your complete ticket set, you must export from both the All Tickets and Archived Tickets views separately — Desk365 does not combine them in a single export.

Default fields in every export: Ticket Number, Subject, Description, Source, Created Time, Contact Name, and Contact Email. You can add status, priority, category, sub-category, type, and custom fields.

For KB export details, see How to Export Desk365 Knowledge Base Data: API, Limits & Methods.

API Extraction Path

The Desk365 REST API v3 is the only way to get full ticket data including reply threads.

Authentication: API key-based. Find your key in Settings → Integrations → API. Pass the key as a request header: X-Api-Key: {your_api_key}. All requests go through your subdomain: https://<yoursubdomain>.desk365.io/v3/.

Key endpoints for migration:

GET /v3/tickets?ticket_count=100&page={n}  # List tickets with pagination
GET /v3/tickets/{id}                        # Single ticket with replies
GET /v3/contacts                            # List contacts
GET /v3/knowledge-base/articles             # KB articles

Rate limit: 10,000 tickets per hour. At 100 tickets per call, that's 100 list-endpoint calls per hour. Individual ticket detail calls (needed for full reply threads) count separately against this hourly cap — for a 20,000-ticket migration, you'll need two hours minimum just for detail extraction, not counting contact or KB calls.

Estimating attachment volume before you start: Run GET /v3/tickets?ticket_count=100 across your full ticket set and sum the attachments_count field returned in each ticket record. Multiply average attachment size (check a representative sample via GET /v3/tickets/{id}) by total attachment count to estimate total storage transfer volume. This prevents mid-migration surprises when staging storage fills up.

Custom field format: Desk365 v3 returns custom fields with a cf_ prefix (e.g., cf_department, cf_employee_id). The API returns ticket descriptions in both HTML (description) and plain text (description_text) — use the HTML version to preserve formatting in HappyFox.

Delta sync query parameter: To extract only tickets updated since a specific timestamp (required for Phase 3 delta syncs), use the updated_since parameter: GET /v3/tickets?updated_since={ISO8601_timestamp}&ticket_count=100. This returns tickets where the updated_at field is greater than or equal to the specified timestamp. Store your last extraction timestamp in a local file and use it as the updated_since value for each subsequent delta run. Note: Desk365's API does not expose a "deleted tickets" endpoint — tickets deleted in Desk365 after extraction will remain as orphaned records in HappyFox unless you reconcile via a separate count check.

Do not attempt to extract from Desk365 and push to HappyFox in real-time. Network timeouts and rate limit collisions will cause data loss. Extract to an intermediate store (local database or secure middleware server) first, then load into HappyFox as a separate phase.

Loading Data into HappyFox

HappyFox CSV Import

HappyFox offers a built-in CSV import tool for ticket migration. Its key limitation: it does not support importing individual reply messages as separate updates on a ticket.

The "Text" column becomes the first message. All subsequent correspondence must be concatenated and imported as a single private note. A 15-reply ticket thread becomes two entries: one initial message and one wall-of-text note.

HappyFox API Loading

The HappyFox API v1.1 is the proper path for full-fidelity migration.

Authentication: API key + auth code, passed via HTTP Basic Auth. Encode {api_key}:{auth_code} in Base64 and send as Authorization: Basic {encoded_value}. Retrieve your API key and auth code from Settings → Apps & Integrations → API in your HappyFox account.

Key endpoints for import:

POST /api/1.1/json/tickets/                    # Create single ticket
POST /api/1.1/json/tickets/bulk/                # Create up to 100 tickets
POST /api/1.1/json/ticket/{number}/staff_update/ # Add staff reply/note
POST /api/1.1/json/ticket/{number}/user_reply/   # Add user reply
GET  /api/1.1/json/categories/                  # List categories (get IDs)
GET  /api/1.1/json/ticket_custom_fields/         # List custom fields (get IDs)
GET  /api/1.1/json/staff/                        # List staff (get IDs)

Rate limits: 500 GET requests/minute and 300 POST requests/minute. Exceeding either triggers a 429 response with a 10-minute cooldown. These are account-wide limits — if any other integration (Zapier, webhook receivers) is making POST calls during your migration window, those count against the same limit.

Error handling for bulk requests: The bulk endpoint (POST /api/1.1/json/tickets/bulk/) processes up to 100 tickets per request but does not guarantee atomic success. A batch where 70 tickets succeed and 30 fail will return HTTP 207 (Multi-Status) with per-ticket status codes in the response body. Your script must parse this response and re-queue failed tickets individually. Common causes of per-ticket failures within a successful batch: invalid category ID, missing required custom field, or staff ID that doesn't exist. Log the full response body for every bulk call — do not assume HTTP 200 means all 100 tickets were created.

HTTP status codes to handle:

Code Meaning Action
200/201 Success Continue
207 Partial success (bulk) Parse per-ticket results, re-queue failures
400 Bad request (field validation) Log payload, fix mapping, retry
401 Auth failure Check API key/auth code
429 Rate limit exceeded Wait 10 minutes, then resume with exponential backoff
500 Server error Wait 60 seconds, retry up to 3 times, then escalate

Suppressing notifications and Smart Rules during import: Bulk-creating thousands of tickets will trigger HappyFox Smart Rules and send notification emails to agents and customers for every ticket unless suppressed. Before starting your migration load phase, disable all Smart Rules in Settings → Smart Rules. Also disable outbound email notifications in Settings → Notifications. Re-enable both after validation is complete. Failure to do this during a 50,000-ticket import will result in 50,000 agent notification emails and potentially Smart Rule actions (auto-assignments, status changes) firing on historical closed tickets.

Tip

Throughput math: At 300 POSTs/minute and 100 tickets per bulk request, you can theoretically create 30,000 tickets per minute. In practice, you'll hit 429s well before that because staff_update and user_reply calls also count against the 300 POST/minute limit. Budget for ~150 complete tickets per minute (creation + 2–3 reply updates each) with backoff logic. Stay under 250 POSTs/minute to leave headroom.

EU-hosted accounts: If your HappyFox instance is hosted in the EU, use <instance>.happyfox.net instead of <instance>.happyfox.com.

Staging environment: HappyFox does not provide a dedicated sandbox or staging environment on standard plans. Test migrations must be run against a separate trial account or cleaned up manually via the API after validation. Factor cleanup time into your test phase planning — deleting 1,000 test tickets via the API at HappyFox's DELETE rate limits takes longer than creating them.

Field Mapping Reference

This is the mapping table you'll build your transform script around.

Desk365 Field HappyFox Field Notes
Ticket Number (none — auto-generated) Store Desk365 number in a custom field for cross-reference
Subject subject Direct 1:1
Description (HTML) text (on create) Use HTML version
Status status (ID) Map by name → ID lookup
Priority priority (ID) Map by name → ID lookup
Group + Category category (ID) Requires structural decision — see flattening framework above
Agent assignee (staff ID) Pre-create all staff, then map
Contact Email email HappyFox auto-creates contacts
Contact Name name Passed on ticket creation
Custom fields (cf_*) t-cf-{id} Map each field individually
Tags tags Not natively supported on create via API — apply via update
Created Time (not preserved on standard create) Requires special handling — see timestamp note below
Attachments attachments (multipart) Must download from Desk365 first

Ticket Number Continuity

HappyFox auto-generates ticket IDs using a category-specific prefix (e.g., IT-1045). If you are migrating into an existing HappyFox instance that already has tickets, the auto-generated IDs will continue from the existing sequence — they will not conflict with Desk365's numeric IDs. However, any external systems (Power Automate flows, Slack integrations, spreadsheets) that reference Desk365 ticket numbers by ID will break. Store the original Desk365 ticket number in a dedicated HappyFox custom field (e.g., cf_desk365_ticket_id) on every migrated ticket. This preserves cross-reference ability for agents and audit purposes.

Custom Field Mapping

HappyFox custom fields use a t-cf-{id} reference pattern where dropdown options must be specified by their internal choice ID, not the display text. A Desk365 dropdown value of "Billing" might map to choice ID 47 in HappyFox. Passing the string value instead of the ID will silently fail or create tickets with null field values.

Required workflow:

  1. Create all custom fields in HappyFox first (manually or via API)
  2. Fetch the field definitions from /api/1.1/json/ticket_custom_fields/
  3. Build a lookup table: {desk365_field_name → happyfox_field_id, desk365_value → happyfox_choice_id}
  4. Apply during transform

HappyFox custom fields are scoped per category. If you have a field that should appear in multiple categories, you must associate it with each — and the same field can have different required/optional status per category. A required custom field with no value in the migration payload will cause the entire ticket creation to fail with HTTP 400, even in a bulk request.

Preserving Conversation History

This is where most Desk365-to-HappyFox migrations break down.

The problem: Desk365's CSV export includes only the ticket description (initial message). Reply threads — agent responses, customer replies, internal notes — are not included in the CSV. You must use the Desk365 API to extract complete conversation history.

The HappyFox constraint: HappyFox's CSV import tool cannot recreate individual replies as separate ticket updates (a flattening limitation that also affects teams migrating from HappyFox to Zendesk via CSV export). It flattens everything into a single text entry plus one optional private note.

The solution: Use the API on both sides. Extract each ticket's full reply chain from Desk365 via API, then replay the conversation in HappyFox by calling the staff_update and user_reply endpoints for each message in chronological order.

import requests
import time
from requests.auth import HTTPBasicAuth
 
DESK365_BASE = "https://{subdomain}.desk365.io/v3"
DESK365_HEADERS = {"X-Api-Key": "{your_desk365_api_key}"}
 
HAPPYFOX_BASE = "https://{instance}.happyfox.com/api/1.1/json"
HAPPYFOX_AUTH = HTTPBasicAuth("{api_key}", "{auth_code}")
 
def post_with_backoff(url, data, files=None, max_retries=5):
    """POST with exponential backoff on 429 and retry on 500."""
    delay = 60  # Start with 60s on 429 (10-minute lockout minimum)
    for attempt in range(max_retries):
        resp = requests.post(url, data=data, files=files, auth=HAPPYFOX_AUTH)
        if resp.status_code in (200, 201, 207):
            return resp
        elif resp.status_code == 429:
            print(f"Rate limited. Waiting {delay}s before retry {attempt + 1}.")
            time.sleep(delay)
            delay = min(delay * 2, 600)  # Cap at 10 minutes
        elif resp.status_code == 500:
            print(f"Server error. Waiting 60s before retry {attempt + 1}.")
            time.sleep(60)
        else:
            print(f"Unrecoverable error {resp.status_code}: {resp.text}")
            resp.raise_for_status()
    raise Exception(f"Max retries exceeded for {url}")
 
def migrate_ticket(ticket):
    # Step 1: Create ticket in HappyFox
    create_payload = {
        "subject": ticket["subject"],
        "text": ticket["description"],  # HTML version
        "email": ticket["contact_email"],
        "name": ticket["contact_name"],
        "category": CATEGORY_MAP[ticket["group"]][ticket["category"]],
        "priority": PRIORITY_MAP[ticket["priority"]],
        "status": STATUS_MAP[ticket["status"]],
        "t-cf-{desk365_cf_id}": CHOICE_MAP.get(ticket.get("cf_department")),
    }
    resp = post_with_backoff(f"{HAPPYFOX_BASE}/tickets/", data=create_payload)
    hf_ticket_number = resp.json()["id"]
 
    # Step 2: Replay conversation history in chronological order
    for reply in sorted(ticket["replies"], key=lambda r: r["created_at"]):
        if reply["type"] == "agent_reply":
            update_payload = {
                "text": reply["body"],
                "update_type": "privatenote" if reply["is_private"] else "reply",
                "staff": STAFF_MAP[reply["agent_id"]],
            }
            post_with_backoff(
                f"{HAPPYFOX_BASE}/ticket/{hf_ticket_number}/staff_update/",
                data=update_payload
            )
        elif reply["type"] == "customer_reply":
            post_with_backoff(
                f"{HAPPYFOX_BASE}/ticket/{hf_ticket_number}/user_reply/",
                data={"text": reply["body"]}
            )
        time.sleep(0.25)  # ~240 reply calls/minute, within 300 POST/min limit

MS Teams messages that synced to Desk365 tickets are extracted as standard ticket replies via the Desk365 API. They follow the same replay pattern above.

Warning

Timestamp preservation: HappyFox's standard ticket creation API does not let you set a custom created_at timestamp. Tickets will show the import date as their creation date unless you coordinate with HappyFox support to enable timestamp override on import. Confirm this capability before starting your migration — a ticket from 2022 appearing as created today will wreck your reporting and SLA metrics.

Handling Attachments and Inline Images

Attachments require binary data transfer and strict authentication handling. Your script cannot simply pass the Desk365 attachment URL to HappyFox.

File Attachments

  1. Authenticate against the Desk365 API using X-Api-Key header
  2. Download the binary file to your middleware server
  3. Construct a multipart/form-data payload containing the file
  4. Upload the file to HappyFox and associate it with the correct ticket or update ID

Large attachments may time out during upload. Stage files locally and upload to HappyFox with retry logic using the same post_with_backoff pattern above.

Inline Images

If a user pasted an image directly into a Teams chat that synced to Desk365, that image is embedded in the HTML body of the ticket. If you migrate the HTML body as-is, the image src tag will still point to Desk365's servers. Once you decommission Desk365, those images will break — resulting in broken image icons across all historical tickets.

Your migration script must:

  1. Parse the HTML of every ticket body and reply using an HTML parser (e.g., BeautifulSoup in Python)
  2. Identify img tags pointing to Desk365-hosted URLs (domains containing desk365.io)
  3. Download those images using an authenticated Desk365 API request
  4. Upload them to HappyFox as attachments on the corresponding ticket or update
  5. Rewrite the HTML src tag to point to the new HappyFox-hosted URL before submitting the payload

The same applies to inline images in knowledge base articles.

Knowledge Base Migration

Desk365 organizes KB articles in categories and sections. HappyFox organizes articles within sections inside categories.

The migration path:

  1. Extract articles from Desk365 via API (including HTML body, section, and any embedded images)
  2. Create corresponding sections in HappyFox
  3. Upload articles via the HappyFox KB API or manually
  4. Re-upload embedded images — URLs pointing to Desk365's CDN will break after migration, so image URLs in article HTML must be rewritten using the same inline image process described above

Formatting (especially tables and embedded videos) often breaks during KB migration. Manually migrate high-traffic articles to ensure formatting integrity.

Execution Strategy: The 4-Phase Approach

Treat this migration as a software engineering project, not a weekend administrative task.

Phase 1: Environment Preparation and Mapping

Do not write extraction scripts until your HappyFox environment is fully configured.

  • Audit your Desk365 data: count total tickets (including archived), custom fields, contacts, KB articles, and attachment volume (use the method described in the API Extraction section above)
  • Decide on your Group-to-Category flattening strategy using the framework above; create all HappyFox Categories
  • Replicate all Custom Fields and document their internal HappyFox IDs via /api/1.1/json/ticket_custom_fields/
  • Pre-create all staff accounts in HappyFox and map Desk365 agents to HappyFox staff IDs via /api/1.1/json/staff/
  • Export the Desk365 user list and map Entra ID emails to HappyFox contacts
  • Build your complete field mapping lookup tables (categories, priorities, statuses, custom field choice IDs)
  • Create a dedicated HappyFox custom field to store original Desk365 ticket numbers
  • Create a subset of test data (100 closed tickets, 10 open tickets with replies, 5 tickets with attachments) for validation testing
  • Disable HappyFox Smart Rules and outbound notifications before any data load

Phase 2: Historical Sync

Extract all closed and resolved tickets from Desk365. Because these tickets are no longer active, you can migrate them over several days without impacting operations. This phase validates your attachment handling, timestamp preservation, inline image rewriting, and custom field mapping at scale.

Store extracted data in intermediate JSON files. Transform field values to HappyFox IDs. Load via the bulk endpoint (up to 100 tickets per request), then replay conversation history using staff_update and user_reply endpoints. Stay under 250 POSTs/minute to leave headroom for 429 avoidance. Parse every bulk response for HTTP 207 partial failures and re-queue failed tickets before moving to the next batch.

Phase 3: Delta Sync

Once the historical sync is complete, extract and migrate all active (open, pending) tickets.

Because active tickets are constantly changing, you need delta syncs — queries to Desk365 using GET /v3/tickets?updated_since={last_extraction_timestamp}&ticket_count=100 to catch tickets created or updated since the last extraction. Run these delta syncs daily leading up to the final cutover. Store your last-run timestamp after each successful delta sync and use it as the updated_since value for the next run. After each delta sync, run a count reconciliation: total tickets in Desk365 (from GET /v3/tickets metadata) vs. total tickets in HappyFox with the cf_desk365_ticket_id custom field populated.

Phase 4: Final Cutover

On the day of the transition:

  1. Halt all incoming ticket creation in Desk365 (update MX records, redirect support portals, disable Teams bots)
  2. Run the final delta sync to catch the last few updates
  3. Verify data integrity in HappyFox using the validation checklist below
  4. Manually rebuild SLA policies, Smart Rules, canned responses, and satisfaction surveys in HappyFox
  5. Re-enable Smart Rules and notifications in HappyFox
  6. Update any external integrations (Power Automate flows, webhooks)
  7. Route all new support traffic to HappyFox

With delta syncs, you achieve a zero-downtime migration. Your support team logs out of Desk365 on Friday and logs into HappyFox on Monday with all data up to date.

What Cannot Be Migrated Programmatically

APIs have limits. These items must be rebuilt manually in HappyFox:

  • Automation rules → Smart Rules: Desk365 automations and HappyFox Smart Rules use completely different configuration models. No export/import path exists.
  • SLA policies: Must be reconfigured manually per category.
  • Canned responses / Macros: Pre-written responses must be recreated.
  • Satisfaction surveys: Survey configurations and historical results do not transfer.
  • Agent roles and permissions: HappyFox's role system differs from Desk365's.
  • Microsoft Teams bot integration: Desk365's native Teams bot is purpose-built. HappyFox has a Teams integration, but it works differently. Workflows relying on Desk365's in-Teams ticket creation will need redesign.
  • Approval workflows: Desk365's approval management has no direct equivalent in HappyFox's standard help desk.
  • Power Automate flows: Any custom Power Automate integrations pointing to Desk365 must be rebuilt.

Migration Timeline and Effort Estimates

Dataset Size Method Estimated Effort Calendar Time
< 1,000 tickets CSV import (lossy) 8–16 hours 1–2 days
1,000–5,000 tickets API scripting 40–80 engineer-hours 5–8 days
5,000–25,000 tickets API scripting 80–120 engineer-hours 8–12 days
25,000–100,000 tickets Managed service 120–200 hours 10–15 days
100,000+ tickets Managed service Scoped per project 15–25 days

These estimates include extraction, transform, load, and validation. They do not include manual rebuild of automations, SLAs, and canned responses — add 1–3 days for that work depending on complexity.

Common Failure Modes

  1. Exceeding HappyFox's rate limit and getting locked out. The 10-minute cooldown on 429 errors means a single burst of writes can stall your entire migration. Implement exponential backoff starting at 60 seconds (not shorter — the lockout is 10 minutes minimum) and stay under 250 POSTs/minute to leave headroom.

  2. Custom field choice ID mismatches. Passing the display text "High" instead of the choice ID 3 will silently fail or create tickets with null field values. Required fields with missing values return HTTP 400 and fail the entire ticket creation. Always resolve to IDs before loading.

  3. Missing Desk365 archived tickets. Desk365 requires separate exports from All Tickets and Archived Tickets views. Teams that forget the archived export leave historical data behind.

  4. Broken inline images. Migrating HTML bodies without rewriting image URLs means every embedded image breaks once Desk365 is decommissioned. Parse every HTML body for img tags pointing to desk365.io domains before loading.

  5. Attachment timeouts. Large attachments may time out during upload. Download from Desk365, stage locally, and upload to HappyFox with retry logic.

  6. Duplicate contacts. HappyFox matches contacts by email address. If Desk365 has duplicate contacts with the same email (common with Entra ID aliases), HappyFox will merge them — which may not be what you want. Normalize email addresses during extraction.

  7. Smart Rules and notifications firing during import. Bulk-creating tickets into a live HappyFox account with active Smart Rules will trigger automations on historical closed tickets and send notification emails to every agent and customer. Disable both before any load phase.

  8. Bulk request partial failures ignored. HTTP 207 from the bulk endpoint does not mean all 100 tickets succeeded. Ignoring per-ticket failure codes in the response body will silently drop records. Always parse the full response.

  9. Orphaned records from deleted source tickets. Tickets deleted in Desk365 after extraction but before cutover will remain in HappyFox with no source record. Run a count reconciliation using the Desk365 API total count vs. HappyFox cf_desk365_ticket_id count before going live.

Post-Migration Validation Checklist

Run these checks before cutover:

  • Ticket count match: Total tickets in HappyFox (filtered by cf_desk365_ticket_id presence) equals total extracted from Desk365, including archived tickets
  • Reply count spot-check: Sample 50 tickets and verify reply counts match source
  • Custom field values: Verify dropdown values resolved correctly (not null, not wrong choice)
  • Required field coverage: Confirm no tickets have null values in fields marked required per category
  • Attachment accessibility: Open 20+ attachments across different tickets to confirm they're downloadable
  • Inline images: Verify embedded images render correctly in migrated ticket bodies and KB articles
  • Contact deduplication: Verify contact count is within expected range; spot-check alias normalization
  • Category assignment: Spot-check that tickets landed in the correct HappyFox categories
  • Agent assignment: Verify ticket assignment matches source (agents must exist in HappyFox first)
  • KB article rendering: Check that embedded images and formatting survived the move
  • Smart Rules disabled: Confirm no Smart Rules fired during load (check audit log)
  • Notification suppression: Confirm no outbound emails were sent during the load phase
  • Orphan check: Total HappyFox ticket count with cf_desk365_ticket_id populated matches final Desk365 ticket count
  • Bulk 207 log review: Confirm all partial failures from bulk requests were re-queued and resolved

When to DIY vs. Use a Managed Service

DIY makes sense when:

  • Ticket volume is under 5,000
  • Custom fields are flat (text, number — no multi-level dependent dropdowns)
  • Conversation history is not a hard requirement
  • You have a Python/Node developer available for 2–3 weeks
  • No compliance requirement for zero-downtime cutover

A managed service makes sense when:

  • Ticket volume exceeds 10,000
  • You need full conversation thread fidelity with timestamp preservation
  • Custom fields include dependent dropdowns or category-scoped fields
  • You're in a regulated industry requiring audit trail continuity
  • You can't afford a second migration attempt

Frequently Asked Questions

Can I migrate Desk365 tickets to HappyFox using CSV export?
Technically yes, but with major data loss. Desk365 CSV exports include ticket metadata but not reply threads or internal notes. HappyFox's CSV import flattens all replies into a single private note. For full conversation history, you must use both platforms' REST APIs.
What are the API rate limits for Desk365 and HappyFox during migration?
Desk365 API v3 allows up to 10,000 tickets per hour with a maximum of 100 tickets per call. HappyFox API v1.1 allows 500 GET requests and 300 POST requests per minute, with a 10-minute lockout if exceeded.
Can I preserve original ticket timestamps when migrating to HappyFox?
HappyFox's standard ticket creation API does not support custom created_at timestamps. Tickets will show the import date as their creation date. You must coordinate with HappyFox support to enable timestamp override for migration purposes.
How long does a Desk365 to HappyFox migration take?
For 1,000–5,000 tickets with API scripting: 5–8 business days. For 5,000–25,000 tickets: 8–12 days. For 25,000+ tickets with a managed service: 10–25 days. These estimates include extraction, transform, load, and validation but not manual rebuild of automations.
What Desk365 data cannot be migrated to HappyFox automatically?
Automation rules, SLA policies, canned responses, satisfaction surveys, agent roles and permissions, Microsoft Teams bot configurations, approval workflows, and Power Automate flows must all be rebuilt manually in HappyFox.

More from our Blog

Desk365 to LiveChat Migration: A Technical Guide
Migration Guide/Help Desk

Desk365 to LiveChat Migration: A Technical Guide

Technical guide for migrating from Desk365 to LiveChat + HelpDesk: API extraction, data model mapping, conversation transforms, attachments, and zero-downtime cutover.

Wahab Wahab · · 19 min read