Skip to content

Kustomer to Deskpro Migration: The Complete Technical Guide

A technical guide to migrating from Kustomer to Deskpro, covering API extraction, data model mapping, KObject handling, rate limits, and validation.

Roopi Roopi · · 25 min read
Kustomer to Deskpro Migration: The Complete Technical Guide
TALK TO AN ENGINEER

Planning a migration?

Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.

Schedule a free call
  • 1,500+ migrations completed
  • Zero downtime guaranteed
  • Transparent, fixed pricing
  • Project success responsibility
  • Post-migration support included
Info

TL;DR — Kustomer to Deskpro Migration

A Kustomer to Deskpro migration is a data-model translation project. Kustomer's customer-centric timeline architecture — where Conversations, Messages, Notes, and KObjects all hang off a single Customer record — must be decomposed into Deskpro's ticket-centric model of People, Organizations, Tickets, and Messages. The realistic timeline is 2–3 weeks for under 50K conversations (roughly 1 week extraction, 3–4 days transformation, 1 week loading and validation), and 3–5 weeks for larger datasets with complex KObject schemas. The single biggest risk is losing full conversation transcript history: Kustomer's CSV exports only include message previews, not full message bodies, so you must extract via the REST API. KObjects have no direct equivalent in Deskpro — they must be flattened into custom fields on Tickets, People, or Organizations. Kustomer's Business Rules, Workflows, and Saved Searches cannot be exported and must be rebuilt as Deskpro Triggers and Automations manually.

What Is a Kustomer to Deskpro Migration?

A Kustomer to Deskpro migration is the process of extracting Customers, Companies, Conversations, Messages, Notes, KObjects, Tags, Users, and Teams from Kustomer and loading them into Deskpro as People, Organizations, Tickets, Messages, Notes, Labels, Agents, and Agent Teams.

A successful migration starts with one question: are you migrating records, or working context? If agents need searchable thread history, notes, attachments, and account relationships after cutover, treat this as an API/ETL job — not a flat CSV import.

Kustomer is a customer-centric CRM and support platform built around a single-timeline architecture. Every interaction — email, chat, SMS, social — hangs off a unified Customer record. Custom data objects (KObjects) let teams model business-specific entities like orders, subscriptions, or shipments directly within the platform.

Deskpro is a ticket-centric helpdesk platform available as cloud, private cloud, or on-premise. It organizes work around Tickets assigned to Departments, with People (end users) and Organizations providing the CRM layer. Deskpro supports custom fields on Tickets, People, and Organizations but does not have a custom-object system equivalent to KObjects.

Why teams migrate from Kustomer to Deskpro

  • Deployment flexibility. Deskpro offers on-premise and private cloud options. Teams in regulated industries (finance, healthcare, government) with data-sovereignty requirements need infrastructure control that Kustomer's SaaS-only model can't provide.
  • Cost structure. Kustomer's per-seat pricing at the Enterprise/Ultimate tier can exceed Deskpro's per-agent cost significantly. Deskpro publishes public cloud pricing starting at $39, $59, and $99 per agent/month for Team, Professional, and Enterprise tiers. (deskpro.com)
  • Simplified data model. Not every team needs KObjects, Klasses, and a full CRM data layer. Teams that primarily need ticket management and a knowledge base find Deskpro's simpler schema easier to maintain.
  • Ownership uncertainty. Kustomer was acquired by Meta (acquisition closed February 2022) and subsequently divested. Teams evaluating long-term platform stability sometimes prefer Deskpro's independent trajectory.

Core data model differences

Concept Kustomer Deskpro
Primary entity Customer (timeline) Ticket
Support interaction Conversation → Messages Ticket → Messages/Replies
End user Customer Person (User in UI, /people in API)
Company Company Organization
Custom data objects KObjects / Klasses No equivalent (use custom fields)
Agent User Agent
Categorization Tags, Queues Labels, Departments, Queues
Automation Business Rules, Workflows Triggers, Automations, Escalations
Knowledge Base KB Articles KB Articles (with Categories)

Migration Approaches: Which Method Fits Your Scenario

There are five viable paths. Each has sharp trade-offs.

1. Native CSV Export/Import

How it works: Export Customers, Conversations, and Messages from Kustomer's Reporting section as CSV files. Import into Deskpro via Admin > Data > Importer.

When to use it: Contact/Organization-only migrations with no conversation history requirements.

Pros:

  • No code required
  • Fast for small user lists

Cons:

  • Kustomer's CSV exports only include message previews, not full message bodies — you lose transcript history
  • Kustomer's reporting export is limited to a 30-day window per export and a maximum of 50,000 rows
  • Standard searches return data updated within the past 2 years only
  • Deskpro's CSV ticket importer only supports ticket properties and the first message — it excludes full message threads and attachments
  • No relationship preservation (Customer→Conversation→Messages chain breaks)
  • KObjects cannot be exported via CSV at all

Complexity: Low Scalability: Small datasets only (< 5,000 contacts, no conversations)

