How to Migrate from Gladly to Zendesk: The Complete Technical Guide
How to migrate from Gladly to Zendesk — object mapping, API limits, conversation splitting, attachment handling, and step-by-step process from migration engineers.
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
How to Migrate from Gladly to Zendesk: The Complete Technical Guide
TL;DR — Gladly to Zendesk Migration
Migrating from Gladly to Zendesk is a data-model translation problem, not a CSV job. Gladly's architecture centers on the Customer — a single, continuous conversation timeline per person. Zendesk centers on the Ticket — a discrete record with its own lifecycle. The biggest risk is silent truncation: Gladly's core history endpoints cap at 100 conversations per customer and 1,000 items per conversation with no standard pagination. You must use Zendesk's Ticket Import API (/api/v2/imports/tickets) to preserve historical timestamps. Realistic timeline: 10–17 business days depending on volume, attachment handling, and custom field complexity. Teams with fewer than 5,000 conversations and no attachment requirements can self-serve with API scripting. For anything larger — or if you need zero downtime and full attachment fidelity — a managed migration service is the safer path.
Last verified: June 2025. Rate limits, API endpoints, and OAuth deprecation dates confirmed against official Gladly and Zendesk developer documentation.
What Is a Gladly to Zendesk Migration?
A Gladly to Zendesk migration extracts Customers, Conversations, Conversation Items (individual messages, notes, and replies within a Conversation), Topics, Agents, Teams, Inboxes, Tasks, and Answers from Gladly's person-centric helpdesk and loads them into Zendesk as Users, Organizations, Tickets, Comments, Tags, Custom Fields, Groups, Macros, and Help Center articles.
Why Teams Move from Gladly to Zendesk
Teams leave Gladly for platform-specific reasons:
- Integration ecosystem. Zendesk's marketplace lists 1,500+ pre-built integrations. Gladly lists roughly 40 native integrations. Teams that need deep connections to CRMs (Salesforce, HubSpot), BI tools (Looker, Tableau), or ITSM workflows (Jira, ServiceNow) outgrow Gladly's ecosystem.
- Multi-brand and enterprise scale. Zendesk supports multi-brand instances, complex SLA policies, custom ticket statuses, and a mature RBAC model with up to 5 custom roles on Enterprise and unlimited on Enterprise Plus. Gladly targets mid-market consumer brands and lacks equivalent enterprise governance.
- Reporting and analytics. Zendesk Explore offers SQL-like custom reporting, scheduled dashboards, and cross-object analytics. Gladly's reporting is improving but remains less flexible for operations teams that need granular, ad-hoc data slicing.
The Architectural Clash: Person-Centric vs. Ticket-Centric
This is the core challenge. In Gladly, a Customer is the primary object. All interactions — email, chat, SMS, voice, social — flow into a single, lifelong conversation timeline per customer. There are no ticket numbers. Conversations are simply paused or resolved until the customer reaches out again. (help.gladly.com)
In Zendesk, the Ticket is the primary object. Each support interaction gets its own ID and its own status lifecycle (New → Open → Pending → On-hold → Solved → Closed). When a customer reaches out a month later about a new issue, a new ticket is created.
If you dump a Gladly customer's multi-year history into a single Zendesk ticket, you will break Zendesk's UI (comments become unscrollable beyond ~500 entries), hit comment limits, and render AI tools like Intelligent Triage useless because they score per-ticket, not per-timeline. Every Gladly Conversation must be mapped to one or more Zendesk Tickets, and every Conversation Item must be mapped to a Zendesk Comment. The splitting logic — deciding where one "ticket" ends and another begins within a continuous thread — is where most DIY migrations break.
How Does the Gladly to Zendesk Object Mapping Work?
The default mapping is Customer → User, Conversation → Ticket, and Conversation Item → Comment, with original Gladly IDs retained as custom fields or external IDs for reconciliation. The table below is an implementation pattern based on the documented source and destination models. (developer.gladly.com)
| Gladly Object | Zendesk Object | Notes / Caveats | Data Loss Risk |
|---|---|---|---|
| Customer | User (end-user) | Map emails, phones, and custom attributes. Preserve customerId as external_id or a custom user field. Merged customers return 301 errors in Gladly's API — follow the redirect to the canonical customer ID. |
Low |
| Customer → Company | Organization | Gladly's company association maps to Zendesk organization membership. If B2B, roll up by email domain. | Low |
| Conversation | Ticket(s) | One Gladly Conversation may produce multiple Zendesk tickets. Define a splitting strategy (by topic, by time gap, or by session). | Medium — splitting logic determines fidelity |
| Conversation Item | Comment | Each message, note, or reply becomes a Zendesk comment with public: true/false. Preserve author, timestamp, and channel. A Conversation Item is a single atomic message within a Conversation — it has a type (e.g., CHAT_MESSAGE, EMAIL, NOTE), an author, a timestamp, and optional attachments. |
Low |
| Topic | Tag or Custom Field | Gladly Topics are categorical labels. Map to a custom dropdown field for reporting, with tags as fallback. | Low |
| Inbox | Group | Route tickets by mapping Gladly Inboxes to Zendesk Groups. Add ticket forms if one inbox represented a distinct workflow. | Low |
| Agent | Agent (User) | Match by email. Agents must exist in Zendesk before ticket import to preserve historical assignment. | Low |
| Team | Group | Gladly Teams map to Zendesk Groups. Multiple Teams may consolidate into fewer Groups. | Low |
| Task | Ticket (type: task) | Gladly Tasks become Zendesk tickets with type: task. Do not bury tasks inside unrelated comments. |
Low |
| Answers (agent-facing) | Macro | Gladly Answers used as quick replies map to Zendesk Macros. Variables (e.g., {{customer.name}}) must be translated to Zendesk Liquid markup ({{ticket.requester.name}}). |
Medium — variable syntax requires manual review |
| Answers (public-facing) | Help Center Article | Public-facing Answers map to Zendesk Guide articles. Neither mapping is automated — both require manual creation or scripted import via the Help Center API. | Medium |
| Conversation Attachments | Comment Attachments | Not included in standard Gladly exports. Requires custom API extraction per conversation item. | High if not handled |
| Voice Transcript | Internal Comment | Zendesk Support has no standalone transcript object. Append as internal notes — structured format (speaker labels, timestamps) is lost. | Medium |
| Rules | Trigger or Automation | Cannot be migrated programmatically. Must be rebuilt in Zendesk after data load. Budget 2–5 days for a complex rule set (20+ rules). | N/A — manual rebuild |
What has no clean Zendesk equivalent: Gladly's lifelong customer timeline view, native voice AI transcripts (in structured form), Sidekick AI resolution metadata, satisfaction survey responses (must be exported separately and stored outside Zendesk or appended as tags/notes), and routing/queue history cannot be directly replicated in Zendesk. Plan to archive this data separately or append it as internal notes on the customer's Zendesk user profile.
Channel-Specific Mapping Details
Each Gladly channel produces Conversation Items with different metadata. The mapping to Zendesk comments requires channel-aware transformation:
- Email: Maps cleanly to Zendesk email comments. Preserve
from,to,cc, andsubjectfields. Zendesk comments support HTML bodies. - Chat: Maps to Zendesk comments with
via: chat. Chat messages lack email headers — the requester is identified by their Zendesk user record. Preserve chat timestamps at the per-message level. - SMS: Gladly stores the phone number on the Customer, not per-message. Map SMS items to comments and ensure the customer's phone number is set on their Zendesk user profile. Zendesk Talk SMS requires a separate Zendesk Talk license to continue SMS support post-migration.
- Social (Facebook, Instagram, Twitter/X): Gladly stores social handles as contact points on the Customer. Zendesk requires separate channel integrations (Zendesk Social Messaging) and maps social interactions to tickets via channel-specific APIs. Historical social messages import as standard comments — they lose their native social threading and reaction metadata.
- Voice: Gladly stores call recordings and transcripts as Conversation Items. Zendesk Talk stores recordings on its own call objects. Historical Gladly voice data must be appended as internal comments with links to archived recordings. There is no way to populate Zendesk Talk's call history retroactively.
Field-Level Mapping Considerations
- Timestamps: Use Zendesk's Ticket Import API (
/api/v2/imports/tickets) to preservecreated_at,updated_at, andsolved_at. The standard ticket creation endpoint overwrites all dates with the current server time. - Statuses: Gladly Conversations are either Open or Closed. Zendesk offers six statuses (New, Open, Pending, On-hold, Solved, Closed). Map Closed Gladly conversations to Zendesk
solvedorclosedbased on your reporting needs. Usesolvedif you want them to appear in Zendesk Explore solved-ticket reports; useclosedwitharchive_immediately: truefor pure archival. - Custom Attributes: Gladly supports free-form custom attributes. Zendesk requires custom fields to be pre-created with strict types (text, dropdown, checkbox, numeric, regex, date). If a Gladly text field contains dates in varied formats (e.g., "May 12, 2023" vs. "2023-05-12"), it will fail to import into a Zendesk Date custom field unless normalized to ISO 8601 first. Cast all variables to Zendesk's expected formats before payload construction.
- Field limits: Do not explode every Gladly Topic into its own Zendesk custom field. Zendesk recommends staying within about 400 ticket fields per account. If Gladly Topics drive reporting, use one governed disposition dropdown field plus tags for the rest. Flat tags are cheaper than field sprawl.
What Are the API Rate Limits for Gladly and Zendesk?
[For engineering] Both platforms enforce hard limits that will terminate aggressive extraction or loading scripts. Build rate-limit handling into your migration architecture from day one. (developer.gladly.com)
Gladly API Constraints
- Default rate limit: 10 requests per second. Exceeding this returns HTTP 429. Remaining allocation is exposed in response headers. (help.gladly.com)
- Conversations per customer: The API returns at most 100 conversations per customer. The list is not paginated. If a customer has more than 100 conversations, Gladly sets a
Gladly-Limited-Dataresponse header — but there is no standard mechanism to retrieve the rest. - Items per conversation: The API returns at most 1,000 items per conversation, also not paginated. The
Gladly-Limited-Dataheader flags truncation. Items can be filtered bysessionId, which can help work around this ceiling by fetching items for individual sessions within a conversation. - Customer search: Max 50 profiles per request, sorted by most recent
updatedAt. - Export API: Bulk conversation export files are generated every 24 hours, available for 14 days, with a limit of 2,000 conversation items per file. Use the Export API as your primary extraction strategy for high-volume migrations (100K+ conversations) to reduce per-customer API call overhead. Use the REST API for targeted extraction of specific customers or for delta sync passes.
- Reporting API: Limited to 10 requests per minute (separate from the standard API limit). Reporting data runs about one hour behind — do not use reports as your cutover truth source.
When to use the Export API vs. REST API:
| Criterion | Export API | REST API (per-customer) |
|---|---|---|
| Volume | >50K conversations | <50K conversations or targeted extraction |
| Freshness | 24-hour lag | Near real-time |
| Attachments | Not included | Included via item-level endpoints |
| Truncation risk | 2,000 items/file limit | 100 conversations, 1,000 items/conversation |
| Best for | Bulk historical extraction | Delta sync, attachment extraction, targeted re-extraction of truncated customers |
At 10 requests per second, Gladly's theoretical ceiling is 36,000 API calls per hour. That is a hard ceiling, not a planning target. Standard scripts will silently drop historical data when they hit the Gladly-Limited-Data header if you don't explicitly check for it.
Zendesk API Constraints
| Zendesk Plan | Rate Limit (req/min) |
|---|---|
| Team | 200 |
| Growth / Professional | 400 |
| Enterprise | 700 |
| Enterprise Plus (High Volume API) | 2,500 |
- The Ticket Import API (
/api/v2/imports/tickets) supports single-ticket and bulk (/create_many) endpoints. Bulk accepts up to 100 tickets per request. (developer.zendesk.com) archive_immediately: truesends closed tickets directly to the archive — Zendesk recommends this for imports exceeding 750,000 tickets to avoid performance impact on active tickets.- Triggers do not fire on imported tickets. They resume if the ticket is later updated.
- SLAs and Zendesk metrics are not calculated for imported tickets. Tag imported tickets (e.g.,
migrated_from_gladly) and exclude them from SLA reporting. - Users referenced by
requester_idorauthor_idmust exist in Zendesk before ticket import. Always load users and organizations first. - On large loads, the tighter constraint is often the background-job ceiling: Zendesk allows only 30 queued or running jobs at once and exposes remaining capacity in the
zendesk-ratelimit-inflight-jobsheader. (developer.zendesk.com) - When rate limits are exceeded, Zendesk returns
429 Too Many Requestswith aRetry-Afterheader. Your script must read this header and pause execution. Ignoring 429 errors results in temporary IP bans and broken historical relationships.
[For engineering] As of mid-2026, new migration code should use Zendesk OAuth instead of long-lived API tokens. Zendesk starts auto-deactivating inactive API tokens on July 28, 2026, blocks new token creation on October 27, 2026, and permanently deactivates remaining tokens on April 30, 2027. The client credentials flow is the documented server-to-server option for background jobs and data pipelines. (developer.zendesk.com)
For a deeper look at common rate-limit mistakes, see Common Help Desk Data Migration Mistakes and How to Avoid Them.
How to Handle Gladly Attachments and Inline Images
Gladly's standard historical data exports are text-based only. Gladly's own documentation confirms the platform "does not support the import of historical images, recordings, attachments, metrics, or routing/conversation assignments." If you export Gladly data using their standard mechanisms, attachments are lost. (help.gladly.com)
To preserve attachments, your migration architecture must:
- Extract attachment URLs from individual Conversation Items via the Gladly REST API. Each Conversation Item of type
EMAIL,CHAT_MESSAGE, orNOTEmay contain anattachmentsarray withurl,filename,contentType, andsizeproperties. - Download each file to a secure temporary staging location. If your organization is subject to GDPR, HIPAA, or other data residency requirements, ensure the staging location meets compliance standards — attachments may contain PII, PHI, or customer-uploaded documents. Use encryption at rest and delete staged files within 72 hours of successful import.
- Upload to Zendesk using the Attachments API (
POST /api/v2/uploads), which returns a token. - Reference the token in the corresponding ticket comment during import.
This adds significant per-record overhead. For a 50K-conversation migration with an average of 1.5 attachments per conversation, expect ~75,000 additional API calls to Gladly and ~75,000 uploads to Zendesk — roughly 12–20 hours of attachment processing alone at Gladly's 10 req/sec limit.
If you skip this step, historical images and PDFs will render as broken links or disappear entirely in Zendesk.
What Are the Migration Approaches?
No single path handles Gladly history, binaries, workflow rebuild, and cutover on its own. (support.zendesk.com)
| Approach | How It Works | Complexity | Best For | Key Risk |
|---|---|---|---|---|
| CSV Export + Zendesk Import | Export Gladly Conversation CSV, transform, use Zendesk CSV importer | Low | <5K simple conversations with no attachments | Loses threading, attachments, and timestamps |
| Zendesk Data Importer | Imports users, organizations, and custom object records only (support.zendesk.com) | Low | Pre-staging master data | No ticket history support |
| Third-Party Wizard Tool | Guided migration connecting both platforms | Medium | Mid-volume, standard schemas | May dump entire Gladly customer history into one Zendesk ticket. Validate how it handles Gladly's capped, non-paginated endpoints and conversation splitting. |
| Custom API ETL | Extract via Gladly REST API, transform in-memory, load via Zendesk Ticket Import API | High | Full-fidelity migration at any scale | Requires significant engineering effort: rate-limit handling, conversation-splitting logic, error recovery, checkpoint/resume, and validation |
| Managed Migration Service | Dedicated engineers build and run a custom migration pipeline | Low (for you) | Enterprise volumes, complex fields, zero-downtime requirements | Cost — but you trade engineering time for guaranteed fidelity |
[For engineering] If you choose custom API ETL, budget 80–120 hours of developer time for a 50K+ conversation migration, including splitting logic, attachment handling, error recovery, and validation scripts.
[For PMs] If your team doesn't have a developer who has worked with both the Gladly and Zendesk APIs before, the learning curve alone adds 1–2 weeks.
Step-by-Step Migration Process
This migration requires strict order-of-operations to maintain relational integrity. If you load tickets before users or enable triggers before validation, you create broken relationships or fire live business rules on historical data. (developer.zendesk.com)
1. Prepare the Zendesk Target Environment
- Create all custom ticket fields, groups, and tags that map to Gladly objects
- Import agents and match by email address
- Import organizations
- Disable triggers and automations that could fire on imported records
- Pre-create dropdown options — Zendesk warns that omitting an existing option during an update can remove it, stripping values from tickets
- Sandbox first: Run the full migration in a Zendesk Sandbox environment before production. Sandbox limitations: sandbox environments share the same rate limits as your production plan, sandbox data resets on refresh (which deletes all imported data), and some Enterprise features may not be available in sandbox. Plan sandbox testing before any scheduled refresh.
See the full Zendesk Migration Checklist for environment prep.
2. Extract Data from Gladly
Extract all Customers and their Conversations via the Gladly REST API. Respect the 10 req/sec rate limit. Log every Gladly-Limited-Data response header — these flag truncated results for high-volume customers that need a separate extraction path (e.g., sessionId-filtered requests or Gladly support escalation for bulk export).
# Pseudo-code: Extract customers and conversations with truncation detection
import requests, time, logging
GLADLY_DOMAIN = "https://yourorg.gladly.com"
HEADERS = {"Authorization": "Basic <base64_credentials>"}
log = logging.getLogger("gladly_extract")
# Track truncated customers for post-extraction review
truncated_customers = []
def get_conversations(customer_id):
"""Returns at most 100 conversations — check Gladly-Limited-Data header."""
resp = requests.get(
f"{GLADLY_DOMAIN}/api/v1/customer-history/{customer_id}/conversations",
headers=HEADERS
)
if resp.status_code == 301:
# Merged customer — follow redirect to canonical ID
redirect_id = resp.headers.get("Location", "").split("/")[-2]
log.info(f"Customer {customer_id} merged into {redirect_id}")
return get_conversations(redirect_id)
if resp.headers.get("Gladly-Limited-Data"):
log.warning(f"Truncated data for customer {customer_id} — >100 conversations")
truncated_customers.append({"id": customer_id, "type": "conversations"})
return resp.json()
def get_items(customer_id, conversation_id):
"""Returns at most 1000 items — check Gladly-Limited-Data header."""
resp = requests.get(
f"{GLADLY_DOMAIN}/api/v1/customer-history/{customer_id}/conversations/{conversation_id}/items",
headers=HEADERS
)
time.sleep(0.1) # Respect 10 req/sec limit
if resp.headers.get("Gladly-Limited-Data"):
log.warning(f"Truncated items for conversation {conversation_id} — >1000 items")
truncated_customers.append({
"id": customer_id,
"conversation_id": conversation_id,
"type": "items"
})
return resp.json()Download all attachments locally to prevent URL expiration before you reach the load phase.
3. Transform: Split Conversations into Tickets
This is the hardest step. A single Gladly Conversation may span weeks and cover multiple topics. Define your splitting strategy:
- By Topic: Each distinct Topic in a Conversation becomes a separate Zendesk ticket. Best when Gladly Topics are well-governed and consistently applied.
- By Time Gap: If there's a gap exceeding a defined threshold between items, start a new ticket. Choose a threshold that matches your support patterns — common values range from 72 hours to 14 days. A 7-day gap works well for most consumer brands.
- By Session: Use Gladly's
sessionIdon conversation items to group messages into logical tickets. This is the most structurally faithful approach since sessions represent natural interaction boundaries in Gladly. - Hybrid: Split by session first, then sub-split by topic if a single session spans multiple topics. This produces the most granular ticket set but increases total ticket count significantly.
Whichever strategy you choose, preserve chronological order within each resulting ticket. Re-map Topics to Zendesk custom fields or tags during this phase.
4. Extract and Upload Attachments
Run attachment extraction as a separate pass. Download each binary from Gladly conversation items via the API, upload it to Zendesk's Attachments API (POST /api/v2/uploads) to get upload tokens, and reference those tokens in the corresponding ticket comments during import.
Do not combine this with the comment load — missing attachments can silently vanish inside comment payloads if you don't handle them independently.
5. Load Tickets via the Ticket Import API
Use Zendesk's Ticket Import API, not the standard ticket creation endpoint. The standard endpoint overwrites all historical timestamps with the current server time, destroying your chronological history.
{
"ticket": {
"requester_id": 123456789,
"assignee_id": 987654321,
"created_at": "2023-05-12T10:00:00Z",
"updated_at": "2023-05-12T14:30:00Z",
"status": "solved",
"tags": ["migrated_from_gladly", "gladly_topic_billing"],
"external_id": "gladly_conv_abc123",
"custom_fields": [
{"id": 12345, "value": "gladly_customer_xyz789"}
],
"comments": [
{
"author_id": 123456789,
"created_at": "2023-05-12T10:00:00Z",
"value": "Historical Gladly message content here.",
"public": true
},
{
"author_id": 987654321,
"created_at": "2023-05-12T10:15:00Z",
"value": "Agent response with attachment.",
"public": true,
"uploads": ["token_from_attachments_api"]
}
]
}
}For bulk imports, use /api/v2/imports/tickets/create_many with batches of up to 100 tickets. Set archive_immediately: true for closed historical tickets on large imports.
Implement checkpoint/resume logic so that a crash at ticket 45,000 doesn't require restarting from ticket 1. Track imported Gladly conversation IDs in a local database or file, and skip already-imported records on restart.
# Pseudo-code: Job-aware batch import with retry, checkpoint, and partial failure handling
import json, time, requests
CHECKPOINT_FILE = "migration_checkpoint.json"
def load_checkpoint():
try:
with open(CHECKPOINT_FILE) as f:
return set(json.load(f).get("imported_ids", []))
except FileNotFoundError:
return set()
def save_checkpoint(imported_ids):
with open(CHECKPOINT_FILE, "w") as f:
json.dump({"imported_ids": list(imported_ids)}, f)
def poll_job_status(job_url, auth):
"""Poll until job completes. Log per-ticket errors from results."""
while True:
resp = requests.get(job_url, auth=auth)
status = resp.json()["job_status"]
if status["status"] == "completed":
# Check for partial failures
for result in status.get("results", []):
if result.get("error"):
log.error(f"Ticket import failed: {result['error']} — external_id: {result.get('external_id')}")
return status
elif status["status"] == "failed":
raise Exception(f"Job failed: {status}")
time.sleep(5)
def wait_for_available_job_slot(auth, max_inflight=30):
"""Check inflight job count before submitting new batch."""
while True:
resp = requests.get("https://yourinstance.zendesk.com/api/v2/job_statuses", auth=auth)
inflight = int(resp.headers.get("zendesk-ratelimit-inflight-jobs", 0))
if inflight < max_inflight:
return
time.sleep(10)
def import_batch(tickets_batch, auth):
resp = requests.post(
"https://yourinstance.zendesk.com/api/v2/imports/tickets/create_many",
json={"tickets": tickets_batch},
auth=auth
)
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 60))
log.warning(f"Rate limited. Retrying after {retry_after}s")
time.sleep(retry_after)
return import_batch(tickets_batch, auth)
if resp.status_code == 422:
# Validation error — log and skip batch, or retry individual tickets
log.error(f"Validation error: {resp.json()}")
return None
return resp.json() # Returns job_status with URL for polling
auth = ("email/token", "api_key")
imported_ids = load_checkpoint()
batch = []
for ticket in transformed_tickets:
if ticket["external_id"] in imported_ids:
continue # Skip already-imported tickets
batch.append(ticket)
if len(batch) == 100:
wait_for_available_job_slot(auth)
result = import_batch(batch, auth)
if result:
poll_job_status(result["job_status"]["url"], auth)
imported_ids.update(t["external_id"] for t in batch)
save_checkpoint(imported_ids)
batch = []
# Import remaining partial batch
if batch:
wait_for_available_job_slot(auth)
result = import_batch(batch, auth)
if result:
poll_job_status(result["job_status"]["url"], auth)
imported_ids.update(t["external_id"] for t in batch)
save_checkpoint(imported_ids)6. Validate
- Record-count reconciliation: Total Gladly conversations vs. total Zendesk tickets created (accounting for splits). If you split by session, total Zendesk tickets will exceed total Gladly conversations — document the expected multiplier.
- Field-level sampling: Spot-check 2–5% of records across high-volume customers. Confirm comments are in order, custom fields populated, and attachments present.
- Timestamp verification: Confirm
created_aton Zendesk tickets matches Gladly conversation start times. - Edge-case audit: Check customers who hit the 100-conversation or 1,000-item Gladly API cap.
- Search checks: Find migrated customers by email and original external ID.
- Attachment presence check: For sampled tickets, verify that all attachment links resolve and files open correctly in Zendesk.
If you only validate record counts, you can still miss the important loss: a 1,001st conversation item or a missing recording. Validate by history depth and binary presence, not only by totals. (developer.gladly.com)
Testing environment sizing: For migrations under 50K conversations, run a full test migration in sandbox. For larger migrations, run a representative sample: extract the top 100 customers by conversation count (to stress-test truncation handling), 500 randomly sampled customers, and all customers with known edge cases (merged profiles, multi-channel histories, high attachment counts). This typically covers 3–5% of total volume while capturing 80%+ of potential failure modes.
Have three senior agents review 50 randomly selected historical tickets in the Zendesk Sandbox. They must verify that original creation dates are accurate, attachments open correctly, comment authorship matches the historical record, and public/private status is correct.
For a comprehensive post-migration QA process, see Post-Migration QA: 20 Tests to Run After Your Help Desk Data Migration.
7. Rollback Plan
Before starting the production migration, document your rollback procedure:
- Partial import cleanup: If migration fails mid-load, use Zendesk's bulk delete API (
DELETE /api/v2/tickets/destroy_many?ids=1,2,3) to remove imported tickets. The API accepts up to 100 ticket IDs per request. Tag all migrated tickets withmigrated_from_gladlyso you can identify and delete them in bulk via the Search API. - User cleanup: Imported end-users can be deleted if they have no non-migrated tickets. Agents cannot be deleted if they are assigned to tickets — reassign or delete their tickets first.
- Full rollback: If the import must be completely reversed, delete all tickets tagged
migrated_from_gladly, then remove imported organizations and users. This is operationally expensive on large imports — another reason to validate thoroughly in sandbox first. - Gladly continuity: Keep Gladly active and receiving traffic until Zendesk is fully validated. Do not cancel your Gladly contract until go-live is confirmed and agents have operated in Zendesk for at least one full business week.
8. Delta Sync and Go-Live
Run a final delta sync to capture any Gladly conversations created during the primary load phase. Use the Gladly REST API filtered by updatedAt timestamp to extract only conversations modified since the primary extraction started.
Redirect email (update MX records or forwarding rules), chat (swap widget code), and other channels from Gladly to Zendesk. Confirm agents can see historical context on returning customers by searching for known returning customers and verifying ticket history appears on their user profile.
For strategies on maintaining operations during this phase, read our guide on Zero-Downtime Help Desk Data Migration.
How Long Does a Gladly to Zendesk Migration Take?
[For PMs] Most mid-market Gladly to Zendesk projects land in a 2–4 week window. Volume matters, but attachment count, workflow rebuild, and UAT speed matter more.
| Phase | Duration | Dependencies |
|---|---|---|
| Discovery & field mapping | 2–3 days | Access to both Gladly admin and Zendesk sandbox |
| Zendesk environment setup | 1–2 days | Custom fields, groups, agents created |
| Script development & testing | 3–5 days | Developer familiar with both APIs |
| Sample migration & UAT | 2–3 days | Stakeholder review and sign-off |
| Full migration run | 1–3 days | Depends on volume (see throughput math below) |
| Delta sync & go-live | 1 day | Final cutover window |
| Total | 10–17 business days |
Throughput math: At Gladly's 10 req/sec limit, extracting a customer with 5 conversations and 20 items per conversation requires ~26 API calls (~2.6 seconds). For 50,000 customers, extraction alone takes ~36 hours. Zendesk import at 400 req/min (Professional plan) with 100-ticket batches processes ~40,000 tickets/hour. Attachment processing adds 12–20 hours for 75K attachments. Total data movement time for a 50K-customer migration with attachments: approximately 50–60 hours of processing time, typically spread across 2–3 calendar days with monitoring.
Plan for a phased approach on large datasets: migrate historical (closed) conversations first using archive_immediately: true, then run a delta sync to capture conversations created during migration.
Risk Register
| Risk | Likelihood | Mitigation |
|---|---|---|
| Gladly API truncates data for high-volume customers | Medium | Log Gladly-Limited-Data headers; escalate to Gladly support for bulk export; use sessionId filtering to work around item caps |
| Zendesk 429 errors or job saturation stall import | High | Implement exponential backoff with Retry-After header; monitor inflight job count; spread load across off-peak hours |
| Conversation splitting produces illogical tickets | Medium | Define splitting rules upfront; validate with CS team during UAT; adjust threshold if >10% of sampled tickets feel wrong to agents |
| Attachments not migrated | High (if using CSV) | Use API extraction; budget extra processing time; verify attachment presence in validation |
| Duplicate users in Zendesk | Medium | De-duplicate by email before import; handle Gladly merged-customer 301 errors by following redirects |
| Partial import failure requiring rollback | Low | Tag all migrated records; document bulk delete procedure; keep Gladly active until go-live confirmed |
| Staging storage exposes PII/PHI | Medium (if attachments are staged) | Encrypt at rest; use compliant storage region; delete staged files within 72 hours of successful import |
What Do Customers and Agents Notice During Migration?
[For customer success] With a phased migration, customers notice nothing. Historical tickets appear in Zendesk before cutover. New tickets created during the migration window are captured by a delta sync. The only visible change is the support interface — customers receive responses from Zendesk instead of Gladly after go-live.
History preservation matters. When a returning customer contacts support post-migration, the agent must see prior interactions. Imported tickets tagged with migrated_from_gladly give agents full context. Without historical data, agents lose the relationship continuity that Gladly's person-centric model was built for — and they start asking customers to repeat information.
Agents will notice a structural shift. Gladly's single-timeline view is now split across discrete Zendesk tickets. Train agents on using Zendesk's user profile view ("Requested tickets" tab) to approximate Gladly's lifelong timeline. Communicate this change 2 weeks before go-live so agents can adjust to groups, forms, macros, and views before the routing switch. Consider creating a Zendesk view filtered to migrated_from_gladly so agents can easily browse historical context for any customer.
What Data Cannot Be Migrated from Gladly to Zendesk?
Some Gladly objects and features have no clean Zendesk equivalent. These require archival, manual rebuild, or redesign — not field mapping.
| Gladly Feature | Why It Can't Migrate | Recommended Action |
|---|---|---|
| Sidekick AI metadata (resolution outcomes, AI scores) | No Zendesk equivalent object | Export and archive in data warehouse |
| Voice AI transcripts (structured format) | Zendesk has no standalone transcript object | Append as internal notes; link to archived recordings |
| Routing assignments and queue history | Zendesk does not store pre-import routing data | Export for historical analysis; do not attempt to import |
| Liveboards and real-time metrics | Platform-specific visualization | Rebuild dashboards in Zendesk Explore |
| SLA calculations | Zendesk explicitly does not calculate SLAs on imported tickets | Tag imported tickets and exclude from SLA reporting |
| Satisfaction survey responses | Zendesk CSAT is ticket-specific; no bulk import of historical scores | Export separately; store in data warehouse or append as tags |
| Rules | Gladly rules ≠ Zendesk triggers/automations (different logic model) | Manual rebuild; budget 2–5 days for 20+ rules |
| Answer types (Reference, Email, Messaging) | No clean 1:1 mapping; split across macros, articles, and playbooks | Audit each Answer and assign to the appropriate Zendesk mechanism |
Gladly explicitly notes that text-based historical import paths do not preserve historical images, recordings, attachments, metrics, or routing assignments. (help.gladly.com)
Build In-House or Use a Managed Service?
Build in-house when:
- You have fewer than 10,000 conversations
- Your Gladly instance uses minimal custom attributes (fewer than 10)
- You have a developer with prior experience in both APIs
- Attachments are not critical to preserve
- One inbox maps cleanly into one Zendesk operating model
- Test extracts show no
Gladly-Limited-Dataheaders for any customer
Use a managed service when:
- You have 50,000+ conversations or high-volume customers hitting Gladly's API caps
- You need attachment and inline image fidelity
- You cannot afford downtime or a failed migration requiring re-migration
- Your team's engineering hours are better spent on product work
- Test extracts show
Gladly-Limited-Dataheaders for important customers - You have compliance requirements (GDPR, HIPAA) that constrain how data can be staged and transferred
The hidden cost of DIY is not the initial build — it's the 3–4 weeks of debugging edge cases: merged Gladly customers returning 301 errors, conversations hitting the 1,000-item cap silently, Zendesk rejecting comments with empty bodies, and the operational drag of a migration that runs over schedule. Those are documented platform constraints, not bad luck. (developer.gladly.com)
ClonePartner has completed 1,500+ data migrations including hundreds of helpdesk migrations involving complex conversation threading and custom field transformations. We handle Gladly's API truncation limits, Zendesk's 429 retry logic and job saturation, and attachment extraction as standard operating procedure — without pulling your engineers off their roadmap.
Frequently Asked Questions
- How long does a Gladly to Zendesk migration take?
- A typical Gladly to Zendesk migration takes 10–17 business days end to end. The largest variable is data volume — extracting 50,000 customers at Gladly's 10 req/sec API limit takes roughly 36 hours for extraction alone. Zendesk's Ticket Import API can load approximately 40,000 tickets per hour on a Professional plan.
- Can Gladly conversation history be preserved in Zendesk?
- Yes, but you must use Zendesk's Ticket Import API (/api/v2/imports/tickets) to preserve original timestamps. The standard ticket creation endpoint overwrites created_at with the current server time. Each Gladly Conversation is split into one or more Zendesk tickets with comments in chronological order.
- What data cannot be migrated from Gladly to Zendesk?
- Gladly Sidekick AI metadata, voice AI transcripts in structured form, routing queue history, Liveboard metrics, and satisfaction survey responses have no direct Zendesk equivalent. SLAs are not calculated on imported tickets. Rules and automations must be manually rebuilt in Zendesk.
- Will attachments migrate from Gladly to Zendesk?
- Not through standard exports — Gladly's CSV and bulk exports are text-only. To preserve attachments, you must extract them via Gladly's REST API per conversation item, upload each file to Zendesk's Attachments API, and link the upload token to the corresponding comment during import.
- Does the Gladly API have pagination for conversations?
- No. Gladly's conversation listing endpoint returns at most 100 conversations per customer and is not paginated. If a customer exceeds this limit, the API sets a Gladly-Limited-Data response header but provides no standard mechanism to retrieve additional records. Contact Gladly support for bulk extraction in these cases.
