---
title: "Zendesk to Jira Service Management Migration: Technical Guide"
slug: zendesk-to-jira-service-management-migration-technical-guide
date: 2026-11-09
author: Rishabh Makhar
categories: [Zendesk, Jira Service Management, Migration Guide]
excerpt: "Migrate Zendesk to Jira Service Management without exposing internal notes. Covers data model mapping, ADF conversion, API rate limits, and step-by-step process."
tldr: "Zendesk to JSM is a data-model translation problem. The biggest risk is exposing internal notes as public comments — always use the JSM Service Desk comment API with \"public\": false, not the standard Jira API."
canonical: https://clonepartner.com/blog/zendesk-to-jira-service-management-migration-technical-guide
---

# Zendesk to Jira Service Management Migration: Technical Guide


# Zendesk to Jira Service Management Migration: Technical Guide

> [!NOTE]
> **Quick Answer:** A Zendesk to Jira Service Management (JSM) migration is a data-model translation — Zendesk organizes data around customer conversations, while JSM organizes it around Jira issues with workflows and request types. No native migration path exists. The single biggest risk is **exposing internal notes as public comments** if your migration script uses the standard Jira comment API instead of the JSM Service Desk API with `"public": false`. SLA policies, triggers, macros, and Zendesk Guide articles cannot be migrated programmatically and must be rebuilt. The data migration itself typically completes within **1–5 business days**, depending on volume, complexity, and API rate limits.

Migrating from Zendesk to Jira Service Management means translating a conversation-centric support model into an issue-centric ITSM platform. The two systems organize data differently at every level — objects, statuses, comments, field types, and user relationships.

Zendesk's CSV export leaves out ticket comments and descriptions, along with multi-line text, multi-select, and custom date fields ([support.zendesk.com](https://support.zendesk.com/hc/en-us/articles/4408886165402)). That makes it inadequate for anything beyond a basic proof-of-concept. If you have more than a few hundred tickets or need to preserve internal note visibility, you must use an API-based approach. This guide covers the technical constraints, API differences, field type compatibility, and data mapping requirements for executing a Zendesk to JSM migration.

## What Is a Zendesk to JSM Migration?

A Zendesk to JSM migration is the process of extracting tickets, comments (public and internal), users, organizations, attachments, custom fields, and tags from Zendesk Support and loading them into Atlassian's JSM — while preserving conversation history, comment visibility, author attribution, and data relationships.

This is non-trivial because the platforms model support data in fundamentally different ways:

- **Tickets vs. Issues:** In Zendesk, a ticket is the core object in a conversation thread. In JSM, the core object is a Jira Issue, surfaced to customers via a "Request Type" in the portal.
- **Requesters vs. Reporters:** Zendesk users are either agents or end-users. JSM separates users into Atlassian Accounts (licensed agents) and Portal-Only Customers (free end-users).
- **Rich Text vs. ADF:** Zendesk formats descriptions and comments in HTML. Jira Cloud requires Atlassian Document Format (ADF), a strict JSON-based block structure.
- **Data model orientation:** Zendesk's model centers on omnichannel customer conversations — tickets are children of end-users, organizations, and communication channels. JSM's model centers on Jira issues — request types, workflows, queues, and a schema-based CMDB that links incidents to infrastructure.

A migration is not a file transfer. It is a data-model translation problem.

## Why Teams Move from Zendesk to JSM

- **Atlassian consolidation.** Teams already using Jira Software and Confluence want a single ecosystem for engineering, IT, and support — shared queues, linked issues, and one user directory.
- **ITSM maturity.** JSM is PinkVERIFY ITIL 4 certified and provides native change management, incident management, problem management, and asset/CMDB capabilities that Zendesk lacks out of the box.
- **Developer-support alignment.** JSM issues *are* Jira issues. Support agents and engineers work in the same backlog, eliminating the Zendesk-to-Jira sync that many teams maintain.
- **Cost structure.** For organizations that already pay for Jira Software, adding JSM agents can be cheaper than maintaining a separate Zendesk contract.