Warning

CSV is not a migration method for conversation history. Both platforms' CSV tooling drops message bodies. Use it only for bootstrapping a contact list. (help.kustomer.com)

How it works: Extract all data from Kustomer's REST API (/v1/customers, /v1/conversations/{id}/messages, /v1/companies, KObject endpoints), transform it into Deskpro's schema, and load it via Deskpro's REST API (/api/v2/tickets, /api/v2/people, /api/v2/organizations).

When to use it: Any migration that needs full conversation history, attachments, or KObject data.

Pros:

  • Full message bodies preserved
  • Attachment migration possible
  • Relationship mapping (Customer↔Company, Conversation↔Messages)
  • KObject data extractable and mappable to custom fields
  • Incremental/resumable extraction

Cons:

  • Requires engineering effort (Python, Node.js, or similar)
  • Rate limit management needed on both sides
  • Attachment re-hosting adds time and storage considerations
  • You own retries, deduplication, and mapping logic

Complexity: Medium–High Scalability: Handles enterprise datasets (100K+ conversations) with proper batching

Throughput estimate: At Kustomer's 1,000 RPM rate limit ceiling, expect roughly 400–600 tickets/hour with attachments (each ticket requires multiple API calls for messages and blob uploads), or ~1,500–2,000 tickets/hour for text-only tickets without attachments.

3. Third-Party Migration Tools

How it works: Services like Help Desk Migration offer a wizard-based migration from Kustomer to Deskpro, handling field mapping and data transfer through their platform.

When to use it: Teams without engineering bandwidth who need a standard migration without heavy customization.

Pros:

  • No code required
  • Pre-built connectors for common helpdesk platforms
  • Demo migration before full run

Cons:

  • Limited control over edge cases (KObject handling, custom transformations)
  • Per-record pricing can get expensive at scale
  • May not support all custom field types or complex relationship chains
  • You're trusting a third party with your data in transit — verify their SOC 2 or equivalent compliance if handling PII

Complexity: Low–Medium Scalability: Medium (depends on tool pricing and connector capabilities)

4. Custom ETL Pipeline

How it works: Build a dedicated extract-transform-load pipeline using tools like Python + Airflow, AWS Glue, or Azure Data Factory. Extract from Kustomer API, stage data in a warehouse or flat files, transform with SQL or code, load into Deskpro API.

When to use it: Large-scale migrations (500K+ records) with complex KObject schemas, multi-brand setups, or compliance requirements that mandate data staging and audit trails.

Pros:

  • Full control over every transformation
  • Audit trail and lineage tracking
  • Reusable for ongoing data operations
  • Can handle complex KObject→custom field transformations

Cons:

  • Highest engineering investment
  • Requires infrastructure (scheduler, staging DB, monitoring)
  • Overkill for simple migrations

Complexity: High Scalability: Enterprise-grade

Info

AWS Glue's Kustomer connector has been reported to have a hard limit of 10,000 records per filtered request — data beyond that limit may be silently dropped unless you implement date-range partitioning. Verify this against current AWS documentation before relying on it for full extraction.

5. Middleware / Integration Platforms (Zapier, Make)

How it works: Use Zapier or Make to connect Kustomer triggers to Deskpro actions, creating tickets or contacts on the fly.

When to use it: Ongoing sync of new records only — not historical migration.

Pros:

  • No code needed
  • Good for keeping two systems in sync during a transition period

Cons:

  • Cannot migrate historical data (trigger-based, not batch)
  • Per-task pricing makes bulk operations prohibitively expensive
  • No control over ordering or relationship integrity
  • Attachment handling is limited or absent

Complexity: Low Scalability: Not viable for migration; only for ongoing sync of new records

Comparison Table

Method Complexity Full History Attachments KObjects Scale Cost Model
CSV Export/Import Low Small Free
API-Based Medium–High ✅ (flattened) Enterprise Engineering time
Third-Party Tools Low–Medium ✅ (partial) ❌ (limited) Medium Per-record
Custom ETL High Enterprise Infrastructure + engineering
Middleware (Zapier/Make) Low Small Per-task

Scenario-Based Recommendations

  • Small team (< 10K conversations, no KObjects, limited budget): Third-party migration tool or lean API script
  • Mid-market (10K–100K conversations, some KObjects): API-based migration with a dedicated engineer or managed service
  • Enterprise (100K+ conversations, complex KObject schemas, compliance needs): Custom ETL pipeline or managed migration service
  • Ongoing sync during transition period: Middleware for new records + API batch for historical backfill

When a Managed Migration Service Makes Sense

When NOT to build in-house

  • Your engineering team is already committed to product work and can't absorb 3–5 weeks of migration effort
  • You have complex KObject schemas that need careful flattening into Deskpro's custom field structure
  • You're migrating attachments at scale (re-hosting to Deskpro's blob storage adds significant complexity)
  • You need zero-downtime cutover with delta sync of records created during the migration window
  • You've never worked with either platform's API before

