Kustomer to Gorgias Migration: A Technical Guide
Technical guide to migrating from Kustomer to Gorgias: API constraints, data model mapping, KObject flattening, rate limits, and step-by-step process.
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
Migrating from Kustomer to Gorgias is a data model downshift. Kustomer stores every customer interaction as a continuous, chronological timeline — emails, chats, notes, KObjects, and custom events all rendered in a single stream per customer record. Gorgias is a ticket-centric e-commerce helpdesk: each conversation is a discrete ticket with its own message thread, tags, and status.
There is no native migration path between these platforms. Kustomer has no built-in Gorgias export, and Gorgias's native importer supports Zendesk but does not support Kustomer. (docs.gorgias.com) The practical route is Kustomer API extraction → data transformation → Gorgias API loading.
This guide covers the exact object mapping, API constraints on both sides, extraction strategies, edge cases, and the failure modes that derail teams mid-migration. All API-specific claims reflect documentation as of June 2025 — verify rate limits and field constraints against current platform docs before implementation. If you're evaluating the technical feasibility of moving from Kustomer's CRM-grade platform to Gorgias's Shopify-native helpdesk, start here.
For context on helpdesk data scoping, see the Help Desk Data Migration Playbook. For Kustomer export methods and limits, see How to Export Data from Kustomer. For post-migration validation, review our Help Desk Data Migration QA Checklist.
Why Companies Move from Kustomer to Gorgias
The migration usually isn't about dissatisfaction — it's about fit. The most common drivers:
- Shopify-native integration. Gorgias surfaces order data, refund actions, and customer lifetime value inside every ticket without custom API work. Kustomer connects to Shopify, but key actions often require leaving the helpdesk or additional configuration.
- Pricing model shift. Kustomer uses per-seat pricing with an 8-seat minimum billed annually — check kustomer.com/pricing for current rates, as tiers have changed over time. Gorgias uses ticket-based pricing starting at $10/month for the Starter plan (50 tickets/month), making it significantly cheaper for smaller DTC teams.
- Simpler operational model. Gorgias is purpose-built for e-commerce support. Teams that don't need Kustomer's CRM-grade data model, custom objects, and enterprise routing find Gorgias faster to operate and maintain.
- Agency use cases. Outsourced support agencies often standardize on Gorgias due to its multi-brand capabilities and predictable per-ticket pricing.
Moving from Kustomer to Gorgias means accepting a simpler data model. Gorgias has no custom objects, no Company hierarchy, a maximum of 25 active ticket fields, and only 4 active customer fields. If your Kustomer instance relies heavily on KObjects or complex Company→Customer relationships, those structures must be flattened or discarded.
Core Data Model Differences
Understanding the architectural gap is the single most important step before planning your migration.
| Concept | Kustomer | Gorgias |
|---|---|---|
| Architecture | Customer-centric timeline | Ticket-centric inbox |
| Primary record | Customer (all events roll up here) | Ticket (standalone per conversation) |
| Conversations | Hang off Customer record as timeline events | Standalone Tickets with message threads |
| Companies/Accounts | First-class Company object linked to Customers | No company/organization object |
| Custom objects | KObjects via Klasses (up to 500 attributes per Klass) | Not supported — use tags or ticket fields |
| Custom fields | Unlimited via KObject schema | 25 active ticket fields, 4 active customer fields |
| Ticket statuses | Open, Snoozed, Done (plus custom) | Open, Closed (API level) |
| Notes | Internal notes on timeline | Internal notes on tickets |
| Knowledge base | Built-in KB with categories and articles | Built-in Help Center |
| Automations | Workflows + Business Rules | Rules (max 70) |
A Kustomer customer with 15 conversations across email, chat, and phone becomes 15 separate tickets in Gorgias — each with its own message thread but linked to the same customer profile. The unified timeline is gone.
Migration Approaches
There are five viable methods for moving data from Kustomer to Gorgias. Each has different trade-offs around completeness, complexity, and cost.
1. Native CSV Export + API Import
How it works: Export CSV files from Kustomer's reporting dashboard or saved search exports. Transform the CSVs to match Gorgias's expected schema. Import customers via POST /api/customers and tickets via POST /api/tickets.
When to use: Small datasets under 5,000 conversations with simple field schemas and no attachment requirements.
Pros: Low technical barrier, quick for simple datasets.
Cons: Kustomer CSV exports are capped at 50,000 rows and limited to 30-day reporting windows. Message bodies are not included in conversation exports — you get metadata only. No attachment export via CSV. Gorgias does not document a general CSV importer for Kustomer ticket history. (help.kustomer.com)
Scalability: Small only. Breaks above ~10K records due to export limitations.
Complexity: Low to Medium.
2. Full API-to-API Migration
How it works: Build a custom script that extracts data from Kustomer's REST API (/v1/customers, /v1/conversations, /v1/conversations/{id}/messages) and loads it into Gorgias via the REST API (POST /api/customers, POST /api/tickets, POST /api/tickets/{id}/messages). Use Kustomer's archive search endpoint (POST /v1/customers/archive-search) for records older than the standard two-year search window, since the standard search endpoint (POST /v1/customers/search) only returns records updated within the past two years and caps at 100 pages per query. (help.kustomer.com)
When to use: Medium to large datasets, teams that need full message bodies and attachments, or anyone requiring conversation threading fidelity.
Pros: Full access to all Kustomer data including message bodies, notes, and KObjects. Preserves timestamps, channels, and relationships. Can be automated and made idempotent.
Cons: Requires engineering effort (Python/Node.js). Must handle rate limits on both platforms. Kustomer Search API has a 100-page maximum per query — large datasets need date-range partitioning.
Scalability: Enterprise-grade with proper batching and pagination.
Complexity: High.
3. Third-Party Migration Tools
How it works: Platforms like Help Desk Migration offer a wizard-based interface that connects to both Kustomer and Gorgias, maps fields, runs a demo migration, then executes the full transfer. (docs.gorgias.com)
When to use: Teams without engineering bandwidth who need a turnkey solution and accept the tool's mapping constraints.
Pros: No-code setup, demo migration before committing, handles basic ticket, customer, and tag migration.
Cons: Limited customization for complex field mappings. KObject data may not transfer. Tickets with more than 30–40 comments may not fully migrate. Inline images migrate only as attachments, not embedded.
Scalability: Moderate — depends on the tool's processing capacity.
Complexity: Low.
4. Custom ETL Pipeline
How it works: Build a full extract-transform-load pipeline using a data orchestration tool (Airflow, Prefect, or a simple script runner). Extract from Kustomer API → store in intermediate format (JSON/database) → transform and validate → load into Gorgias API. Kustomer recommends choosing between API, exports, and bulk operations based on workload shape rather than treating one endpoint as a universal export tool. (help.kustomer.com)
When to use: Enterprise migrations with complex KObject schemas, multi-brand setups, or compliance requirements that demand auditability.
Pros: Full control over data transformation logic, audit trail and logging at every stage, reusable for delta syncs.
Cons: Highest engineering investment, requires dedicated development and QA time.
Scalability: Enterprise-grade.
Complexity: High.
5. Middleware Platforms (Zapier, Make)
How it works: Use Zapier or Make to create automated workflows triggered by Kustomer events that create records in Gorgias. Kustomer's Zapier integration supports triggers and actions but does not support two-way sync. (help.kustomer.com)
When to use: Ongoing lightweight sync of new records during a phased cutover. Not for historical migration.
Pros: No-code, quick to set up, good for real-time forwarding of new conversations.
Cons: Not designed for bulk historical data migration. Rate limits and execution timeouts make large transfers unreliable. No batch processing — records move one at a time. Expensive per-task pricing for bulk operations.
Scalability: Small volume only (~100s of records per day).
Complexity: Low.
Approach Comparison
| Method | Best For | Message Bodies | Attachments | KObjects | Scale | Complexity |
|---|---|---|---|---|---|---|
| CSV Export + API Import | <5K conversations | ❌ | ❌ | ❌ | Small | Low/Med |
| API-to-API | 5K–500K+ conversations | ✅ | ✅ | Flatten to tags | Enterprise | High |
| Third-Party Tool | <50K, simple schemas | ✅ | Partial | ❌ | Moderate | Low |
| Custom ETL Pipeline | Enterprise, complex schemas | ✅ | ✅ | Flatten with logic | Enterprise | High |
| Middleware (Zapier/Make) | Ongoing sync, <100/day | ✅ | ❌ | ❌ | Small | Low |
Recommendations by scenario:
- Small DTC team (<5K tickets, no KObjects): Third-party tool or managed service.
- Mid-market e-commerce (5K–100K tickets): API-to-API with rate limit handling, or managed service.
- Enterprise (100K+ tickets, KObjects, attachments): Custom ETL or managed migration service.
- Phased cutover: API or ETL for the historical backfill, middleware only for narrow delta sync.
Pre-Migration Planning Checklist
Before writing any code or connecting any tool, audit your Kustomer instance.
Data Audit
- Customers: Total count, fields used, email/phone channels per customer
- Companies: Count and whether Company→Customer relationships are business-critical
- Conversations: Total count by status (Open, Snoozed, Done), average messages per conversation
- Messages: Total volume, channels used (email, chat, SMS, social, voice)
- KObjects: Custom object types (Klasses), record counts per type, field schemas
- Linked conversations: Cross-references between conversations
- Tags: Tag taxonomy — which tags are actively used vs. legacy
- Knowledge Base: Article count, categories, translations
- Attachments: Volume and average size per ticket
- Users/Teams: Agent count, team structure, role assignments
- Workflows and Business Rules: Document conditions and actions manually — these don't export
- Saved Searches and Custom Klass schema definitions: Also not exportable via CSV (help.kustomer.com)
Identify What to Leave Behind
Not everything needs to move. Common data to skip:
- Conversations older than 2–3 years with no business value
- Duplicate or merged customer records
- Test or spam conversations
- KObjects that map to Shopify data (Gorgias pulls this natively)
- Unused custom Klasses
- Sales-style objects (leads, opportunities) modeled in Kustomer — these don't have a first-class destination in Gorgias
GDPR and Data Residency Considerations
If you serve EU customers, evaluate data residency before extraction. Kustomer may host data in specific AWS regions (US, EU). Gorgias stores data primarily in US-based infrastructure. Transferring customer PII across regions may require updated Data Processing Agreements (DPAs), Standard Contractual Clauses (SCCs), or explicit consent depending on your GDPR compliance framework. Document the data flow path (Kustomer region → intermediate storage location → Gorgias region) and confirm it satisfies your legal obligations before starting extraction.
Migration Strategy
| Strategy | When to Use | Risk Level |
|---|---|---|
| Big bang | Small datasets, short cutover window acceptable | Medium |
| Phased | Multiple brands or regions; migrate one at a time | Low |
| Incremental (delta) | Zero-downtime requirement; import history first, then sync new records | Low |
For most e-commerce teams, incremental is the safest approach: load all historical data while both systems are live, cut email and chat routing to Gorgias during a low-volume window, then run a delta sync to catch records created during the overlap.
Data Model and Object Mapping
This is where migrations succeed or fail. Kustomer's richer data model must be intentionally translated into Gorgias's simpler structure.
Core Object Mapping
| Kustomer Object | Gorgias Equivalent | Notes |
|---|---|---|
| Customer | Customer | Map email, name, phone. Preserve source IDs in external_id for validation. (developers.gorgias.com) |
| Company | ❌ (No equivalent) | Flatten to a customer tag (e.g., company:acme-corp) or use one of Gorgias's 4 customer custom fields. |
| Conversation | Ticket | Each conversation becomes one ticket. |
| Message | Ticket Message | Map body, direction, channel, sentAt. |
| Note | Internal Note | Preserve as internal messages on the ticket (from_agent: true, public: false). |
| KObject (Order, Shipment, etc.) | ❌ (No equivalent) | Flatten to tags, ticket fields, or rely on Gorgias's native Shopify integration. |
| Tag | Tag | Direct 1:1 mapping via tag name. |
| Knowledge Base Article | Help Center Article | Separate migration via Gorgias Help Center API (POST /api/articles). Requires mapping Kustomer KB categories to Gorgias collections and converting article bodies to Gorgias's expected HTML format. |
| User (Agent) | User | Create agents in Gorgias first, then map by email. |
| Team | Team | Create teams manually, then assign agents. |
| Workflow / Business Rule | Rule | Must be manually rebuilt — no export/import path. |
| Linked Conversation | ❌ (No equivalent) | Preserve cross-links in internal notes or an external reference table. (help.kustomer.com) |
Field-Level Mapping
| Kustomer Field | Gorgias Field | Transformation |
|---|---|---|
customer.name |
customer.name |
Direct |
customer.emails [].email |
customer.email |
Take primary email |
customer.phones [].phone |
customer.channels [].address |
Map to phone channel |
conversation.name |
ticket.subject |
Direct (max 998 characters) (developers.gorgias.com) |
conversation.status |
ticket.status |
done → closed, open/snoozed → open |
conversation.tags [] |
ticket.tags [] |
Map by tag name |
conversation.assignedTeams |
ticket.assignee_team |
Map team by name after creating in Gorgias |
conversation.assignedUsers |
ticket.assignee_user |
Map user by email |
conversation.createdAt |
ticket.created_datetime |
ISO 8601 |
message.body |
message.body_html |
Sanitize HTML, replace attachment URLs (1MB body limit) |
message.sentAt |
message.sent_datetime |
Critical — must be set to prevent live email sends |
message.direction |
message.from_agent |
in → false, out → true |
| Custom KObject fields | Ticket tags or ticket fields | Flatten: e.g., order.status: shipped → tag order-shipped |
The sent_datetime trap: If you omit sent_datetime when creating messages via the Gorgias API, Gorgias treats the message as new and will attempt to send it to the customer as a live email. Every historical message imported without this field becomes an outbound email to your customer. Always set sent_datetime to the original message timestamp. This is the single highest-risk failure mode in the entire migration.
Handling Companies and KObjects
Gorgias has no Company object and no custom object framework. This is the largest structural loss in this migration.
Companies: If your Kustomer instance uses Company→Customer relationships for B2B workflows, you have two options:
- Flatten the company name into a customer tag (e.g.,
company:acme-corp) - Use one of Gorgias's 4 customer custom fields to store the company name
KObjects: If you track orders, subscriptions, or shipments as KObjects in Kustomer, evaluate whether Gorgias's native Shopify integration already provides this data. For Shopify-based teams, Gorgias pulls order history, tracking, and customer LTV directly — making most order-related KObjects redundant. Non-Shopify KObject data must be flattened into tags, ticket fields, or formatted internal notes appended to the ticket.
Field type mismatches: Kustomer allows complex multi-select picklists. Gorgias relies heavily on tags for categorization. Script a transformation that converts Kustomer picklist values into Gorgias tags (e.g., Category: Returns → tag returns). Document the mapping table explicitly — agents will need it during the transition.
Migration Architecture
The recommended architecture for any non-trivial migration follows a three-stage ETL pipeline:
[Kustomer REST API] → Extract → [Intermediate Storage (JSON/S3/DB)] → Transform → [Gorgias REST API] → Load
Stage 1: Extract from Kustomer
Endpoints:
GET /v1/customers— paginated, cursor-based (page [size]=100,page [after])POST /v1/customers/search— for filtered extraction (max 100 pages per query, max 10,000 records per query)POST /v1/customers/archive-search— for records last updated more than two years ago; same pagination limits as standard search but queries the archive indexGET /v1/conversations— paginatedGET /v1/conversations/{id}/messages— per-conversation message retrievalGET /v1/klasses/{name}— KObject schema and data extraction
Rate limits (Kustomer, as of June 2025):
- 1,000 requests/minute on Enterprise, 2,000 on Ultimate (org-wide, shared across all API keys)
- Object-level: 50 updates per 10 minutes per object
- Search API: max 100 pages per query — use date-range partitioning to work around this
- Standard search only returns records updated within the past two years — use archive search for older data
Kustomer's conversation export does not include full message bodies. You must call /v1/conversations/{id}/messages for each conversation to get the actual content. For 50,000 conversations, that's 50,000+ additional API calls — plan for this in your rate limit budget.
Stage 2: Transform
- Flatten KObjects into tags or ticket field values
- Map Kustomer statuses to Gorgias's
open/closed - Convert message direction (
in/out) tofrom_agentboolean - Ensure all message timestamps are in ISO 8601 with
sent_datetimeset - Deduplicate customers by email address
- Download and re-host inline images that reference Kustomer CDN URLs (these expire after Kustomer account cancellation)
- Strip proprietary HTML wrappers from Kustomer messages
- Truncate ticket subjects to 998 characters
- Validate message body size against Gorgias's 1MB limit — truncate or split oversized bodies
Stage 3: Load into Gorgias
Endpoints:
POST /api/customers— create or update customer recordsPOST /api/tickets— create tickets with initial message (accepts 1–500 messages in the initial payload) (developers.gorgias.com)POST /api/tickets/{id}/messages— add subsequent messages to a ticketPOST /api/custom-fields— create custom field definitionsPUT /api/tickets/{id}— update ticket tags, status, custom field values
Rate limits (Gorgias, as of June 2025):
- API key integrations: 40 requests per 20-second window
- OAuth2 integrations: 80 requests per 20-second window
- Enterprise accounts: same request counts but 10-second window
- Leaky bucket algorithm — budget refills steadily, not in a block
- Monitor
X-Gorgias-Account-Api-Call-LimitandRetry-Afterheaders
Throughput math: At 40 requests per 20 seconds (API key auth), you can make roughly 120 API calls per minute. A ticket with 5 messages requires 6 API calls (1 ticket creation + 5 message additions), so throughput caps around 20 full tickets per minute. A 50,000-ticket migration at this rate takes ~42 hours of continuous API calls. In practice, add 20–30% overhead for retries, 429 handling, and network latency — budget approximately 50–55 hours.
Webhook behavior during import: Gorgias fires webhooks on ticket creation and update events, including API-created tickets. If you have active webhook subscriptions (e.g., to Slack, a CRM, or an analytics tool), these will trigger for every imported ticket. Either disable webhook subscriptions during import or filter events by channel: api in your webhook consumers.
Custom field writes: Gorgias uses replace-all semantics for ticket custom fields. If you PUT custom fields on a ticket, it overwrites all existing values. Use a fetch-merge-put pattern to avoid losing data set by other processes.
Step-by-Step Migration Process
Step 1: Create Agents, Teams, and Custom Fields in Gorgias
Before migrating any tickets, create all agent accounts and teams in Gorgias manually or via the API. Record a mapping of Kustomer User IDs → Gorgias User IDs. Set up custom ticket fields (max 25 active) and pre-create tags that map to your Kustomer tag taxonomy. Disable all Gorgias rules and webhook subscriptions during import — active rules can auto-close, auto-tag, or auto-assign imported tickets, and webhooks will fire for every created record, flooding downstream systems.
Step 2: Extract Customers from Kustomer
Paginate through /v1/customers using cursor-based pagination. Store each customer record with their email, phone channels, custom attributes, and associated Company name.
Step 3: Load Customers into Gorgias
Create customer records via POST /api/customers. Gorgias deduplicates customers by email address — if a customer already exists (e.g., from Shopify sync), the API returns 409 Conflict. Match on external_id, email, and phone before insert. On 409, fetch the existing customer via GET /api/customers?email={email} and record the Gorgias customer ID for ticket association.
Example 409 response body:
{
"type": "error",
"message": "A customer with this email already exists",
"meta": {
"customer_id": 12345678
}
}Step 4: Extract Conversations and Messages from Kustomer
For each conversation, call /v1/conversations/{id}/messages to retrieve full message bodies. Store conversations grouped by customer with all messages, notes, and metadata.
import requests
import time
KUSTOMER_API = "https://api.kustomerapp.com"
KUSTOMER_TOKEN = "your-kustomer-api-key"
headers = {"Authorization": f"Bearer {KUSTOMER_TOKEN}"}
def extract_conversations(after_cursor=None):
params = {"page[size]": 100}
if after_cursor:
params["page[after]"] = after_cursor
resp = requests.get(f"{KUSTOMER_API}/v1/conversations", headers=headers, params=params)
resp.raise_for_status()
return resp.json()
def extract_messages(conversation_id):
resp = requests.get(
f"{KUSTOMER_API}/v1/conversations/{conversation_id}/messages",
headers=headers
)
resp.raise_for_status()
return resp.json()["data"]
# Paginate through all conversations
all_conversations = []
cursor = None
while True:
batch = extract_conversations(cursor)
all_conversations.extend(batch["data"])
cursor = batch.get("links", {}).get("next")
if not cursor:
break
time.sleep(0.1) # Respect rate limitsStep 5: Transform Data to Gorgias Schema
Map Kustomer statuses to Gorgias open/closed, convert message direction to from_agent boolean, flatten KObjects into tags or ticket fields, and ensure all messages have sent_datetime set. Deduplicate customers by email. Download any attachments from expiring Kustomer S3 URLs — these signed URLs typically expire within hours and become permanently inaccessible after Kustomer account cancellation.
Step 6: Load Tickets and Messages into Gorgias
For each Kustomer conversation, create a Gorgias ticket with the first message inline, then add subsequent messages.
GORGIAS_DOMAIN = "your-store"
GORGIAS_EMAIL = "your-email@example.com"
GORGIAS_API_KEY = "your-gorgias-api-key"
GORGIAS_API = f"https://{GORGIAS_DOMAIN}.gorgias.com/api"
def create_ticket_with_backoff(conversation, messages, customer_email, max_retries=5):
first_msg = messages[0]
ticket_payload = {
"customer": {"email": customer_email},
"channel": "api",
"status": "closed" if conversation["attributes"]["status"] == "done" else "open",
"tags": [{"name": t} for t in conversation["attributes"].get("tags", [])],
"messages": [{
"sender": {"email": customer_email},
"body_html": first_msg["attributes"].get("preview", ""),
"channel": "api",
"from_agent": first_msg["attributes"]["direction"] == "out",
"sent_datetime": first_msg["attributes"]["sentAt"], # CRITICAL
"via": "api"
}]
}
for attempt in range(max_retries):
resp = requests.post(
f"{GORGIAS_API}/tickets",
auth=(GORGIAS_EMAIL, GORGIAS_API_KEY),
json=ticket_payload
)
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(retry_after)
continue
resp.raise_for_status()
break
ticket_id = resp.json()["id"]
# Add remaining messages with exponential backoff
for msg in messages[1:]:
msg_payload = {
"sender": {"email": customer_email} if msg["attributes"]["direction"] == "in"
else {"email": GORGIAS_EMAIL},
"body_html": msg["attributes"].get("preview", ""),
"channel": "api",
"from_agent": msg["attributes"]["direction"] == "out",
"sent_datetime": msg["attributes"]["sentAt"],
"via": "api"
}
for attempt in range(max_retries):
resp = requests.post(
f"{GORGIAS_API}/tickets/{ticket_id}/messages",
auth=(GORGIAS_EMAIL, GORGIAS_API_KEY),
json=msg_payload
)
if resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(retry_after)
continue
resp.raise_for_status()
break
time.sleep(0.5) # Throttle to stay within rate limits
return ticket_idExample 429 response:
HTTP/1.1 429 Too Many Requests
Retry-After: 5
X-Gorgias-Account-Api-Call-Limit: 40/40
Tickets created with message channel api do not trigger auto-reply rules in Gorgias, which is the correct behavior for historical imports. Always implement exponential backoff on 429 responses — both Kustomer and Gorgias return Retry-After headers that specify the wait time in seconds.
Step 7: Validate Migrated Data
After loading, run validation checks (detailed in the Validation section below).
Multi-Brand and Multi-Store Considerations
If your Kustomer instance serves multiple brands, or you're migrating to multiple Gorgias accounts (one per store), additional planning is required:
- Gorgias multi-store structure: Each Gorgias account maps to one Shopify store. Multi-brand operations typically require separate Gorgias accounts, each with independent ticket, customer, and rule configurations.
- Extraction partitioning: Filter Kustomer conversations by brand tag, team, or custom attribute to segment which records go to which Gorgias account.
- API keys per account: Each Gorgias account has its own API credentials and independent rate limits. You can parallelize loading across accounts to increase total throughput.
- Customer deduplication across stores: If a customer exists across multiple brands, they'll be independent records in separate Gorgias accounts. There is no cross-account customer linking.
- Rule rebuilding: Each Gorgias account needs its own rule set. A 3-brand migration means rebuilding automations three times.
Edge Cases and Challenges
These are the issues that break migrations in practice:
- Duplicate customers. Kustomer allows multiple customer records with the same email. Gorgias deduplicates by email and returns
409 Conflicton duplicates. Merge or choose a primary record before import. - Multi-channel conversations. A single Kustomer conversation can span email, chat, and SMS. Gorgias tickets are channel-specific. Split multi-channel conversations into separate tickets or import all messages under
channel: api. - Kustomer Search API limits. The Search API returns a maximum of 10,000 records per query regardless of pagination (100 pages × 100 records). For larger datasets, use date-range filters to partition extraction into smaller windows. Use archive search (
POST /v1/customers/archive-search) for records older than two years. - Message body size. Gorgias has a 1MB message body limit. Long enterprise email threads that exceed this limit are silently rejected — the API returns
200but the body is truncated or empty. Validate message body size before import and split oversized bodies. - Ticket subject length. Gorgias limits ticket subjects to 998 characters. (developers.gorgias.com)
- Message count per ticket creation. Ticket creation accepts 1 to 500 messages in the initial payload. Threads longer than 500 messages need an append phase via
/api/tickets/{id}/messages. (developers.gorgias.com) - Attachments and expiring URLs. Kustomer stores attachments as AWS S3 signed URLs that expire after a short period (typically hours). If you simply pass the URL to Gorgias, the image breaks when the signature expires. Your migration script must download the binary file from the Kustomer URL, upload it to Gorgias via
POST /api/upload, and replace the URL in the message body. Gorgias can return413 Payload Too Largeon oversized files — test your largest files early. (developers.gorgias.com) - Inline images. Kustomer inline images reference Kustomer CDN URLs. After migration and Kustomer account cancellation, these URLs become inaccessible. Download and re-host images before canceling your Kustomer subscription.
- Snoozed conversations. Kustomer's
snoozedstatus has no direct Gorgias equivalent. Import asopenand tag withsnoozed-from-kustomerfor manual triage. - Company→Customer relationships. Lost entirely in Gorgias. If this hierarchy drives your routing or reporting, evaluate whether Gorgias is the right target platform before committing.
- Linked conversations. Kustomer supports linked conversations; Gorgias tickets are independent. Preserve cross-links in internal notes (e.g., "Linked to original ticket: KUST-12345") or an external reference table. (help.kustomer.com)
- Merged customer records. Kustomer allows merging customers. Sometimes the API returns historical data attached to a deprecated ID. Ensure your mapping table resolves merged IDs to the primary email address before pushing to Gorgias.
- Email threading post-migration. Gorgias threads emails based on SMTP headers (
In-Reply-To,References). When migrating via API, you force grouping via the Ticket ID, but customer replies post-migration might create new tickets if the original SMTP headers were not preserved. Agents need to be trained to manually merge these.
Gorgias Limitations vs. Kustomer
Be explicit about what you lose in this migration:
| Capability | Kustomer | Gorgias |
|---|---|---|
| Custom objects | KObjects with 500+ attributes per Klass | Not supported |
| Custom fields | Unlimited via Klass schema | 25 ticket fields, 4 customer fields |
| Company/Account object | First-class with hierarchy | Not available |
| Ticket statuses | Open, Snoozed, Done + custom | Open, Closed |
| Advanced routing | Skill-based, SLA-driven, queue management | Rule-based (max 70 rules) |
| Data model depth | CRM-grade, relational | Flat, ticket-centric |
| API throughput | 1,000–2,000 req/min | ~120 req/min (API key), ~240 req/min (OAuth2) |
| Webhook granularity | Event-based with filters | Event-based, fires on all API-created records |
If your team uses fewer than 5 KObject types and doesn't rely on Company hierarchy for routing, the simplification is often an operational advantage — less schema to maintain, faster agent onboarding, lower platform cost.
Validation and Testing
Never trust a migration without systematic validation.
Record Count Comparison
- Total customers in Kustomer vs. Gorgias (expect slight differences due to deduplication — typically 2–5% fewer in Gorgias)
- Total conversations vs. tickets (should be 1:1)
- Total messages per ticket (sample 50–100 tickets manually)
Field-Level Validation
- Spot-check 5% of migrated tickets for correct status, tags, timestamps, and assignee
- Verify
sent_datetimeis set on all historical messages — query Gorgias API for tickets where any message hassent_datetimeequal to today's date (these are likely missing the original timestamp) - Confirm customer email and phone channels transferred correctly
- Open historical tickets and verify that inline images and PDF attachments load
Sampling Strategy
- Random sample: 100 tickets across different date ranges
- Edge cases: Tickets with 20+ messages, multi-channel conversations, tickets with attachments >5MB
- High-value customers: Manually verify VIP or high-LTV customer profiles
- Boundary dates: Tickets near the 2-year archive search boundary
UAT Process
Have 2–3 agents use Gorgias in parallel with Kustomer for 24–48 hours before full cutover. They should verify:
- Customer history is visible and accurate
- Tags and custom fields render correctly
- Macros and rules work as rebuilt
- Search, assignment, and historical context lookup function as expected
Rollback Plan
Do not cancel your Kustomer account until validation is complete. Keep Kustomer in read-only mode (revoke agent write access) for at least 2 weeks post-migration. Operationally, rollback means:
- Re-enable agent write access in Kustomer and restore email/chat routing to Kustomer endpoints
- Disable Gorgias email forwarding to prevent duplicate ticket creation
- Preserve the Gorgias import — don't delete imported data, as it serves as validation reference
- Run a delta extract from Gorgias for any tickets created during the cutover window that need to be pushed back to Kustomer
If critical data is missing, you can re-extract from Kustomer. The intermediate storage layer (S3/database) from your ETL pipeline provides a backup independent of both platforms.
Post-Migration Tasks
Data migration is only half the job. Once the data is in Gorgias, you must rebuild the operational layer.
Rebuild Automations
Kustomer Workflows and Business Rules do not export. Document every active workflow before migration and rebuild them as Gorgias Rules. Gorgias supports up to 70 rules that apply across stores and channels unless scoped with conditions. (docs.gorgias.com) Common patterns:
- Auto-tagging by channel or keyword → Gorgias Rule with tag action
- SLA-based escalation → Gorgias Rule with priority/assignment action
- CSAT surveys → Gorgias native satisfaction surveys
Rebuild Macros
Migrate canned responses. Gorgias supports CSV import for macro names, body text, tags, and IDs, but it is not a full-fidelity migration format for cross-platform macro logic. (docs.gorgias.com) Gorgias supports Shopify variables in macros (e.g., {{ticket.customer.integrations.shopify.orders.last.name}}) — update your templates to use these native variables.
Migrate Knowledge Base
Kustomer's built-in KB articles need to be migrated to Gorgias's Help Center. Options:
- Manual: Copy-paste for small KBs (<50 articles). Tedious but preserves formatting control.
- API-based: Extract articles from Kustomer via
/v1/kb/articles, transform to Gorgias's article schema, and create viaPOST /api/articles. Map Kustomer KB categories to Gorgias Help Center collections. Internal images must be re-hosted — Kustomer-hosted image URLs will break after account cancellation.
Reconnect Integrations
- Shopify: Connect Gorgias's native Shopify integration — this replaces most Kustomer KObjects for order data
- Other tools: Reconnect any Slack, Jira, or CRM integrations via Gorgias's integration marketplace or API
- Webhooks: Reconfigure any webhook consumers to point to Gorgias's event format
Agent Training
Train agents on the discrete ticketing model. They will no longer have a single scrolling timeline for all customer interactions. Focus on:
- Ticket field usage (replacing KObject lookups)
- Macro creation and usage with Shopify variables
- Rule-based automation setup
- Shopify action sidebar (refunds, order edits in-ticket)
- How to find prior conversations for a customer (Gorgias groups tickets by customer, but doesn't present a unified timeline)
Monitor for 30 Days
After cutover, watch for:
- Missing customer history complaints from agents
- Broken inline images referencing old Kustomer CDN URLs
- Duplicate tickets from delta sync edge cases
- Rule misfires from incorrectly rebuilt automations
- Webhook flooding to downstream systems from imported ticket events
- Customer replies creating new tickets instead of threading into migrated conversations
When to Use a Managed Migration Service
DIY is viable for small, simple migrations. It stops being viable when:
- Ticket volume exceeds 50K — rate limit orchestration across both APIs becomes a full-time engineering task for 2–3 weeks
- KObject schemas are complex — flattening logic requires business context that's hard to script generically
- Zero-downtime is required — delta syncs with proper deduplication are error-prone without experience
- Attachments must be preserved — downloading, re-hosting, and re-linking thousands of files is tedious and fragile
- Engineering bandwidth is limited — a migration script that takes 2 weeks to build and debug is 2 weeks not spent on product
- Multi-brand setup — migrating to multiple Gorgias accounts multiplies every step
The APIs are documented, but the edge cases are not. Expiring S3 links for Kustomer attachments, proprietary HTML wrappers in message bodies, merged customer IDs — these are the issues that turn a "two-week sprint" into a two-month maintenance cycle as support agents uncover missing data post-launch.
Best Practices
- Back up everything before starting. Export all Kustomer data to an intermediate store (S3, local DB) before loading into Gorgias. This intermediate layer serves as your rollback safety net and validation source of truth.
- Run a test migration first. Migrate 100–500 tickets to a Gorgias trial account. Validate field mapping, timestamp handling, and tag transfer before touching production.
- Disable Gorgias rules and webhooks during import. Active rules can auto-close, auto-tag, or auto-assign imported tickets. Active webhooks flood downstream systems. Toggle both off before import, re-enable after.
- Partition Kustomer extraction by date. Use date-range filters to stay within the 100-page / 10K-record search limits. Extract month-by-month for large datasets.
- Always set
sent_datetime. Omitting it causes Gorgias to send historical messages as live emails to your customers. - Map agents before tickets. Create all Gorgias user accounts first. Use email-based lookup to map Kustomer assignees to Gorgias agent IDs during ticket import.
- Plan for Kustomer CDN expiry. If inline images or attachments reference Kustomer-hosted URLs, download and re-host them before canceling your Kustomer subscription.
- Freeze Kustomer configurations. Enforce a change freeze on Kustomer tags, custom fields, and workflows two weeks before go-live.
- Use
external_ideverywhere. Preserve Kustomer source IDs asexternal_idon Gorgias customers and tickets for idempotent operations and post-migration validation. - Use delta migrations for zero-downtime cutover. Run the bulk migration over a weekend, then run a delta script to catch any tickets created or updated during the migration window.
Making the Right Call
A Kustomer to Gorgias migration is technically straightforward in concept — extract conversations and customers, transform the schema, load into tickets — but operationally dense. The data model downshift from Kustomer's CRM-grade architecture to Gorgias's flat ticket model requires intentional decisions about what to preserve, what to flatten, and what to leave behind.
For Shopify-native DTC teams, Gorgias's tighter integration often justifies the structural simplification. For teams with heavy KObject usage or B2B account hierarchies, evaluate whether the data model trade-offs are acceptable before committing.
The API rate limits on both sides make this a slow migration by default — budget 50–55 hours of wall-clock time for a 50K+ ticket migration including retry overhead. Test early, validate often, and never skip the sent_datetime field.
Frequently Asked Questions
- Is there a native Kustomer to Gorgias migration tool?
- No. Kustomer has no built-in Gorgias export, and Gorgias's native importer only supports Zendesk. The practical route is Kustomer REST API extraction, data transformation, and Gorgias REST API loading — or a third-party migration service like Help Desk Migration or ClonePartner.
- What data do I lose migrating from Kustomer to Gorgias?
- You lose KObjects (custom objects), Company/Account hierarchy, linked conversations, advanced routing rules, and custom status types. Gorgias supports only 25 active ticket fields and 4 customer fields — far fewer than Kustomer's unlimited custom attributes via Klasses.
- How long does a Kustomer to Gorgias migration take?
- At Gorgias's API rate limit of ~120 requests per minute (API key auth), a 50,000-ticket migration with 5 messages each takes roughly 42 hours of continuous API calls. End-to-end including planning, testing, and validation, budget 2–4 weeks.
- What is the sent_datetime trap in Gorgias migration?
- If you omit the sent_datetime field when creating messages via the Gorgias API, Gorgias treats each imported message as a new outbound email and sends it to your customers. Always set sent_datetime to the original message timestamp to prevent this.
- How do Kustomer KObjects map to Gorgias?
- Gorgias has no native custom object framework. KObject data must be serialized and flattened into Gorgias tags, ticket custom fields (max 25 active), or formatted internal notes. For Shopify-based teams, Gorgias's native Shopify integration often replaces order-related KObjects entirely.