## How Does the Zendesk Data Model Map to JSM?

Every row in this table represents a design decision, not a 1:1 copy.

| Zendesk Object | JSM Equivalent | Migration Notes |
|---|---|---|
| Ticket | Issue (Service Request, Incident, etc.) | Ticket form → request type mapping required |
| Ticket comment (public) | Request comment (`"public": true`) | Must use the JSM Service Desk comment API |
| Ticket comment (internal/private) | Request comment (`"public": false`) | **Wrong API = exposed internal notes** |
| End-user | Customer (Portal-Only) | Created via JSM customer API; do not create as Atlassian Accounts |
| Agent | Agent (licensed JSM user) | Agents must exist before ticket import |
| Organization | Organization (JSM) | JSM organizations exist site-wide but must be added to each service project |
| Group | Team or Queue | No direct mapping; rebuild queue routing |
| Ticket form | Request type | Forms map loosely; field sets differ |
| Custom field | Custom field | Type compatibility varies; reference by ID (`customfield_XXXXX`) |
| Tag | Label | Jira labels are unstructured; multi-value tags flatten |
| Ticket status | Workflow status | Zendesk has 6 fixed status values; JSM uses workflow transitions |
| Satisfaction rating | No native equivalent | Store as a custom field or discard |
| SLA policy | JSM SLA | Cannot migrate; must rebuild |
| Trigger / Automation | Automation rule | Cannot migrate; must rebuild |
| Zendesk Guide article | Confluence page | Separate migration; different content model |
| Attachment | Attachment | Multi-step upload required in JSM |

## Custom Field Type Compatibility Matrix

This is where most migrations encounter silent data loss. The Zendesk-to-JSM field type mapping is not lossless. The table below documents which field types translate cleanly, which require transformation, and which are fundamentally incompatible.

| Zendesk Field Type | JSM Field Type | Mapping Quality | Notes |
|---|---|---|---|
| Text (single-line) | Text Field (single line) | ✅ Clean | Direct string copy |
| Textarea (multi-line) | Text Field (multi-line) | ✅ Clean | Direct string copy |
| Integer | Number Field | ✅ Clean | Direct numeric copy |
| Decimal | Number Field | ✅ Clean | JSM Number Field accepts decimals |
| Checkbox | Checkbox | ✅ Clean | Boolean maps directly |
| Date | Date Picker | ✅ Clean | Normalize to ISO 8601 format |
| Dropdown (single-select) | Select List (single choice) | ⚠️ Requires mapping | Option values must be pre-created in JSM; option IDs differ |
| Multi-select | Select List (multiple choices) | ⚠️ Requires mapping | Each option must exist in JSM before import; order not preserved |
| Lookup (relationship field) | No native equivalent | ❌ Lossy | Store as text or use Insight/Assets objects; structural relationship lost |
| Regex (validated text) | Text Field (single line) | ⚠️ Lossy | Validation pattern is dropped; value migrates as plain text |
| Credit card (redacted) | Text Field | ❌ Redacted data only | Zendesk stores only last 4 digits after redaction; migrate as-is |
| System field (ticket ID) | Custom Text Field | ⚠️ Manual | Store original Zendesk ticket ID in a dedicated custom field for cross-reference |

**Key implications:**

- Pre-create all dropdown and multi-select option values in JSM before running the migration. API calls that reference option values not in the JSM field's allowed list will return 400 errors.
- Lookup/relationship fields that reference other Zendesk objects (e.g., linked tickets, related users) lose their referential integrity. If this data matters, consider migrating it to Jira issue links or JSM Assets objects.
- Regex-validated fields in Zendesk enforce input format at collection time. That constraint does not transfer; the migrated value is a plain string with no validation.

## The Comment Visibility Problem: Internal Notes vs. Public Replies

This is the highest-risk item in any Zendesk-to-JSM migration. Zendesk tickets contain a mix of public replies (visible to the customer) and internal notes (visible only to agents). If your migration script creates comments using the standard Jira comment API (`/rest/api/3/issue/{issueIdOrKey}/comment`), every comment appears as a **public** reply in the JSM portal — including internal notes that may contain sensitive escalation details, customer complaints, or PII.