Hidden costs of DIY migration

  • Rate limit management across two APIs with different throttling models (Kustomer's org-wide 1,000 RPM ceiling vs. Deskpro's per-key configurable limits)
  • Attachment re-hosting — downloading from Kustomer, uploading to Deskpro's /api/v2/blobs/tmp endpoint, then linking blob_auth codes to tickets
  • Relationship reconstruction — Deskpro requires People and Organizations to exist before Tickets can reference them, so load order matters
  • Edge case handling — duplicate emails, orphaned conversations, multi-channel threads, and encoding issues eat weeks of debugging time
  • Security and compliance — if migrating PII (customer emails, phone numbers, support transcripts), you need TLS encryption in transit, secure staging storage, and a data deletion plan for intermediate files. GDPR-regulated organizations must also consider lawful basis for processing during migration.

Why ClonePartner

With 1,500+ migrations completed — including complex helpdesk platform moves involving custom objects, multi-threaded conversation histories, and attachment-heavy datasets — ClonePartner has built repeatable patterns for exactly this kind of data-model translation.

We handle the Kustomer API extraction, KObject-to-custom-field mapping, attachment re-hosting, and Deskpro API loading as a managed service. We run historical syncs in the background and perform a final delta sync before cutover — your agents never stop working. Typical turnaround is 5–10 business days depending on dataset size and complexity.

For more on our approach, see How We Run Migrations at ClonePartner.

Pre-Migration Planning

Data audit checklist

Before writing any migration code, inventory what you actually have in Kustomer:

  • Customers — total count, custom attributes, linked Companies
  • Companies — count, custom fields, parent-child hierarchies
  • Conversations — total count by channel (email, chat, SMS, social), date range, status distribution
  • Messages — average messages per conversation, attachment count
  • Notes — internal notes attached to customers or conversations
  • KObjects — list all Klasses, count per Klass, custom attribute schemas
  • Tags — full tag list, frequency distribution
  • Users (Agents) — count, team assignments, roles
  • Teams — structure, queue assignments
  • Knowledge Base — article count, categories, attachments, translations
  • Business Rules & Workflows — document logic (these cannot be exported via API)
  • Saved Searches — document filter criteria for recreation in Deskpro

Identify data to exclude

Not everything deserves migration. Cut aggressively:

  • Spam/junk conversations (filter by tag or status)
  • Test/sandbox customer records
  • Conversations older than your retention policy requires — consider archiving older data to a data warehouse and only migrating the last 2 years to Deskpro
  • Unused KObject Klasses with zero or minimal records
  • Duplicate customer records (Kustomer allows duplicates; Deskpro matches on email)

Migration strategy

Strategy Best For Risk Level
Big bang Small datasets, weekend cutover window Medium — all-or-nothing
Phased Large datasets, teams that can run both platforms temporarily Low — validate each phase
Incremental Teams that need zero downtime and delta sync Low — but highest engineering effort

For most Kustomer-to-Deskpro migrations, a phased approach works best: migrate Organizations and People first, validate, then migrate Tickets with Messages, then KB articles.

Warning

No read-only access after cancellation. Kustomer does not provide a read-only access period after your subscription ends. Export all data via the API before your subscription terminates — you won't be able to retrieve it afterward. (help.kustomer.com)

Data Model and Object Mapping

This is where the migration succeeds or fails. Kustomer and Deskpro have fundamentally different data architectures.

Object-level mapping

Kustomer Object Deskpro Object Notes
Customer Person (User) Primary email is the match key. Deskpro deduplicates on email.
Company Organization Map company name + domain.
Conversation Ticket One Conversation = one Ticket. Channel metadata maps to Ticket channel.
Message Ticket Message/Reply Preserve direction (inbound/outbound), timestamp, and channel.
Note (internal) Ticket Note (internal) Agent-only visibility preserved.
KObject Custom Fields (on Ticket, Person, or Org) No 1:1 equivalent. Flatten key attributes into custom fields.
Tag Label Direct mapping.
User (Agent) Agent Map roles and team assignments.
Team Agent Team Recreate team structure.
Queue Department / Custom Queue Routing logic must be rebuilt.
KB Article KB Article Map categories, re-host inline images.

Field-level mapping

Kustomer Field Type Deskpro Field Transformation
customer.name String person.name Direct
customer.emails [0].email String person.primary_email Take first verified email
customer.phones [0].phone String person.phone Format with country code
customer.custom.* Various person.custom_fields.* Create matching custom fields in Deskpro first
company.name String organization.name Direct
conversation.name String ticket.subject Fallback to "No Subject" if null
conversation.status Enum ticket.status Map: openawaiting_agent, snoozedawaiting_agent, doneresolved
conversation.priority Enum ticket.priority Map Kustomer priority values to Deskpro's 1–10 scale
conversation.assignedUsers Array ticket.agent Map by agent email
conversation.tags Array ticket.labels Direct
conversation.createdAt ISO 8601 ticket.date_created Preserve original timestamp
message.preview String Do not use. Extract full body via API.
message.body (via API) HTML ticket_message.message Set format: html. Rewrite inline image URLs.
message.direction Enum Message type in → user reply, out → agent reply
message.attachments Array ticket_message.attachments Re-host via blob upload

