Kustomer to Jira Service Management Migration: Technical Guide
Technical guide to migrating from Kustomer to Jira Service Management. Covers data model mapping, API extraction, comment visibility, KObject handling, and rate limits.
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
Kustomer to Jira Service Management Migration: Technical Guide
Quick Answer: Migrating from Kustomer to Jira Service Management (JSM) is a data-model translation — Kustomer organizes everything around a customer timeline, while JSM organizes everything around issues. There is no native migration path. The single biggest risk is exposing internal notes as public comments if your migration script uses the standard Jira comment API (/rest/api/3/issue/{key}/comment) instead of the Service Desk API (/rest/servicedeskapi/request/{key}/comment) with "public": false. Kustomer's KObjects have no 1:1 JSM equivalent and must be handled as custom fields, linked issues, or JSM Assets. Workflows, business rules, and SLA policies cannot be exported from Kustomer and must be rebuilt manually. Realistic timeline: 2–4 weeks for most environments. Teams with fewer than 5,000 conversations and no KObjects can attempt a DIY API script. Everyone else should use a managed migration service.
What Is a Kustomer to JSM Migration?
A Kustomer to JSM migration is the process of extracting customers, conversations, messages, notes, attachments, tags, custom fields, and KObjects from Kustomer's CRM-based customer service platform and loading them into Atlassian's Jira Service Management — while preserving conversation history, comment visibility, and user attribution.
This is non-trivial because the two platforms model support data in fundamentally different ways. Kustomer gives each customer a single timeline — a chronological feed of every interaction across every channel. Conversations exist but hang off the customer record rather than defining it. JSM is issue-centric: every support interaction is a Jira issue with fields, comments, and a workflow state machine.
Because these platforms organize data differently at the database level, a migration is not a simple file transfer. It is a data-model translation problem. If you attempt to map Kustomer data directly to JSM without understanding Atlassian's underlying architecture, you risk breaking ticket threading, exposing internal notes to customers, and losing historical author attribution.
Why Teams Move from Kustomer to JSM
- Atlassian ecosystem consolidation. Engineering teams already on Jira Software and Confluence want a single pane of glass for IT and customer support. JSM's native links to Jira issues and Confluence knowledge bases reduce tool sprawl.
- ITSM maturity. Kustomer is built for omnichannel B2C support — messaging, sentiment analysis, CRM timelines. Teams that need structured ITSM workflows (change management, incident management, problem management) find JSM's ITIL alignment a better fit.
- Cost restructuring. Kustomer's pricing is per-agent with usage-based tiers. JSM's free tier supports up to 3 agents, and its Standard plan can be more cost-effective for teams that don't need Kustomer's AI features.
- Platform stability concerns. Meta acquired Kustomer for a reported $1 billion in 2020, then divested it in 2023. Kustomer subsequently raised a $30 million Series B as an independent company oriented toward an AI-centric roadmap. Some teams prefer Atlassian's long-term ecosystem predictability.
Kustomer vs. JSM Data Model: The Core Translation Problem
Understanding the structural mismatch is the prerequisite for a successful migration. Here's how the core objects map:
| Kustomer Object | JSM Equivalent | Notes |
|---|---|---|
| Customer | Customer (portal user) | JSM customers are portal users, not CRM records. No timeline concept. |
| Conversation | Issue (Service Request) | One conversation = one issue. Channel metadata is lost. |
| Message (outbound/inbound) | Public comment | Map to comments via the Service Desk API. |
| Note | Internal comment | Must use "public": false on the Service Desk comment API. |
| KObject (custom object) | Custom field, linked issue, or JSM Asset | No native equivalent. Requires design decisions. |
| Tag | Label | JSM labels are flat strings — no nesting. |
| Team | Group / Queue | JSM uses agent groups for assignment. |
| Snippet (canned response) | Canned response (JSM template) | Manual recreation required. |
| Workflow / Business Rule | Automation rule | Cannot be exported; must be rebuilt. |
| Knowledge Base Article | Confluence page | Requires a separate migration to Confluence. |
KObjects are the hardest mapping problem. Kustomer lets you define custom object schemas (Klasses) — orders, subscriptions, shipments — tied to customer timelines. JSM has no native equivalent. Your options: flatten KObject data into custom fields on the issue, create linked Jira issues in a separate project, use JSM Assets (formerly Insight, requires Premium plan), or store references as external links. Each approach has trade-offs in searchability, reporting, and agent experience.
Step 1: Audit and Scope the Migration
Before writing any code, inventory what you're moving and what you're leaving behind.
What to count
- Conversations — total count, plus how many are older than 2 years. The standard Kustomer Search API only returns records updated within the past 2 years. Conversations older than 2 years will not appear in search results. Use the Archive Search endpoint (
/v1/customers/archive/search) to access conversations older than 2 years. Missing this means you silently lose old conversations. - Messages per conversation — drives the number of JSM comment API calls. High-touch accounts can have hundreds of messages on a single conversation.
- Attachments — total count and total size. In JSM Cloud, the limit is 1 GB per attachment on all plans. Storage quotas apply per plan: Standard plan tenants have a 250 GB total storage limit; Premium plan tenants have unlimited file storage per the Atlassian storage documentation.
- KObjects — count by Klass type. Decide the mapping strategy (custom fields vs. linked issues vs. Assets) before extraction begins.
- Custom fields — Kustomer allows custom attributes on every object type. Map each one to a JSM custom field or decide to drop it.
- Users and agents — every agent you migrate needs a paid JSM agent license. Customers are portal users and are not billed as agents.
Migration size benchmarks
The following estimates are derived from Kustomer's published API rate limits and a fixed assumption of 15 API calls per conversation (1 customer fetch + 1 conversation fetch + 8 messages + 3 notes + 2 attachment downloads). Actual call counts vary with message volume.
| Conversation Count | Est. Total API Calls | Time at 500 rpm (Business) | Time at 1,000 rpm (Enterprise) |
|---|---|---|---|
| 5,000 | ~75,000 | ~2.5 hours | ~1.25 hours |
| 50,000 | ~750,000 | ~25 hours | ~12.5 hours |
| 200,000 | ~3,000,000 | ~100 hours | ~50 hours |
These are extraction-only estimates. JSM load time adds roughly 30–50% on top at sustained write rates of 50–80 requests/second (observed on Standard-tier Cloud tenants; Enterprise tenants typically sustain higher throughput before hitting burst limits — test your specific tenant before committing to a timeline).
What you cannot export from Kustomer
Business rules (automations and workflows), conversational assistant configurations, custom timeline layouts, and routing queue settings are not included in any Kustomer export format. Document these manually: screenshot your workflow conditions and actions, copy your snippet text, and note your SLA policy thresholds and routing rules before canceling your account.
Step 2: Extract Data from Kustomer via API
Kustomer offers multiple export paths. For migration, only the API approach gives you the fidelity you need.
Why CSV exports fall short
The Export Buddy app exports current users, teams, snippets, shortcuts, conversation tags, and knowledge base articles as CSV files. It does not export customer data, conversation history, messages, or attachments. Reporting exports flatten relational data — you lose the customer→conversation→message hierarchy. For environments over 10,000 tickets, do not rely on CSV exports. You need the REST API.
API extraction pattern
Kustomer uses standard Bearer token authentication. The extraction follows the data hierarchy:
- List all customers via
GET /v1/customerswith cursor-based pagination. - For each customer, fetch conversations via
GET /v1/customers/{id}/conversations. - For each conversation, fetch messages via
GET /v1/conversations/{id}/messagesand notes viaGET /v1/conversations/{id}/notes. - For each message with attachments, download attachment binaries from Kustomer's AWS S3 buckets.
- Fetch KObjects per customer via
GET /v1/customers/{id}/klasses/{klassName}.
Pagination is cursor-based using page [size] (max 100) and page [after] parameters. You must follow the links.next URL in the JSON response rather than incrementing page numbers. The Search API has a hard limit of 100 pages per query. If your dataset exceeds 100 pages, use cursor-based pagination to work around this limit.
Rate limit planning
Kustomer publishes the following rate limits for machine users by plan tier (Kustomer API documentation):
| Plan | Rate Limit |
|---|---|
| Professional | 300 rpm |
| Business | 500 rpm |
| Enterprise | 1,000 rpm |
| Ultimate | 2,000 rpm |
This limit is counted against the sum of all requests through the API across the entire platform, regardless of endpoint or target object. Any automated integration running in parallel (webhooks, BI connectors, Zapier flows) reduces your effective budget for migration calls.
For a 50,000-conversation migration on the Enterprise tier (1,000 rpm), extracting customers + conversations + messages + notes takes roughly 12–16 hours of continuous API calls depending on message volume per conversation. Build retry logic with exponential backoff — a 429 response means your application has exceeded the rate limit.
import time
import requests
KUSTOMER_API_KEY = "your-api-key"
BASE_URL = "https://api.kustomerapp.com/v1"
HEADERS = {"Authorization": f"Bearer {KUSTOMER_API_KEY}"}
def fetch_paginated(url, params=None):
results = []
while url:
resp = requests.get(url, headers=HEADERS, params=params)
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 60))
time.sleep(retry_after)
continue
resp.raise_for_status()
data = resp.json()
results.extend(data.get("data", []))
url = data.get("links", {}).get("next")
params = None # next URL includes params
return results
# Fetch all customers
customers = fetch_paginated(f"{BASE_URL}/customers")Extract to an intermediate format. Don't try to write directly to JSM during extraction. Dump everything to local JSON files first, then transform and load in a separate phase. This decouples the two APIs, makes debugging easier, and lets you re-run the load phase without re-extracting.
Step 3: Transform — Map Kustomer Data to JSM Schema
This is where the real engineering work happens.
Conversation → Issue mapping
Each Kustomer conversation becomes one JSM issue. Map these fields:
- Conversation subject → Issue
summary - Conversation status (open, snoozed, done) → JSM workflow status. Issues are created in the initial workflow status, so you must transition each issue to the correct status after creation.
- Conversation priority → Issue
priority(map Kustomer's priority levels to JSM's scheme) - Conversation tags → Issue
labels(JSM labels are flat strings, no spaces allowed — replace spaces with hyphens or underscores) - Assigned team → JSM group/queue assignment
- Assigned agent → Issue
assignee(requires the agent's Atlassian Account ID) - Created timestamp → There is no native way to set
createdon a JSM issue via the API. Store the original creation date in a custom DateTime field.
You cannot backdate issue creation in JSM Cloud. The created field is system-generated and immutable. If preserving original timestamps matters for reporting or compliance, store the Kustomer createdAt in a dedicated DateTime custom field (e.g., "Original Created Date") and train your team to filter on it. Comment creation dates are also set to the time the API call is made, not the original Kustomer timestamp. This limitation affects SLA reporting on migrated tickets — any time-based SLA metric will be calculated from migration date, not original creation date.
Mapping statuses
Kustomer's default statuses are simple: Open, Done, Snoozed. JSM uses Jira workflows, which can be complex (e.g., Waiting for Support, Waiting for Customer, Escalated, Resolved). You must map Kustomer's flat statuses to JSM's workflow steps and then transition each issue to its correct final state after creation.
Simplify transitions during migration. Temporarily modify the JSM workflow to allow "Any Status to Any Status" transitions. This lets your script set the final state directly without triggering required fields, validation rules, or approval gates. Revert the workflow once the migration finishes.
Custom attributes → Custom fields
Kustomer allows custom attributes on Conversations. In JSM, these become Custom Fields. Before migrating, create the necessary Custom Fields in Jira and associate them with the correct Request Types and Issue Screens. Note the Custom Field IDs (e.g., customfield_10024), as the Atlassian API requires the ID, not the field name, when inserting data.
Kustomer's custom attribute type system includes types that have no JSM equivalent. The table below maps every Kustomer attribute type to its JSM counterpart:
| Kustomer Attribute Type | JSM Custom Field Type | Data Loss Risk |
|---|---|---|
string |
Text Field (single line) | None |
number |
Number Field | None |
boolean |
Checkbox | None |
date |
Date Picker | None |
datetime |
Date Time Picker | None |
email |
Text Field | None — JSM has no native email field type |
url |
URL Field | None |
select (single) |
Select List (single choice) | None — recreate options manually |
multiselect |
Select List (multiple choices) | None — recreate options manually |
tree |
Select List (single or cascading) | High — hierarchical structure is lost; flatten to leaf-node values |
object (nested) |
Not supported | Total — store as JSON in a Text Area field or use JSM Assets |
Map every custom attribute type before starting the load phase. A type mismatch causes a 400 Bad Request with the message "Field 'customfield_XXXXX' cannot be set" — which will silently drop the field value if your error handling is not strict.
Message → Comment mapping (the visibility trap)
This is the highest-risk mapping in the entire migration.
A conversation in Kustomer represents a set of interactions with a customer about a specific topic. Conversations can span multiple channels and include a set of messages and internal notes. Kustomer separates messages (customer-facing) from notes (internal-only). Notes are internal communications visible only to users in the organization.
In JSM, comments come in two flavors: public comments and internal comments. If a customer is using the REST API, they will only see public comments. If a licensed JSM agent is using the REST API, they will see all comments, both public and internal.
You must use the Service Desk API to set comment visibility:
# Public comment (customer-visible)
curl -X POST \
"https://your-domain.atlassian.net/rest/servicedeskapi/request/{issueKey}/comment" \
-H "Authorization: Basic <base64-encoded-credentials>" \
-H "Content-Type: application/json" \
-d '{"body": "Message text here", "public": true}'
# Internal comment (agent-only)
curl -X POST \
"https://your-domain.atlassian.net/rest/servicedeskapi/request/{issueKey}/comment" \
-H "Authorization: Basic <base64-encoded-credentials>" \
-H "Content-Type: application/json" \
-d '{"body": "Internal note text here", "public": false}'When public: false, the comment becomes an internal note that is invisible to customers. If you use the standard Jira API (/rest/api/3/issue/{key}/comment) instead, the visibility parameter uses role-based restrictions — which does not hide comments from JSM portal users the same way. The standard Jira API's visibility parameter restricts visibility to Jira roles/groups but does not hide the comment from customers in the JSM portal.
Rule: Kustomer messages → "public": true. Kustomer notes → "public": false. Always use the Service Desk API. If the Kustomer message type is ambiguous, default to false. Exposing years of private agent discussions to your customer base is not recoverable.
Author attribution
Both the Service Desk comment API and the standard Jira comment API create comments as the authenticated user. If you use a single admin API token, every comment in JSM will say "Created by Admin." JSM Cloud does not natively support creating comments on behalf of another user via API.
Workaround: Prepend the original author's name and timestamp to each comment body:
[Jane Doe — 2024-03-15 14:22 UTC] Original message text here.
For issues, you can preserve attribution more cleanly. The Service Desk API supports raiseOnBehalfOf when creating requests, allowing you to set the customer who raised the request. For assignee, pass the agent's Atlassian Account ID (AAID).
To get AAIDs, provision your Kustomer agents and customers in JSM first, then query the Atlassian API (/rest/api/3/user/search?query=email@domain.com) to build a mapping dictionary of email → AAID. Build this map before starting the issue creation phase — attempting to look up AAIDs inline during migration slows throughput and introduces points of failure.
Customer → JSM Customer mapping
JSM customers are portal users who can raise requests and view their tickets. Unlike Kustomer's rich CRM profiles, JSM customer records are minimal — email, display name, and organization membership.
To create customers programmatically, use the Service Desk API:
POST /rest/servicedeskapi/customer
{"displayName": "Jane Doe", "email": "jane@example.com"}
Custom CRM data from Kustomer (phone numbers, external IDs, social handles, sentiment data) must either go into JSM custom fields on the customer's issues or live in an external system linked via Jira's Assets/CMDB feature. There is no customer-level custom field in JSM — all custom data attaches to issues, not to the customer entity itself. If your agents rely on customer-level attributes for routing or personalization, this architectural difference requires a process change, not just a data migration.
KObject handling strategies
Kustomer's CRM data model is built on Klasses and KObjects. You can model your own business data — order, shipment, subscription, policy, claim, loyalty tier — as structured objects tied to each customer. JSM has no equivalent. Your options:
| Strategy | Pros | Cons |
|---|---|---|
| Flatten into custom fields | Simple, searchable within the issue | Loses structure; one-to-many relationships become awkward |
| Linked issues in a separate project | Preserves entity relationships; can use Jira's linking | Adds issue count; clutters search; requires careful project design |
| JSM Assets / Insight objects | Closest structural equivalent; real CMDB objects | Requires JSM Premium; more setup effort |
| External reference (URL field) | Zero JSM clutter; data stays in source system | Agents must click out; no in-Jira search |
For most teams, flattening the most-used KObject attributes into 5–10 custom fields is the pragmatic choice. Store the full KObject JSON in an external data store and link to it for edge cases.
JSM Assets import for KObjects (Premium plan only)
If your team relies heavily on KObjects and you're on JSM Premium or Enterprise, Jira Assets is the better path. Here is the minimum viable process:
- Define an Object Schema in Jira Assets (Assets → Object Schemas → Create Schema).
- Create Object Types that mirror your Kustomer KObject classes (e.g.,
Order,Subscription). For each Object Type, define attributes matching the KObject Klass fields — use Assets attribute types:Text,Integer,Float,Boolean,Date,DateTime,URL,Select,Object(for references). - Export KObjects from Kustomer via
GET /v1/customers/{id}/klasses/{klassName}for each customer. - Prepare the Assets CSV import file. The required CSV schema for Assets import is:
- Column 1:
objectKey(leave blank for new objects; Assets auto-assigns) - Columns 2–N: one column per Object Type attribute, using the exact attribute name as defined in step 2
- Optional:
Created,Updated(ISO 8601 datetime strings) - Import via Assets → Object Types → [your type] → Import → CSV
- Column 1:
- Alternatively, use the Assets REST API (
POST /rest/assets/1.0/object/create) with a JSON body specifyingobjectTypeIdandattributesas an array of{objectTypeAttributeId, objectAttributeValues}pairs. RetrieveobjectTypeAttributeIdvalues viaGET /rest/assets/1.0/objecttype/{id}/attributes. - Create an Assets custom field on your JSM Request Types and link the Jira issue to the specific Asset object using the field's object picker.
If you are on JSM Standard, Jira Assets is unavailable. You must flatten or link externally.
Step 4: Load Data into Jira Service Management
API choice: Service Desk API vs. standard Jira API
There are two APIs that can create issues: POST /rest/api/3/issue (standard Jira create issue API) and POST /rest/servicedeskapi/request (Service Desk create request API).
Use /rest/servicedeskapi/request to create issues. This ensures request types are set correctly and the issue appears properly in the JSM portal. The standard Jira API creates the issue but skips request-type assignment, meaning it won't show up in the customer portal as expected.
JSM uses Basic Auth (email address and API token encoded in base64) or OAuth 2.0 for enterprise integrations.
Rate limits on the JSM side
Atlassian does not publish fixed rate limits for JSM Cloud because the computation logic evolves continuously. When any limit is exceeded, JSM returns an HTTP 429 Too Many Requests response. Your app should handle this gracefully by respecting the Retry-After header and implementing exponential backoff.
Rate limiting is enforced per tenant and per API/resource path. The burst limit is independent of the number of users in the tenant; adding more users does not increase the per-second allowance.
In practice, sustained write rates of 50–80 requests/second are achievable on Standard-tier Cloud tenants before hitting burst limits (observed in migration testing; Enterprise tenants typically sustain higher throughput). Start conservative and ramp up while monitoring 429 response rates.
Warning: Ignoring Atlassian's Retry-After header and continuing to hammer the API will result in temporary IP bans, halting your migration completely.
Load sequence
- Create JSM customers — build a Kustomer customer ID → JSM customer account ID lookup map.
- Create custom fields — ensure all mapped custom fields exist in the target project before creating issues.
- Create issues — one per Kustomer conversation. Use
raiseOnBehalfOfto attribute the request to the original customer. Store the issue key in your lookup map. - Add comments — for each conversation, add messages and notes in chronological order using the Service Desk comment API. Set the
publicflag correctly. - Upload attachments — for each message with attachments, upload via
POST /rest/api/3/issue/{issueKey}/attachmentswith the requiredX-Atlassian-Token: no-checkheader. - Transition issue status — move each issue to the correct status using
POST /rest/api/3/issue/{issueKey}/transitions.
Comment ordering matters. JSM displays comments in chronological order based on creation timestamp. If you load comments out of order (e.g., parallelizing API calls per conversation), the conversation thread will be scrambled. Load comments sequentially within each conversation, sorted by Kustomer's sentAt timestamp.
Handling attachments
Attachments require a two-step transfer because you cannot pass a URL to JSM and ask it to fetch the file.
- Download: Parse the Kustomer message for attachment URLs. Use an authenticated GET request to download the binary file from Kustomer to your local migration server.
- Upload: Post the binary file to JSM using the
/rest/api/3/issue/{issueKey}/attachmentsendpoint.
Atlassian requires a specific header to prevent Cross-Site Request Forgery (CSRF) attacks when uploading attachments via the API. You must include X-Atlassian-Token: no-check in your POST request.
curl -D- -u user@domain.com:api_token \
-X POST \
-H "X-Atlassian-Token: no-check" \
-F "file=@/local/path/to/image.png" \
https://your-domain.atlassian.net/rest/api/3/issue/PROJ-123/attachmentsFailure to include this header results in a 403 Forbidden error, even if your API token has full administrative permissions. The per-file limit on JSM Cloud is 1 GB. Most Kustomer attachments are well under this, but validate sizes before loading if you have large files from email or chat channels.
Step 5: Delta Sync — Handling Conversations Created After Extraction Begins
For production migrations with live customer traffic, there is always a window between when you start extracting from Kustomer and when you complete loading into JSM. Conversations created or updated in Kustomer during this window will be missing from JSM unless you run a delta sync.
Delta sync process
- Record the extraction start timestamp before your first Kustomer API call. Store this as
EXTRACTION_START. - Run the full initial extraction and load as described in Steps 2–4.
- After the load completes, query Kustomer for all conversations with
updatedAt > EXTRACTION_START:GET /v1/conversations?filter [updatedAt][gte]=EXTRACTION_START - For new conversations (not yet in JSM): run the full create + comment + attachment sequence.
- For updated conversations (already in JSM): compare comment counts and field values. Add any new comments; update changed field values via
PUT /rest/api/3/issue/{issueKey}. - Repeat the delta sync with a tighter window (last 2–4 hours) immediately before the go-live cutover.
Deduplication
Before creating an issue in JSM, check your Kustomer ID → JSM issue key lookup map. If a Kustomer conversation ID already exists in the map, the conversation was loaded in the initial pass — skip creation and go directly to updating fields and adding new comments.
If your migration script crashed mid-run, rebuild the lookup map by querying JSM for issues with a custom field storing the original Kustomer conversation ID (create this field before migration begins). This field also serves as the authoritative deduplication key for delta syncs.
Cutover window
Zero-downtime cutover is achievable for most environments:
- Keep Kustomer active while loading into JSM.
- Run delta syncs on a schedule (every 2–4 hours) during the migration window.
- Run a final delta sync immediately before switching agent access to JSM.
- After the final delta sync, disable new Kustomer conversations (set your support email routing and chat widgets to JSM's intake).
- Validate JSM data, then decommission Kustomer.
For environments with under 5,000 conversations, the total migration window (initial load + one delta sync) can fit within a weekend maintenance window.
Step 6: Rebuild What Can't Be Migrated
APIs can move data, but they cannot move logic. These elements must be manually rebuilt in JSM before your go-live date:
- Workflows and business rules — Kustomer's visual workflow builder and rule engine must be manually recreated as JSM automation rules. Document every rule before decommissioning Kustomer.
- SLA policies — Kustomer SLAs track time based on business hours and message events. JSM SLAs are JQL-based timers. These must be rebuilt under Project Settings → SLAs. Note: SLA timers on migrated issues will calculate from the migration date, not the original creation date, unless you use the "Original Created Date" custom field approach described in Step 3.
- Routing queues — Kustomer's queue-based routing translates to JSM queues, but must be manually configured.
- Snippets/canned responses — Export from Kustomer via Export Buddy, then manually recreate in JSM as templates.
- Knowledge base — Kustomer's knowledge base does not map directly to JSM. JSM requires Atlassian Confluence. Migration steps: (1) Export Kustomer KB articles as HTML or Markdown via the Kustomer API or Export Buddy. (2) Create a Confluence space for each Kustomer knowledge base category. (3) Import articles into Confluence using Confluence's HTML/Markdown import or the Confluence REST API (
POST /wiki/rest/api/content). (4) Link the Confluence space to your JSM portal under Project Settings → Knowledge Base. (5) Test that the JSM portal search surfaces Confluence articles to customers.
For a complete list of pre-migration tasks, review our Jira Service Management Migration Checklist.
Common Failure Modes
API Error Reference
The following table covers errors you will encounter in production migration scripts — not edge cases, but predictable failures with known fixes:
| Error | API | Cause | Fix |
|---|---|---|---|
429 Too Many Requests |
Kustomer or JSM | Rate limit exceeded | Respect Retry-After header; implement exponential backoff |
403 Forbidden on attachment upload |
JSM | Missing X-Atlassian-Token: no-check header |
Add the header to all attachment POST requests |
400 Bad Request: "Field cannot be set" |
JSM | Custom field type mismatch (e.g., sending string to a number field) | Validate field types against Kustomer attribute type mapping table |
404 Not Found on user lookup |
JSM | Invalid or non-existent Atlassian Account ID | Pre-build AAID lookup map; handle missing users by leaving assignee blank |
401 Unauthorized |
Kustomer or JSM | Expired API token or incorrect auth encoding | Rotate token; verify base64 encoding for Basic Auth |
400 Bad Request: "Reporter not found" |
JSM | raiseOnBehalfOf email doesn't match a JSM customer |
Create the customer via Service Desk API before creating the issue |
400 Bad Request: "Request type not found" |
JSM | Using standard Jira API instead of Service Desk API for creation | Switch to /rest/servicedeskapi/request |
400 Bad Request: "Transition not found" |
JSM | Workflow transition doesn't exist for the current status | Enable "Any to Any" transitions during migration; revert after |
413 Payload Too Large |
JSM | Attachment exceeds 1 GB | Validate file sizes before upload; split or skip oversized files |
1. Internal notes exposed to customers
This is the #1 migration defect. Using the standard Jira comment API instead of the Service Desk API, or forgetting to set "public": false, will leak internal notes to the customer portal. Validate every comment's public flag in a staging environment before going live.
2. Author attribution loss
Every comment created with a single admin API token appears as that admin. There is no way to back-attribute comments to another user in JSM Cloud. Prepend original author names and timestamps to comment bodies during migration — this cannot be fixed after the fact.
3. Missing conversations older than 2 years
The standard Search API only returns records updated within the past 2 years. If you need historical data, use the Archive Search endpoint (/v1/customers/archive/search). Missing this means you silently drop old conversations without any error.
4. Scrambled comment order
If you parallelize comment creation within a single conversation, JSM will timestamp them based on API call order, not the original Kustomer timestamp. The result is a garbled conversation history. Always load comments sequentially per conversation.
5. Custom field type mismatches
Kustomer's tree type (hierarchical select) and nested object types have no JSM equivalents. If you don't map every attribute type before starting the load phase, you'll hit 400 errors or silently lose field values mid-migration.
6. Delta sync deduplication failures
If your migration script crashes and restarts without a deduplication key, you will create duplicate issues in JSM. Always store the Kustomer conversation ID in a dedicated custom field on the JSM issue during creation. Use this field as your deduplication check on restarts and delta syncs.
Migration Timeline Estimate
| Phase | Duration | Depends On |
|---|---|---|
| Audit & scoping | 2–3 days | Conversation count, KObject complexity |
| Field mapping & JSM configuration | 2–4 days | Custom field count, workflow design |
| Script development & testing | 3–5 days | Developer experience, edge cases |
| Staging migration (full dry run) | 2–3 days | Data volume, rate limits |
| Validation & QA | 2–3 days | Spot-check sample size |
| Production migration + delta syncs | 1–2 days | Data volume |
| Manual rebuild (workflows, SLAs, KB) | 3–5 days | Rule complexity |
| Total | 15–25 business days |
Teams with under 5,000 conversations, no KObjects, and standard fields can compress this to 10–12 days. Complex environments with 100K+ conversations and extensive custom schemas should budget 4–6 weeks.
Validation Checklist
Before going live, verify:
- Conversation count matches — total issues in JSM equals total conversations extracted from Kustomer
- Comment count per issue — spot-check 50+ issues to verify message + note count matches
- Internal notes are internal — open the JSM portal as a customer and confirm no internal notes are visible
- Attachments are accessible — download and verify a sample of migrated attachments
- Custom field values populated — check that mapped fields contain correct data, including type validation (numbers in number fields, dates in date fields)
- Status accuracy — verify closed/resolved conversations map to the correct terminal JSM status
- Author labels — confirm that comment bodies include original author attribution
- Chronological order — verify comments on spot-checked issues appear in the correct sequence
- Delta sync completeness — confirm no conversations created after extraction start are missing
- KObject data integrity — if using Assets, verify object links are intact; if flattened, verify custom field values match source KObject attributes
- Deduplication check — run a search for issues with duplicate Kustomer conversation ID custom field values; result should be zero
DIY vs. Managed Migration
Build it yourself if:
- You have fewer than 5,000 conversations
- You do not use KObjects
- Your custom field schema is straightforward
- Your engineering team has 2–3 weeks to dedicate to writing, testing, and debugging the scripts
Use a managed service if:
- You have 10K+ conversations and need guaranteed data integrity
- KObjects or complex custom field schemas require careful design decisions
- You cannot afford the risk of exposing internal notes publicly
- You need zero downtime — keeping Kustomer running while loading into JSM, then doing a delta sync
- Your team doesn't have engineering bandwidth to build, test, and validate throwaway migration scripts
For more on Kustomer data extraction, see our guide on how to export data from Kustomer. If you're evaluating the architectural differences between platforms, our Zoho Desk to JSM migration guide covers similar ITSM data mapping challenges, and our Kustomer to Zendesk guide provides an alternative look at moving away from Kustomer.
What Decides Whether This Migration Succeeds
A Kustomer to JSM migration forces a re-evaluation of how your support team operates. You are moving from a flexible, customer-centric timeline to a structured issue tracker with strict workflow semantics. The success of the migration depends on how well you map the data model before writing the extraction code, how carefully you handle comment visibility during the load phase, and whether you plan for delta sync before your cutover date.
Define your Jira workflows, provision your users, build your field mapping document, and run a full dry run in a sandbox environment. Treat this as a software engineering project, not an administrative task.
Frequently Asked Questions
- Can I migrate from Kustomer to Jira Service Management using CSV?
- Not for a full migration. Kustomer's Export Buddy and reporting exports only cover users, teams, snippets, tags, and flattened conversation data. They don't preserve the customer→conversation→message hierarchy, attachments, or internal notes. You need the Kustomer REST API for a complete extraction. JSM also lacks a bulk CSV import for issues with threaded comments.
- How do I preserve internal notes when migrating from Kustomer to JSM?
- Use the JSM Service Desk API endpoint POST /rest/servicedeskapi/request/{issueKey}/comment with "public": false for Kustomer notes. Do not use the standard Jira comment API — its visibility parameter restricts by role/group but does not hide comments from JSM portal customers.
- What happens to Kustomer KObjects in Jira Service Management?
- JSM has no native equivalent to KObjects. Your main options are: flatten KObject attributes into custom fields on the JSM issue, create linked issues in a separate Jira project, use JSM Assets (requires Premium plan) as CMDB objects, or store KObject data externally and link via URL fields. Most teams flatten the most-used attributes into custom fields.
- How long does a Kustomer to JSM migration take?
- Typically 2–4 weeks for most environments. Small teams (under 5K conversations, no KObjects) can finish in 10–12 days. Complex migrations with 100K+ conversations, KObjects, and extensive custom fields should budget 4–6 weeks including validation and manual workflow rebuilds.
- Can I preserve original timestamps when migrating to JSM?
- No. JSM Cloud's created field is system-generated and immutable via the API. Store Kustomer's original createdAt timestamp in a custom DateTime field. Comment creation dates are also set to the time the API call is made, not the original Kustomer timestamp.