The fix: use the JSM Service Desk comment API and explicitly map the Zendesk `public` boolean to the JSM `public` boolean.

```bash
POST /rest/servicedeskapi/request/{issueIdOrKey}/comment
Content-Type: application/json

{
  "body": "<PLAIN_TEXT_COMMENT_BODY>",
  "public": false
}
```

The `body` field on this endpoint is a string, and `public` sets whether the comment is public (`true`) or internal (`false`) ([developer.atlassian.com](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/)). Setting `"public": false` ensures the comment is an Internal Note. If you omit this field, or if you use the standard Jira Platform API, the comment may default to public — triggering email notifications to the customer containing your internal agent discussions.

The standard Jira API has no native `public` field. There is an undocumented `sd.public.comment` property that can be passed as a Jira issue property, but it is not part of the official API specification and its behavior is not guaranteed across Atlassian Cloud updates. Atlassian's own reference says comments created through the Jira platform API default to visible in Jira Service Management, and it points to the JSM Create request comment operation for internal comments ([developer.atlassian.com](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-comments/)).

> [!CAUTION]
> **Do not use the standard Jira comment API for JSM migrations.** The `/rest/api/3/issue/{key}/comment` endpoint has no documented field for internal vs. public comments in JSM. Always use `/rest/servicedeskapi/request/{key}/comment` with `"public": false` for internal notes.

## API Endpoint Selection: Which API to Use and When

The choice between the Jira Platform API (`/rest/api/3/`) and the JSM Service Desk API (`/rest/servicedeskapi/`) is not stylistic — it determines whether JSM-specific behavior fires correctly.

| Operation | Correct Endpoint | Why |
|---|---|---|
| Create issue (ticket import) | `/rest/servicedeskapi/request` | Sets the request type from `requestTypeId`, so the request gets JSM features and portal visibility |
| Create comment (public) | `/rest/servicedeskapi/request/{key}/comment` with `"public": true` | Portal visibility correctly set |
| Create comment (internal) | `/rest/servicedeskapi/request/{key}/comment` with `"public": false` | Only safe way to create internal notes |
| Upload temporary attachment | `/rest/servicedeskapi/servicedesk/{id}/attachTemporaryFile` | JSM-specific temporary file store |
| Attach file to issue | `/rest/servicedeskapi/request/{key}/attachment` | Associates temp file; sets portal visibility |
| Create customer (end-user) | `/rest/servicedeskapi/customer` | Creates Portal-Only Customer; does not consume license |
| Transition issue status | `/rest/api/3/issue/{key}/transitions` | JSM uses standard Jira transition mechanism |
| Retrieve transition IDs | `GET /rest/api/3/issue/{key}/transitions` | Required before status transitions (see below) |
| Create issue link | `/rest/api/3/issueLink` | No JSM-specific equivalent |

Using `/rest/api/3/issue` to create tickets during a migration is a common mistake. The issue is created, but without a request type it won't have access to all Jira Service Management features ([support.atlassian.com](https://support.atlassian.com/jira-service-management-cloud/docs/whats-the-difference-between-request-types-and-issue-types/)). It also does not appear in the customer portal unless you set the `Customer Request Type` field, whose custom field ID varies by site.

## How to Handle ADF (Atlassian Document Format) Conversion

**Atlassian Document Format (ADF)** is a JSON-based rich text format used by Jira Cloud for rich text, including issue comments and textarea custom fields ([developer.atlassian.com](https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/)). Zendesk stores comment bodies as HTML. If you use the Jira platform API (v3) to create issues, you must convert that HTML to valid ADF — plain HTML strings are rejected with validation errors.

A simple Zendesk HTML comment like `<p>Hello <b>World</b></p>` becomes this in ADF:

```json
{
  "version": 1,
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "Hello "
        },
        {
          "type": "text",
          "text": "World",
          "marks": [
            {
              "type": "strong"
            }
          ]
        }
      ]
    }
  ]
}
```