Pre-create all Deskpro custom fields before loading data. Deskpro's API addresses custom fields by field IDs, and choice fields also require value IDs. Preserve every source system ID in custom fields or a sidecar mapping table — it makes delta loads and reconciliation much easier.

Handling KObjects

This is the hardest part of any Kustomer migration. KObjects are fully custom — each org defines its own Klasses (schemas) with up to 500 custom attributes per Klass.

Deskpro has no custom object system. Your options:

  1. Flatten into custom fields — Take the most important KObject attributes and create custom fields on Tickets, People, or Organizations in Deskpro. Works for 1–2 KObject types with < 10 key attributes each.
  2. Serialize into a text field or pinned note — Store the full KObject as JSON in a long-text custom field, or compile the data into an HTML table and inject it as a pinned note on the Deskpro Person profile. Preserves data but loses queryability.
  3. External database — Store KObject data in an external system (your CRM, a database) and link to Deskpro records via ID. Best for complex KObject schemas that can't be flattened.
  4. Drop it — If the KObject data isn't needed in Deskpro's operational context, archive it externally and don't migrate it.
Warning

Before mapping KObjects, audit which ones agents actually use day-to-day. In our experience, teams often have 5+ Klasses defined but only 1–2 that are actively referenced during support interactions.

Migration Architecture

Data flow: Extract → Transform → Load

Kustomer REST API (/v1/*)
    ↓ [Extract]
Staging Layer (JSON files / SQLite / PostgreSQL)
    ↓ [Transform]
Deskpro-ready payloads (JSON)
    ↓ [Load]
Deskpro REST API (/api/v2/*)

Kustomer API extraction details

  • Base URL: https://{orgname}.api.kustomerapp.com/v1/
  • Authentication: Bearer token in Authorization header
  • Pagination: Cursor-based using page [size] (max 100 per page) and page [after]
  • Rate limits: 1,000 RPM org-wide for standard API keys (all keys share this ceiling). Machine users: 100 RPM independent limit.
  • Pagination ceiling: 100 pages max per search query. For datasets exceeding 10,000 records per query, paginate using updated_at sort and windowed date-range queries.
  • Archive Search: Use Archive Search for data older than 2 years, as standard searches only return records updated within that window. (help.kustomer.com)
  • Key endpoints:
    • GET /v1/customers — extract all customers
    • GET /v1/customers/{id} — single customer with full attributes
    • GET /v1/conversations — extract conversations
    • GET /v1/conversations/{id}/messagesfull message bodies (not available in CSV exports)
    • GET /v1/companies — extract companies
    • GET /v1/klasses/{klassName}/kobjects — extract KObjects by Klass

Deskpro API loading details

  • Base URL: https://{helpdesk}.deskpro.com/api/v2/
  • Authentication: API key via Authorization: key {id}:{code} header. Use a superuser API key to create records as different agents.
  • Rate limits: Configurable per API key (hourly and daily limits). Set generously for migration, then tighten afterward.
  • Error responses: Deskpro returns standard HTTP status codes — 400 for malformed requests (with a JSON body containing field-level error details), 401 for authentication failures, 404 for invalid endpoints or IDs, 429 for rate limit exceeded (with Retry-After header), and 500 for server errors. Log full response bodies for failed requests.
  • Pagination (for validation): Deskpro uses page and count parameters (e.g., GET /api/v2/tickets?page=2&count=50). The response includes pagination.total for record counts.
  • Key endpoints:
    • POST /api/v2/people — create users
    • POST /api/v2/organizations — create organizations
    • POST /api/v2/tickets — create tickets with initial message
    • POST /api/v2/tickets/{id}/messages — add subsequent messages/replies
    • POST /api/v2/blobs/tmp — upload attachments (returns blob_auth code)
    • POST /api/v2/articles — create KB articles
    • DELETE /api/v2/tickets/{id} — delete individual tickets (for rollback)
    • POST /api/v2/tickets/actions/mass_delete — bulk delete tickets matching criteria (for rollback)
Warning

On-premise Deskpro: If loading into a self-hosted Deskpro instance, you may need VPN access or IP whitelisting for your migration servers. On-premise instances may also run different Deskpro versions with API behavior differences — verify API compatibility against your installed version before starting. Plan this with your infrastructure team.

Attachment handling

Deskpro uses a two-step attachment process:

  1. Upload the file to POST /api/v2/blobs/tmp as form-data
  2. Receive a blob_auth code in the response
  3. Include the blob_auth code when creating the ticket or message

Every attachment requires two API calls on the Deskpro side, plus a download from Kustomer. For attachment-heavy migrations, this is the bottleneck — expect throughput to drop to ~400–600 tickets/hour when tickets average 2+ attachments each.

Kustomer stores attachment URLs as signed URLs that may expire. Download all attachments during extraction and store locally before beginning the Deskpro upload phase. Don't start uploading to Deskpro while you're still extracting from Kustomer — a signed URL that worked at extraction time can 404 by the time you circle back to it.

Channel-specific considerations

Different Kustomer channels have structural differences that affect migration:

  • Email conversations: Most straightforward — map subject, HTML body, headers, and attachments directly to Deskpro email tickets.
  • Chat transcripts: Kustomer stores chat as a series of short messages with rapid timestamps. In Deskpro, these become sequential ticket messages. Consider concatenating rapid-fire chat messages (< 60 seconds apart from the same sender) into single messages to reduce noise.
  • SMS messages: Typically plain-text, short messages. Map to Deskpro ticket messages with format: text. Phone number becomes the Person identifier if no email exists.
  • Social media (Facebook, Twitter/X, Instagram): Kustomer stores social handles and platform-specific metadata. Deskpro may not preserve all platform metadata — map the message content and store social handle as a custom field on the Person record.

Step-by-Step Migration Process

Step 1: Extract data from Kustomer

import requests
import time
import json
 
KUSTOMER_BASE = "https://yourorg.api.kustomerapp.com/v1"
KUSTOMER_TOKEN = "your-api-key"
HEADERS = {"Authorization": f"Bearer {KUSTOMER_TOKEN}"}
 
def extract_paginated(endpoint, params=None):
    """Extract all records from a paginated Kustomer endpoint."""
    all_records = []
    url = f"{KUSTOMER_BASE}{endpoint}"
    page_params = {"page[size]": 100}
    if params:
        page_params.update(params)
    
    page_count = 0
    while url and page_count < 100:  # 100-page ceiling
        resp = requests.get(url, headers=HEADERS, params=page_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()
        all_records.extend(data.get("data", []))
        
        # Cursor-based pagination
        links = data.get("links", {})
        url = links.get("next")
        page_params = {}  # Next URL includes params
        page_count += 1
        time.sleep(0.07)  # Respect rate limits (~850 RPM)
    
    return all_records
 
# Extract customers
customers = extract_paginated("/customers")
 
# Extract conversations
conversations = extract_paginated("/conversations")
 
# Extract full messages for each conversation
for conv in conversations:
    conv_id = conv["id"]
    conv["messages"] = extract_paginated(f"/conversations/{conv_id}/messages")

For datasets exceeding the 100-page ceiling (10,000+ records per query), implement windowed queries — sort by updated_at and break your extraction into date-range slices:

from datetime import datetime, timedelta
 
def extract_windowed(endpoint, start_date, end_date, window_days=7):
    """Extract records in date-range windows to bypass 100-page ceiling."""
    all_records = []
    current = start_date
    while current < end_date:
        window_end = min(current + timedelta(days=window_days), end_date)
        params = {
            "updatedAt_gte": current.isoformat() + "Z",
            "updatedAt_lt": window_end.isoformat() + "Z",
            "sort": "updatedAt"
        }
        records = extract_paginated(endpoint, params)
        all_records.extend(records)
        current = window_end
    return all_records

Step 2: Transform data

def transform_customer_to_person(kustomer_customer):
    """Map Kustomer Customer to Deskpro Person."""
    attrs = kustomer_customer.get("attributes", {})
    emails = attrs.get("emails", [])
    phones = attrs.get("phones", [])
    
    return {
        "name": attrs.get("displayName") or attrs.get("name", "Unknown"),
        "primary_email": emails[0]["email"] if emails else None,
        "phone": phones[0].get("phone") if phones else None,
        "custom_fields": transform_custom_attrs(attrs.get("custom", {})),
        "_kustomer_id": kustomer_customer["id"]  # Keep for ID mapping
    }
 
def transform_conversation_to_ticket(conversation, id_map):
    """Map Kustomer Conversation to Deskpro Ticket."""
    attrs = conversation.get("attributes", {})
    status_map = {
        "open": "awaiting_agent",
        "snoozed": "awaiting_agent",
        "done": "resolved",
        "closed": "resolved"
    }
    
    messages = conversation.get("messages", [])
    first_message = messages[0] if messages else {}
    
    return {
        "subject": attrs.get("name", "No Subject"),
        "person": id_map.get(attrs.get("customer")),
        "status": status_map.get(attrs.get("status"), "awaiting_agent"),
        "message": {
            "message": first_message.get("attributes", {}).get("body", ""),
            "format": "html"
        },
        "labels": attrs.get("tags", []),
        "date_created": attrs.get("createdAt")  # Preserve original timestamp
    }

Step 3: Load into Deskpro

DESKPRO_BASE = "https://yourhelpdesk.deskpro.com/api/v2"
DESKPRO_KEY = "1:YOUR_API_KEY"
DP_HEADERS = {
    "Authorization": f"key {DESKPRO_KEY}",
    "Content-Type": "application/json"
}
 
def create_deskpro_record(endpoint, payload):
    """Create a record in Deskpro with retry logic."""
    for attempt in range(3):
        resp = requests.post(
            f"{DESKPRO_BASE}{endpoint}",
            headers=DP_HEADERS,
            json=payload
        )
        if resp.status_code == 201:
            return resp.json().get("data", {})
        if resp.status_code == 429:
            retry_after = int(resp.headers.get("Retry-After", 30))
            time.sleep(retry_after)
            continue
        if resp.status_code >= 500:
            time.sleep(2 ** attempt)  # Exponential backoff for server errors
            continue
        # Log 4xx errors with full response for debugging
        if resp.status_code >= 400:
            print(f"Error {resp.status_code} on {endpoint}: {resp.text}")
        resp.raise_for_status()
    raise Exception(f"Failed after 3 retries: {endpoint}")
 
# Load order matters: Organizations → People → Tickets → Messages
id_map = {}  # kustomer_id → deskpro_id
 
for org in transformed_orgs:
    result = create_deskpro_record("/organizations", org)
    id_map[org["_kustomer_id"]] = result["id"]
 
for person in transformed_people:
    result = create_deskpro_record("/people", person)
    id_map[person["_kustomer_id"]] = result["id"]
 
for ticket in transformed_tickets:
    result = create_deskpro_record("/tickets", ticket)
    ticket_id = result["id"]
    # Load subsequent messages
    for msg in ticket["_remaining_messages"]:
        create_deskpro_record(f"/tickets/{ticket_id}/messages", msg)

A production loader needs exponential backoff, checkpointing (save progress to disk/DB after each batch so you can resume after failures), idempotent re-runs (check if a record exists before creating), and a dead-letter queue for failed records. The code above is a structural reference — production scripts should also handle network timeouts, partial failures, and state resumption.

Step 4: Validate

After loading, run count comparisons and field-level spot checks. See the Validation section below for the full process.

Edge Cases and Challenges

Duplicate records

Kustomer allows multiple Customer records with the same email address. Deskpro deduplicates on primary_email — if you try to create a Person with an email that already exists, the API returns the existing record (HTTP 200 instead of 201). Your migration script must handle this by checking for existing People before creating and merging conversation history onto the correct Person.

Multi-channel conversation threads

A single Kustomer Conversation can span email, chat, SMS, and social channels within one timeline. Deskpro Tickets have a primary channel. Pick the originating channel for the Ticket and add subsequent cross-channel messages as replies — the content is preserved even if the channel metadata is simplified.

KObject relationship chains

In Kustomer, KObjects can relate to Customers, Conversations, and other KObjects. Deskpro has no object-relationship layer. If you flatten KObjects into custom fields, the relationships between KObjects are lost. Document these relationships externally (e.g., in a reference table or your data warehouse) if they're important for reporting.

Attachment migration at scale

Kustomer stores attachment URLs as signed URLs that may expire. Download all attachments during extraction and store locally before beginning the Deskpro upload phase. Deskpro's two-step blob upload process means attachment-heavy tickets (10+ files) can take significantly longer per ticket. Budget 3–5x the time per ticket compared to text-only tickets.

Inline images

Images pasted directly into Kustomer emails are stored as base64 or secure links. You must parse the HTML, download the image, upload it to Deskpro as a blob, and rewrite the <img> tag in the message body with the new Deskpro URL. A regex-based approach to find <img src="..."> tags is fragile — use an HTML parser like BeautifulSoup (Python) or cheerio (Node.js).

Agent attribution

If an agent has left your company, their account won't exist in Deskpro. You must either create placeholder agent profiles in Deskpro for historical attribution or map their actions to a generic "System Account." Without this, historical ticket assignments and agent replies lose their author context.

Message ordering

Kustomer Messages have createdAt timestamps, but Deskpro may reorder messages during import. Set date_created explicitly on each message and verify chronological order after loading.

Conversation exports missing message bodies

This bears repeating: Kustomer's CSV/reporting exports only include a preview field with truncated message text. You must use the API endpoint GET /v1/conversations/{id}/messages to get full message bodies. This is the single most common data-loss mistake in Kustomer migrations.

For a detailed source-side export walkthrough, see How to Export Data from Kustomer: Methods, API Limits & Data Portability.

Limitations and Constraints

Be honest with your stakeholders about what will change post-migration.

What Deskpro doesn't have vs. Kustomer

  • No custom objects. Deskpro does not have an equivalent to KObjects. All custom data must be expressed as custom fields on Tickets, People, or Organizations.
  • No customer timeline. Kustomer's unified timeline view — showing conversations, KObjects, and events in one chronological feed — has no Deskpro equivalent. Conversation history is ticket-scoped.
  • Simpler status model. Kustomer's conversation statuses and custom status fields may not map cleanly to Deskpro's fixed status set (awaiting_agent, awaiting_user, resolved, closed, hidden).
  • Ticket-centric architecture. Deskpro organizes around Tickets, not Customers. Agents see ticket queues, not customer profiles. This is a workflow shift, not just a data shift.
  • No native KObject triggers. Highly customized Kustomer workflows relying on custom object triggers must be rebuilt using Deskpro's Triggers and Webhooks.

API rate limits

Platform Limit Scope
Kustomer 1,000 RPM (standard API keys) Org-wide, shared across all keys
Kustomer 100 RPM (machine users) Per machine user
Kustomer 100 pages max per search query Per query
Deskpro Configurable per API key Per key (hourly/daily)

If you have 500,000 tickets averaging 5 messages each, that's 2.5M+ message API calls on the Kustomer side alone. At 1,000 RPM, pure extraction takes ~42 hours of continuous API calls — before any transformation or loading. The migration script cannot run at maximum concurrency. You must batch requests and expect the full data load to take several days.

Potential data loss scenarios

  • Using CSV export instead of API (message bodies truncated)
  • Exceeding Kustomer's 100-page pagination limit without implementing windowed queries (records silently skipped)
  • KObject data that can't be flattened into Deskpro's custom field types (e.g., nested arrays, multi-level object hierarchies)
  • Attachments with expired signed URLs if not downloaded promptly during extraction
  • Business Rules, Workflows, and Saved Searches that are not documented before decommissioning Kustomer (there is no export option for these)
  • Custom conversation statuses that don't map to Deskpro's fixed status set — data isn't lost but semantic meaning may change

Validation and Testing

Do not rely on spot-checking. Implement a programmatic validation process.

Record count comparison

Object Kustomer Count (Source) Deskpro Count (Target) Match?
Customers / People GET /v1/customers count GET /api/v2/people?count=1pagination.total
Companies / Organizations GET /v1/companies count GET /api/v2/organizations?count=1pagination.total
Conversations / Tickets GET /v1/conversations count GET /api/v2/tickets?count=1pagination.total
Messages Sum of all messages Sum of all ticket messages
KB Articles GET /v1/kb/articles count GET /api/v2/articles?count=1pagination.total

Note: Deskpro People count may differ from Kustomer Customer count due to email-based deduplication. Document expected deltas.

Field-level validation

For a random sample of 50–100 records per object type:

  1. Compare customer name, email, phone in both systems
  2. Verify conversation/ticket subject, status, assignee, tags/labels
  3. Open 10 tickets in Deskpro and read through the full message thread — confirm all messages are present and in correct chronological order
  4. Check custom field values against source data
  5. Verify attachments are downloadable in Deskpro
  6. Confirm that date_created timestamps on tickets match Kustomer's createdAt — do not accept all tickets showing the migration date

UAT process

  1. Have 2–3 support agents work in Deskpro for 48 hours using migrated data
  2. Agents should search for known customers and verify history is intact
  3. Test replying to migrated tickets (confirm no automation mis-fires)
  4. Validate that Organization→Person relationships are correct
  5. Check that KB articles render correctly with images and formatting

Rollback planning

Deskpro supports import undo for CSV imports, but API-created records must be deleted via the API. Before loading:

  • Tag all migrated records with a label like kustomer-migration-batch-1
  • This allows bulk deletion via POST /api/v2/tickets/actions/mass_delete with a label filter if a rollback is needed
  • For People and Organizations, use DELETE /api/v2/people/{id} and DELETE /api/v2/organizations/{id} — there is no bulk delete for these object types, so script it
  • Keep your staging data intact until validation is complete

For a comprehensive post-migration test suite, see Post-Migration QA: 20 Tests to Run After Your Help Desk Data Migration.

Post-Migration Tasks

Rebuild automations

Kustomer's Business Rules, Workflows, and Saved Searches cannot be exported. You must manually recreate them as:

  • Deskpro Triggers — fire on ticket creation or update (equivalent to Kustomer Business Rules)
  • Deskpro Automations — time-based rules (equivalent to Kustomer time-based Workflows)
  • Deskpro Escalations — SLA-based routing
  • Deskpro Ticket Filters / Queues — equivalent to Kustomer Saved Searches

Document every Kustomer Business Rule before decommissioning. There is no export option — screenshot or manually record the conditions and actions.

User training

The shift from Kustomer's customer-timeline view to Deskpro's ticket-queue view is the biggest workflow change agents will experience. Plan training around:

  • Finding a customer's full history (People → Tickets tab instead of a unified timeline)
  • Using Departments instead of Queues for routing
  • Custom field locations on the ticket panel
  • New keyboard shortcuts and agent interface navigation

Monitoring

For the first 2 weeks after go-live:

  • Monitor for orphaned tickets (tickets without a linked Person)
  • Watch for custom field values that didn't map correctly
  • Check that email routing is working (Deskpro email accounts must be configured independently)
  • Verify that no Kustomer automations are still firing (disable webhooks and integrations in Kustomer)
  • Keep an eye on Deskpro's API logs for the first 48 hours to ensure integrations (Jira, Salesforce, etc.) are syncing correctly to the new ticket IDs

Security and Compliance During Migration

For teams in regulated industries — the primary driver for choosing Deskpro's on-premise deployment — migration itself is a data-handling event that requires compliance attention:

  • Encryption in transit: Ensure all API calls to both Kustomer and Deskpro use TLS 1.2+ (both platforms enforce HTTPS by default).
  • Staging data security: If you stage extracted data locally or in a cloud warehouse, encrypt at rest. Kustomer data contains PII (names, emails, phone numbers, support transcripts).
  • Data residency: For GDPR-regulated organizations, confirm that your staging infrastructure and any third-party migration tools process data within compliant jurisdictions.
  • Post-migration cleanup: Delete all staging files, local attachment copies, and intermediate databases after validation is complete. Document the deletion for audit purposes.
  • Access control: Restrict API keys used during migration. Rotate Kustomer API keys after the migration is complete; tighten Deskpro API key rate limits and permissions once loading is done.
  • Audit trail: Log every record created in Deskpro with its source Kustomer ID. This provides traceability for compliance reviews.

Best Practices

  1. Back up everything before migration. Export full Kustomer data via API to local storage. This is your safety net.
  2. Never migrate directly to production. Always run a full migration to a Deskpro sandbox environment first. Validate before touching production.
  3. Validate incrementally. Don't wait until the end. Check counts and sample records after each object type loads.
  4. Disable automations in Deskpro during import. Triggers that fire on ticket creation will spam agents and customers with notifications if left active during bulk loading.
  5. Preserve original timestamps. Set date_created on tickets and messages to match Kustomer's createdAt. Without this, all migrated tickets appear as "just created."
  6. Preserve legacy IDs. Store the Kustomer_Conversation_ID in a custom field on the Deskpro Ticket. This is mandatory for troubleshooting, delta loads, and post-migration API integrations.
  7. Freeze Kustomer configurations. Implement a change freeze in Kustomer two weeks before the migration. No new custom fields, no new tags.
  8. Plan the cutover window. Pick a low-traffic period. Run a delta sync after the initial migration to catch records created during the migration window.
  9. Keep Kustomer active (read-only) for 30 days post-migration. Agents may need to reference historical data that didn't migrate or wasn't needed.
  10. Automate repetitive tasks. Write scripts for extraction, transformation, and loading. Manual copy-paste does not scale and introduces errors.

Choosing Your Path

Migrating from Kustomer to Deskpro is a data-model translation problem, not a simple import. If you are moving current contacts and a light queue, CSV may be enough. If you are moving support history agents will actually search, use the API. If you are moving KObjects, attachments, multiple brands, or years of history, run this as an ETL program with sample, full, and delta phases.

The practical line between a simple import and a real migration is whether your agents need working context — not just rows — on the other side.

Frequently Asked Questions

Can I migrate full conversation history from Kustomer to Deskpro?
Yes, but only via the Kustomer REST API. CSV exports only include message previews, not full message bodies. You must use the GET /v1/conversations/{id}/messages endpoint to extract complete message content, then load it into Deskpro via the Tickets and Messages API.
How do I handle Kustomer KObjects in Deskpro?
Deskpro has no custom object system equivalent to KObjects. Your options are: flatten key KObject attributes into custom fields on Tickets, People, or Organizations; serialize the full KObject as JSON into a text field or pinned note; store KObject data in an external database; or archive and exclude it from migration.
What are the API rate limits for a Kustomer to Deskpro migration?
Kustomer enforces 1,000 requests per minute org-wide (shared across all API keys) with a 100-page maximum per search query. Machine users have an independent 100 RPM limit. Deskpro's rate limits are configurable per API key with hourly and daily thresholds. Plan extraction and loading as separate, independently throttled processes.
How long does a Kustomer to Deskpro migration take?
Expect 2–3 weeks for under 50K conversations with no KObjects, and 3–5 weeks for larger datasets with complex KObject schemas and attachments. A managed migration service can typically compress this to 5–10 business days.
Does Deskpro have a native Kustomer import tool?
No. Deskpro offers a CSV importer for Users, Organizations, and Tickets, but ticket CSV imports only support ticket properties and the first message — not full conversation threads or attachments. For a complete migration, you need the API or a third-party migration tool.

More from our Blog

Post-Migration QA: 20 Tests to Run After Your Help Desk Data Migration
Help Desk

Post-Migration QA: 20 Tests to Run After Your Help Desk Data Migration

Ensure your help desk migration is a success with this comprehensive 20-point post-migration QA checklist. This expert guide details the 20 essential tests needed to validate your data integrity, system functionality, user-friendliness, and performance . Learn exactly how to check everything from ticket data, attachments, and knowledge base articles to critical workflows, automations, and integrations before you go live. This process is your final line of defense against lost tickets, broken workflows, and unhappy customers.

Raaj Raaj · · 8 min read