If your parser fails to handle complex HTML (nested tables, blockquotes, inline images), the Jira API returns a 400 Bad Request error and that comment fails to migrate.

You have two practical options:

1. **Use the JSM Service Desk API with plain text.** The `/rest/servicedeskapi/request/{key}/comment` endpoint accepts a plain-text `body` string and handles rendering internally. You lose rich formatting (bold, lists, inline images) but gain simpler implementation and portal visibility control. For most migrations, this is the safer choice.

2. **Convert HTML to ADF.** If preserving formatting matters, use a conversion library. Atlassian provides `@atlaskit/editor-markdown-transformer` and `@atlaskit/editor-json-transformer` for JavaScript. For Python, community libraries like `html-to-adf` exist but require validation against JSM's ADF schema.

We cover this in depth in our [ADF conversion and API guide](https://clonepartner.com/blog/blog/help-desk-to-jira-service-management-adf-conversion-api-guide).

## User and Organization Provisioning

Before migrating a single ticket, you must migrate the people. If you migrate a ticket and the assignee or requester does not exist in Jira, the API will reject the payload or attribute the ticket to the API service account.

**Zendesk Agents → JSM Agents:** Agents must be provisioned as Atlassian accounts and granted product access to JSM. You must map each Zendesk agent's email address to the Atlassian Account ID (`accountId`), as Jira APIs no longer accept email addresses or usernames for user assignment due to GDPR compliance. Retrieve `accountId` values using `GET /rest/api/3/user/search?query={email}`.

**Zendesk End-Users → JSM Customers:** Zendesk end-users should be created as **Portal-Only Customers** in JSM using the `/rest/servicedeskapi/customer` endpoint, which takes an email address and display name ([developer.atlassian.com](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-customer/)). If you accidentally create them as full Atlassian Accounts, you will consume paid JSM licenses for every customer in your database.

**Organizations:** JSM organizations exist across the whole site, but each one must be added to every service project that uses it. Create organizations with `POST /rest/servicedeskapi/organization`, attach them with `POST /rest/servicedeskapi/servicedesk/{serviceDeskId}/organization`, and add customers with `POST /rest/servicedeskapi/organization/{organizationId}/user` ([developer.atlassian.com](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-organization/)). Plan your org structure before migrating.

## How to Map Zendesk Ticket Statuses to JSM Workflow States

Zendesk tickets carry a **status** (one of six fixed values: new, open, pending, hold, solved, closed) and an optional **custom_status_id**. JSM uses Jira workflow transitions — statuses are nodes in a state machine, and transitions define the allowed moves between them.

There is no universal mapping. You need to define one per request type based on your JSM workflow configuration. A common starting point:

| Zendesk Status | Suggested JSM Status | Status Category |
|---|---|---|
| New | Waiting for support | To Do |
| Open | In Progress | In Progress |
| Pending | Waiting for customer | In Progress |
| Hold | On hold (custom) | In Progress |
| Solved | Resolved | Done |
| Closed | Closed / Done | Done |

If you use Zendesk custom statuses, extract them via the `GET /api/v2/custom_statuses` endpoint ([developer.zendesk.com](https://developer.zendesk.com/api-reference/ticketing/tickets/custom_ticket_statuses/)) and map each one to the appropriate JSM workflow status before starting the migration.

> [!WARNING]
> **JSM does not let you set an arbitrary status on issue creation via API.** You create the issue in its initial status, then transition it through the workflow using `POST /rest/api/3/issue/{key}/transitions`. Before your migration runs, retrieve valid transition IDs for your target workflow using `GET /rest/api/3/issue/{key}/transitions` on a sample issue, then build a transition map keyed by target status name. Transition IDs are workflow-specific — they differ between JSM projects and cannot be hardcoded.

**Practical transition ID retrieval:**

```bash
GET /rest/api/3/issue/{sampleIssueKey}/transitions
```

Returns:
```json
{
  "transitions": [
    { "id": "11", "name": "Start Progress", "to": { "name": "In Progress" } },
    { "id": "21", "name": "Resolve", "to": { "name": "Resolved" } },
    { "id": "31", "name": "Close", "to": { "name": "Closed" } }
  ]
}
```

Build a `{ "target_status_name": "transition_id" }` lookup table from this response before the migration loop begins. Apply the correct transition ID for each ticket's migrated status.

## API Rate Limits

### Zendesk Extraction

Do not use Zendesk's standard `/api/v2/tickets.json` endpoint for a full migration. It paginates inefficiently for large datasets.

Use the **Zendesk Incremental Export API**, preferably the cursor-based version (`/api/v2/incremental/tickets/cursor.json`), which Zendesk encourages over the time-based `/api/v2/incremental/tickets.json` ([developer.zendesk.com](https://developer.zendesk.com/api-reference/ticketing/ticket-management/incremental_exports/)). This endpoint is designed for data replication and migrations. It requires a Unix epoch `start_time` and returns up to 1,000 records per page in chronological order. Rate limit: **10 requests per minute** (30 with the High Volume API add-on) ([developer.zendesk.com](https://developer.zendesk.com/api-reference/introduction/rate-limits/)).

The incremental API does not include ticket comments in the same payload. You must make secondary calls to `/api/v2/tickets/{ticket_id}/comments.json` to extract conversation threads. General API endpoints for comments, attachments, and users are limited by plan: 200 requests/minute on Suite Team, 400 on Growth and Professional, 700 on Enterprise, and 2,500 on Enterprise Plus or with the High Volume API add-on ([developer.zendesk.com](https://developer.zendesk.com/api-reference/introduction/rate-limits/)).

Comment extraction needs at least one call per ticket. At 400 requests/minute, 100,000 tickets need about 250 minutes of comment calls alone, before attachment downloads and retries.

If a third-party tool runs the extraction rather than your own script, check its access first. Zendesk is ending third-party access to the Incremental Export APIs between December 2, 2026 and January 19, 2027 ([support.zendesk.com](https://support.zendesk.com/hc/en-us/articles/11249701485338)). Our [guide to that change](https://clonepartner.com/blog/blog/zendesk-ending-incremental-apis-for-third-parties-migration-guide) covers the alternatives.

Always use cursor-based pagination and respect the `Retry-After` header.

### JSM Loading

Atlassian applies points-based hourly quotas to Forge, Connect, and OAuth 2.0 apps on Jira Cloud. A migration script that authenticates with an API token is not covered by the points model. It is governed by burst rate limits, enforced per tenant and per endpoint with a token-bucket algorithm ([developer.atlassian.com](https://developer.atlassian.com/cloud/jira/platform/rate-limiting/)).

You cannot hardcode a concurrency limit. Build exponential backoff into your script and monitor the `X-RateLimit-Remaining` header, plus `Retry-After` on 429 responses. 429 Too Many Requests responses are expected during bulk migrations — handle them gracefully.

Beyond rate limits, you must use the correct API endpoint. The Jira Platform API (`/rest/api/3/issue`) will technically create an issue, but without a request type the issue misses JSM features and will not be visible in the customer portal unless you manually set the `Customer Request Type` custom field. Always use the **JSM REST API** (`/rest/servicedeskapi/request`) for migration operations.

## Migration Script Idempotency and Error Recovery

A migration script that is not idempotent will create duplicate records when re-run after a failure. Migrations of any significant size will fail partway through — a 429 at ticket 47,832 out of 50,000 is not an edge case, it is an expected event. Design for it from the start.

**Core idempotency pattern:**

1. **Store the Zendesk ticket ID in a dedicated JSM custom field** (e.g., `customfield_10100`, labeled "Zendesk Ticket ID") on every issue you create.
2. **Before creating an issue**, query JSM for existing issues with that Zendesk ticket ID: `GET /rest/api/3/search/jql?jql=project=MYPROJECT AND "Zendesk Ticket ID"="{zendesk_id}"`. If a result exists, skip creation and log the existing JSM key. Atlassian is removing the older `/rest/api/3/search` endpoint, and search results can lag recent writes ([developer.atlassian.com](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-search/)), so treat this check as a backstop to the local database below.
3. **Maintain a local progress database** (SQLite is sufficient) with one row per Zendesk ticket ID, recording: `zendesk_id`, `jsm_key`, `comments_migrated` (bool), `attachments_migrated` (bool), `status_applied` (bool). Re-runs skip completed rows and resume from the first incomplete row.
4. **Handle comments separately.** A ticket may be created but its comments may not all be migrated if a failure occurred mid-thread. Track comment migration state per ticket, not just ticket creation.

**Exponential backoff on 429:**

```python
import time

def api_call_with_retry(func, max_retries=5):
    for attempt in range(max_retries):
        response = func()
        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
            time.sleep(retry_after)
            continue
        return response
    raise Exception("Max retries exceeded")
```

**Use JSM sandbox for pre-production validation.** Organization admins on Premium and Enterprise plans can create Jira Service Management sandboxes ([support.atlassian.com](https://support.atlassian.com/organization-administration/docs/jira-family-and-sandboxes/)). Run your complete migration script against the sandbox before touching production. Validate record counts, comment visibility, field values, and status transitions against a known sample of Zendesk tickets before the production run.

## Delta Sync: Capturing Changes During the Migration Window

A bulk migration takes days. During that window, Zendesk agents continue working — new tickets are created, existing tickets are updated. The delta sync captures those changes and applies them to JSM before cutover, so agents do not lose recent work.

**Webhook-based approach (preferred):** Register a Zendesk webhook (`POST /api/v2/webhooks`) targeting a listener endpoint you control, and connect it to a trigger that fires when a ticket is created or updated. Store event payloads to a queue (SQS, Pub/Sub, or a simple database table). After the bulk migration completes, replay the queue against JSM, using the idempotency pattern above to avoid duplicates.

**Incremental export polling (simpler):** Re-run the Zendesk Incremental Export API with a `start_time` set to the Unix epoch of your bulk migration start. The API returns all tickets created or updated after that timestamp. Cross-reference against your local progress database: new tickets get created in JSM, updated tickets get their fields and comments reconciled.

The incremental export approach requires no infrastructure changes but adds extraction time proportional to activity volume during the migration window. For high-volume support teams (1,000+ tickets/day), the webhook approach is more reliable.

## How to Migrate Attachments from Zendesk to JSM

Attachments cannot be passed as URLs in the JSON payload. They must be physically moved in a three-step process:

1. **Download from Zendesk.** Fetch each attachment URL from the ticket comments API response. Zendesk serves attachments via authenticated URLs.
2. **Upload as temporary attachment in JSM.** Use `POST /rest/servicedeskapi/servicedesk/{serviceDeskId}/attachTemporaryFile` to upload the file. This requires a `multipart/form-data` request with the file in a parameter named `file`, and the mandatory header `X-Atlassian-Token: no-check` ([developer.atlassian.com](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-servicedesk/)). JSM returns a `temporaryAttachmentId`. Complete step 3 within the same script execution rather than storing temporary IDs for a later run.
3. **Attach to the issue.** Use `POST /rest/servicedeskapi/request/{issueIdOrKey}/attachment` with the temporary IDs and a `public` boolean controlling portal visibility.

By default, the maximum size of any one file in JSM Cloud is 1 GB, and a Jira admin can change this limit ([support.atlassian.com](https://support.atlassian.com/jira-service-management-cloud/docs/attach-files-and-screenshots-to-issues/)). If the attachment was rendered inline within a Zendesk comment, you must also update the ADF payload of that comment to reference the new Jira attachment ID, or the image will appear broken.

## GDPR and Data Residency Considerations

For EU-based organizations, data residency is a migration constraint, not a post-migration concern.

**Zendesk:** The Data Center Location add-on lets an account host its data in the United States, the European Economic Area (EEA), the United Kingdom, Japan, or Australia. It is included at no charge on Suite Professional, Enterprise, and Enterprise Plus ([support.zendesk.com](https://support.zendesk.com/hc/en-us/articles/4408838409754-About-the-Data-Center-Location-add-on)). Your Zendesk region determines where data is extracted from.

**JSM Cloud:** Atlassian offers data residency for Jira Service Management on Standard, Premium, and Enterprise plans. Locations include the EU (Frankfurt and Dublin), Germany (Frankfurt), the USA, the UK, Australia, and others. Issues, comments, attachments, and field content can be pinned to a location. Customer accounts and user account details are out of scope ([support.atlassian.com](https://support.atlassian.com/security-and-access-policies/docs/understand-data-residency/)).

**Migration implications:**
- If you are migrating from a Zendesk EU instance to a JSM EU data residency configuration, ensure your migration infrastructure (the machine running the migration script, any intermediate storage) is also EU-resident or compliant with your data transfer agreements.
- Attachments and comment bodies downloaded from Zendesk and uploaded to JSM transit through your migration host. If that host is outside your designated region, evaluate whether this constitutes a cross-border data transfer under your applicable regulations (GDPR Article 46).
- Do not use a third-party migration SaaS tool without confirming where it processes and temporarily stores your data.

## What Cannot Be Migrated Programmatically

APIs can move data, but they cannot move logic. These Zendesk configurations have no programmatic migration path to JSM:

- **SLA policies and historical SLA data** — JSM SLAs must be rebuilt. Historical SLA attainment data does not transfer.
- **Triggers, automations, and macros** — Zendesk business rules must be recreated using JSM Automation rules.
- **Views** — Rebuild as JSM queues or JQL (Jira Query Language) filters.
- **Satisfaction ratings (CSAT)** — No native JSM equivalent. Store as a custom field if needed.
- **Zendesk Guide articles** — Requires a separate migration to Confluence, which also requires HTML-to-ADF conversion. JSM uses Confluence for knowledge management.
- **Apps and integrations** — Zendesk Marketplace apps do not transfer. Find Atlassian Marketplace equivalents or rebuild.
- **Original Zendesk ticket IDs** — JSM assigns its own issue keys. Store the original Zendesk ticket ID in a custom field for cross-reference and for idempotent re-runs.

## How Long Does a Zendesk to JSM Migration Take?

The **data migration** itself — extracting from Zendesk, transforming, and loading into JSM — typically completes within **1–5 business days**, depending on data volume, complexity, and API rate limits. Small datasets (under 10,000 records) can finish in under 24 hours.

Those figures describe the data migration ClonePartner performs. The broader replatforming project — configuring JSM request types, rebuilding workflows, setting up automations, training agents, and cutting over live channels — is a separate effort that your team runs on its own timeline. Leave room for it before an internal deadline or Zendesk contract renewal.

Run the bulk migration of historical data during the working days before go-live, while agents keep working in Zendesk. Go live on a Monday morning. Before the working day starts, freeze Zendesk and run a delta sync of only the tickets created or updated since the initial extraction, using the incremental export API or webhook queue approach described above. That final pass takes about 30 minutes, and agents log in to JSM on Monday.

## Migration Checklist: Pre-Migration Validation

Before starting a full migration run, validate the following:

**JSM configuration:**
- [ ] All target request types created with correct fields on correct screens
- [ ] All dropdown/multi-select field option values pre-created in JSM
- [ ] All agent accounts provisioned with `accountId` values recorded
- [ ] Transition ID map built from `GET /rest/api/3/issue/{key}/transitions` on a sample issue per request type
- [ ] JSM sandbox tested with a 100-ticket sample covering all ticket forms, statuses, and field types
- [ ] "Zendesk Ticket ID" custom field created for idempotency tracking

**Migration script:**
- [ ] Local progress database initialized
- [ ] Idempotency checks implemented (JQL lookup before create)
- [ ] Exponential backoff on 429 responses implemented
- [ ] Comment visibility (`public` boolean) mapped from Zendesk `public` field
- [ ] Internal note test: verify at least one `"public": false` comment is not visible in customer portal
- [ ] Attachment three-step pipeline tested; temp attachment expiry handled within single execution

**Data:**
- [ ] Zendesk custom field schema exported and mapped to JSM equivalents
- [ ] Lookup/relationship fields handled (text fallback or Assets mapping defined)
- [ ] Regex-validated fields documented as plain-text post-migration
- [ ] Delta sync strategy confirmed (webhook queue or incremental polling)

## DIY or Managed Migration?

The right threshold is not raw ticket count — it is complexity of the field mapping and your tolerance for script debugging in production.

**DIY is viable when:**
- Fewer than 5,000 tickets with simple field types (text, integer, date — no lookup fields or complex multi-selects)
- No HIPAA, SOC 2, or GDPR cross-border constraints
- Engineering capacity to build, test, and re-run a migration script
- Adequate time for iterative testing and re-runs

**A managed or supervised migration is worth considering when:**
- Complex field types (lookup fields, regex-validated fields, multi-select with large option sets)
- Strict compliance requirements where data transit path must be documented
- Hard cutover deadline with no room for extended debugging
- Attachment volume exceeding 50 GB (throughput management becomes its own problem)

Regardless of approach: **API > JSON > CSV** in preference order. CSV drops comments, descriptions, and several custom field types silently. Never use it for migrations involving conversation history.

> [!TIP]
> For a broader JSM migration checklist — covering not just Zendesk but any source platform — see our [Jira Service Management Migration Checklist](https://clonepartner.com/blog/blog/jira-service-management-migration-checklist). For the reverse direction, see [How to Migrate from JSM to Zendesk](https://clonepartner.com/blog/blog/how-to-migrate-from-jira-service-management-to-zendesk).

## What to Do Next

Start with the field audit. Export your Zendesk custom fields and ticket forms, then map them against your target JSM request types using the field type compatibility matrix above. Identify any lookup fields, regex fields, or multi-select fields that require transformation decisions before code is written. Build a sample issue in JSM for each ticket form and retrieve transition IDs for each workflow. Run a 100-ticket sample migration through your JSM sandbox before committing to a full run. The mapping exercise and sandbox validation will surface most of the complexity before any production data moves.

> Book a free 30-minute scoping call. We'll review your Zendesk instance, map the data model differences, and give you a fixed-price proposal starting at $500 — no hourly billing, no hidden fees.
>
> [Talk to us](https://clonepartner.com/talk-to-us?duration=30&utm_source=blog&utm_medium=button&utm_campaign=demo_bookings&utm_content=cta_click&utm_term=demo_button_click)

## Frequently asked questions

### Can I migrate Zendesk tickets to Jira Service Management via CSV?

Not cleanly. Zendesk CSV exports leave out ticket comments, ticket descriptions, and multi-line text, multi-select, and custom date fields. For anything beyond a basic proof-of-concept, use the Zendesk Incremental Export API for extraction and the JSM Service Desk API for loading.

### How long does a Zendesk to Jira Service Management migration take?

The data migration itself typically completes in 1–5 business days, depending on volume, complexity, and API rate limits. Small datasets under 10,000 records can finish in under 24 hours. This covers the data migration ClonePartner performs, not your JSM configuration or workflow rebuild, which is a separate project on your own timeline.

### What Zendesk data cannot be migrated to Jira Service Management?

SLA policies and historical SLA data, triggers, automations, macros, views, satisfaction ratings, Zendesk Guide articles (requires a separate Confluence migration), marketplace app data, and original Zendesk ticket IDs (store in a custom field for reference).

### How do I keep internal notes private during a Zendesk to JSM migration?

Use the JSM Service Desk comment API (POST /rest/servicedeskapi/request/{issueIdOrKey}/comment) with "public": false. The standard Jira comment API has no documented field for internal comments, so notes added through it can reach customers in the portal.

### Do I need to convert Zendesk HTML comments to Atlassian Document Format (ADF)?

Only if you use the Jira platform API (v3) for issue creation. The JSM Service Desk comment API accepts plain-text body strings. If rich formatting preservation matters, convert HTML to ADF using Atlassian's atlaskit libraries or community tools.
