Skip to content

Zoho Desk to Gorgias Migration: API Limits & Data Mapping

Technical guide to migrating from Zoho Desk to Gorgias. Covers API extraction, data model mapping, status translation, rate limits, and edge cases.

Nachi Nachi · · 21 min read
Zoho Desk to Gorgias Migration: API Limits & Data Mapping
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

Zoho Desk to Gorgias Migration: API Limits & Data Mapping

Info

TL;DR — Zoho Desk to Gorgias Migration

A Zoho Desk to Gorgias migration requires a custom API-driven approach — Gorgias has no native importer for Zoho Desk. Realistic timeline: 2–4 weeks end to end. The primary risks are silent data loss from model mismatches: Zoho Desk's multi-stage ticket statuses collapse to Gorgias's 2 API statuses (open and closed), Zoho Desk's unlimited custom fields must fit into Gorgias's 25 active ticket field limit, and Zoho's CSV export does not include ticket threads or comments. You must extract data via the Zoho REST API, handle rolling credit and concurrency limits, reconstruct the ticket lifecycle in Gorgias's e-commerce-native data model, and refresh OAuth tokens during multi-day extractions. Teams with under 10,000 tickets and simple schemas can self-serve with scripts. Everyone else should plan for API orchestration challenges or use a managed migration service.

What Is a Zoho Desk to Gorgias Migration?

A Zoho Desk to Gorgias migration is the process of moving help desk data — tickets, conversation threads, private comments, contacts, accounts, tags, custom fields, and attachments — from Zoho Desk's department-centric platform to Gorgias's e-commerce-native help desk. The goal is to preserve full conversation history, retain customer context, and rebuild workflows without interrupting live support.

This migration is non-trivial because the two platforms have fundamentally different data models. Zoho Desk organizes data around Tickets, Threads (public replies), Comments (private notes), Contacts, Accounts (organizations), Departments, and Agents. Gorgias organizes around Tickets, Messages, Customers, Tags, and Teams — with a flatter schema and a strictly binary status lifecycle. This is not a 1:1 data swap. It is a structural translation.

For a detailed walkthrough of extracting data from Zoho Desk specifically, see our Zoho Desk export guide.

Why E-Commerce Teams Move from Zoho Desk to Gorgias

Teams make this switch for platform-specific architectural reasons:

  • Native Shopify/BigCommerce integration. Gorgias surfaces live order data, refund actions, and shipping status directly in the ticket sidebar via the integrations field on tickets (see Gorgias ticket integrations docs). Agents can issue refunds, duplicate orders, and cancel items without leaving the conversation. Zoho Desk's e-commerce integrations are marketplace add-ons that require separate windows and lack write-back capabilities.
  • Continuous conversations vs. discrete tickets. Gorgias treats customer interactions as an ongoing timeline — a closed conversation reopens when a customer replies. Zoho Desk treats tickets as distinct, isolated units, which frequently leads to duplicates when customers follow up on a closed issue.
  • Ticket-based pricing vs. agent-seat pricing. Gorgias charges by monthly ticket volume, not per agent seat — all paid plans include unlimited agent seats. Zoho Desk's Professional plan charges per agent per month. For teams with 10+ part-time agents or seasonal staff, Gorgias's model can reduce per-resolution cost significantly.
  • Simpler data model. Teams that found Zoho Desk's Departments, Blueprints, and multi-module architecture (Tasks, Calls, Events) heavier than needed often prefer Gorgias's focused ticket-and-message model.

If you're still evaluating platforms, our Gorgias alternatives comparison covers the full landscape.

Data Model Mapping: Zoho Desk → Gorgias

The structural translation is the hard part. Map every Zoho Desk object before writing a single line of migration code. Get this wrong and you'll end up with orphaned tickets, lost context, or broken automation rules.

Zoho Desk Object Gorgias Equivalent Notes
Ticket Ticket 1:1, but status model differs significantly
Thread (public reply) Message (channel: 'email') Each thread becomes a message on the ticket
Comment (private note) Message (channel: 'internal-note') Internal notes map directly
Contact Customer Customer is keyed by email address
Account (Organization) Company (limited) or tag/metadata Gorgias Company object is less featured than Zoho Account
Department Tag or Team No native department routing in Gorgias
Agent User Agents map to Gorgias users; must pre-exist before ticket import
Custom Fields Ticket Fields / Customer Fields Gorgias caps at 25 active ticket fields, 4 active customer fields
Products No equivalent Store in ticket meta or drop
Activities (Tasks, Calls, Events) No equivalent Cannot be migrated
Blueprints Rules Manual rebuild required; no import path
KB Articles Separate migration Gorgias Help Center is a distinct module
Attachments Message attachments Must be downloaded from Zoho and re-uploaded via Gorgias API
Shopify order linkage integrations field on Ticket Critical for e-commerce teams; set during ticket creation

Status Translation

This is the single most common source of confusion. Zoho Desk supports a multi-stage ticket lifecycle with custom statuses ("Awaiting Dev", "Pending Customer", "Escalated", etc.). Gorgias enforces a strict binary model at the API level: open or closed. There is no pending, on-hold, or escalated state in the Gorgias API.

Zoho Desk Status Gorgias Status Rationale
Open open Active, needs agent action
Escalated open Preserve as open so it stays in agent queues
On Hold closed + snooze Use snooze_datetime to auto-reopen at follow-up time
Closed closed Terminal state

Gorgias supports a snooze mechanism — you can set snooze_datetime on a ticket to auto-reopen it at a specific UTC timestamp. For Zoho Desk "On Hold" tickets that have a follow-up date, snooze is the closest functional equivalent. If your "On Hold" means "agent needs to take action internally" rather than "waiting on customer," map to open with a tag instead.

Warning

Custom statuses are lost. If your Zoho Desk instance uses custom statuses beyond the four defaults, you must decide per-status whether to map to open or closed. Preserve the original status as a tag (e.g., zoho-status:waiting-on-vendor) so agents can filter and find them post-migration.

Custom Fields: The 25-Field Ceiling

Zoho Desk allows virtually unlimited custom fields across tickets, contacts, and accounts. Gorgias enforces hard limits: 25 active ticket fields and 4 active customer fields (see Gorgias custom fields documentation).

Before migration, audit your Zoho Desk custom fields. Identify which ones are actively used in workflows, reports, or agent processes. For fields that don't fit:

  • Encode as tags. A Zoho field like Priority Tier = Gold becomes a tag priority-tier:gold.
  • Store in the meta object. Gorgias tickets and customers both support a freeform meta JSON field for structured key-value data. It is queryable via API but not visible in the UI without a custom widget.
  • Drop low-value fields. If a field was only populated on fewer than 5% of tickets, it likely doesn't justify migration effort.

Available Gorgias ticket field types are: Dropdown, Number, Text, and Yes/No.

Contacts and Accounts → Customers and Companies

Zoho Desk separates Contacts (individual people) from Accounts (organizations). Gorgias uses Customers as the primary object. While Gorgias supports a Companies concept, it is far less featured than Zoho's Account hierarchy — no custom fields on the Company object, no hierarchical parent/child accounts.

The practical approach:

  1. Migrate each Zoho Contact as a Gorgias Customer, keyed by email address.
  2. Map Zoho Accounts to Gorgias Companies where applicable, or store the Account name as a tag (e.g., org:acme-corp) or in the customer's data field.
  3. Create Customer and Company records before migrating tickets. Store the mapped IDs (zoho_contact_id → gorgias_customer_id) in a local database or key-value store.

When POSTing a new customer that already exists in Gorgias (because of a prior Shopify sync, for example), Gorgias returns the existing customer record rather than creating a duplicate. The response will have HTTP 200 with the existing id. Store this ID in your mapping table; do not assume a new ID was created.

This is a real downgrade for B2B teams that rely heavily on account-level views or hierarchical organization records. If account hierarchy is critical to your support operations, evaluate whether Gorgias is the right target platform before committing to migration.

Departments → Tags and Views

Zoho Desk silos tickets into Departments — each ticket belongs to exactly one department, and agents in one department cannot easily see tickets in another unless explicitly granted access.

Gorgias uses a flatter structure with Teams and Views (filtered lists based on tags, channels, or assignees). Two approaches:

  1. Map departments to tags (e.g., dept:billing, dept:returns). Create Gorgias Views based on those tags to replicate the departmental workflow. This is simpler to implement and more flexible for reporting.
  2. Map departments to Gorgias Teams and assign each ticket to the corresponding team. This preserves routing intent but requires pre-creating all teams before ticket import.

Most e-commerce teams migrating to Gorgias choose tags, because Gorgias's Rules engine can replicate department-based routing by acting on tags automatically.

Tickets, Threads, and Comments → Tickets and Messages

This is the most complex part of the data translation. Zoho Desk splits a conversation into three distinct entities: the Ticket (metadata), Threads (public-facing replies, each with a direction field of in or out), and Comments (private notes with isPublic: false). Gorgias unifies everything as Messages on a ticket, differentiated by the channel field and via direction.

Zoho Desk Entity Gorgias Message Property Value
Thread (direction: in) via customer
Thread (direction: out) via agent
Comment (isPublic: false) channel internal-note
Thread with attachment Message + uploaded file Separate upload step required

Extracting Data from Zoho Desk

You have three extraction paths, and only one gives you full conversation history.

Option 1: CSV Export (Not Viable for Full Migrations)

Zoho Desk's built-in CSV export under Setup → Data Administration exports ticket metadata — subject, status, priority, assignee, timestamps. It does not include threads or comments. The UI export is capped at 3,000 records per export. Report exports allow up to 20,000 records but still exclude conversation content.

For anything beyond a contact list migration, CSV export is not viable.

Option 2: Data Backup (Partial Coverage)

Zoho Desk's Data Backup feature exports a broader set of modules as CSV files in a downloadable ZIP: tickets, threads, comments, time entries, contacts, accounts, activities, products, KB articles, agents, teams, and departments.

Warning

Attachment limitation. The backup includes secure download links for attachments, not the actual files. You must use the Zoho Desk API to fetch each attachment using those links before they expire. Plan for this as a separate extraction step. The backup has a 10 million record cap. Only the primary contact on the Zoho account can create and download backups — not just any admin.

The Zoho Desk REST API provides full access to tickets, threads, comments, contacts, accounts, attachments, and custom fields. This is the recommended extraction method for any migration that needs full fidelity.

Authentication and data residency: Zoho uses OAuth 2.0. Ensure you are hitting the correct top-level domain based on the account's data residency:

  • US: desk.zoho.com
  • EU: desk.zoho.eu
  • IN: desk.zoho.in
  • AU: desk.zoho.com.au
  • JP: desk.zoho.jp

Gorgias similarly has EU-hosted accounts on eu.gorgias.com. If both your Zoho and Gorgias accounts are EU-hosted, all API calls and data transfers stay within EU infrastructure. If they differ, you have a cross-region data transfer that may carry GDPR implications depending on your customer base.

Daily credit limits vary by plan. The Free plan gets 25,000 API requests per organization per day; Standard gets 50,000; Professional gets 75,000; Enterprise gets 100,000. You can purchase add-on credits up to 5,000,000. See Zoho Desk API credit documentation for current values.

Per-minute throttling. Even within the daily limit, Zoho Desk enforces concurrent request limits and returns HTTP 429 when exceeded. There is no published per-minute rate cap in Zoho's documentation — the threshold is enforced empirically. Throttle your extraction scripts to 3–5 concurrent requests as a conservative starting point.

Pagination. List endpoints use from and limit parameters. Maximum limit per request is 100.

Thread and comment retrieval costs extra credits. Listing tickets is one call; fetching threads for each ticket is a separate call per ticket; fetching comments for each ticket is another separate call. For 50,000 tickets, that is a minimum of 150,000 API calls just for tickets + threads + comments, before counting attachments.

OAuth token expiry during multi-day extractions. Zoho's OAuth access tokens expire after 1 hour by default. For a 4–5 day extraction window (required on the Standard plan at 50,000 credits/day), your script must automatically refresh tokens using the refresh token flow. Failure to handle this results in silent 401 failures mid-extraction, often without obvious error logging.

# Zoho OAuth token refresh during long-running extraction
import requests
import time
 
ZOHO_TOKEN_URL = "https://accounts.zoho.com/oauth/v2/token"
 
def refresh_access_token(client_id, client_secret, refresh_token):
    resp = requests.post(ZOHO_TOKEN_URL, data={
        "grant_type": "refresh_token",
        "client_id": client_id,
        "client_secret": client_secret,
        "refresh_token": refresh_token
    })
    resp.raise_for_status()
    data = resp.json()
    return data["access_token"]
 
class ZohoDeskClient:
    def __init__(self, org_id, client_id, client_secret, refresh_token):
        self.org_id = org_id
        self.client_id = client_id
        self.client_secret = client_secret
        self.refresh_token = refresh_token
        self.access_token = None
        self.token_expiry = 0
        self.base_url = "https://desk.zoho.com/api/v1"
 
    def get_headers(self):
        if time.time() >= self.token_expiry - 60:  # Refresh 60s before expiry
            self.access_token = refresh_access_token(
                self.client_id, self.client_secret, self.refresh_token
            )
            self.token_expiry = time.time() + 3600
        return {
            "orgId": self.org_id,
            "Authorization": f"Zoho-oauthtoken {self.access_token}"
        }
 
    def get_tickets(self, from_index=0, limit=100):
        resp = requests.get(
            f"{self.base_url}/tickets",
            headers=self.get_headers(),
            params={"from": from_index, "limit": limit, "include": "contacts"}
        )
        resp.raise_for_status()
        return resp.json()["data"]
 
    def get_threads(self, ticket_id):
        resp = requests.get(
            f"{self.base_url}/tickets/{ticket_id}/threads",
            headers=self.get_headers()
        )
        resp.raise_for_status()
        return resp.json()["data"]
 
    def get_comments(self, ticket_id):
        resp = requests.get(
            f"{self.base_url}/tickets/{ticket_id}/comments",
            headers=self.get_headers()
        )
        resp.raise_for_status()
        return resp.json()["data"]
Tip

Budget your API credits before starting. For a 50K-ticket migration with threads, comments, and attachments, expect to consume 275,000–350,000 API credits on the Zoho side alone. If you're on the Standard plan (50,000/day), that's 5–7 days of extraction just from rate limits — across which you will need multiple OAuth token refreshes.

Warning

The 100-ticket pagination limit. Zoho's GET /api/v1/tickets endpoint returns a maximum of 100 tickets per page. For 500,000 tickets, that is 5,000 API calls just for parent tickets, plus up to 500,000 calls for threads, plus 500,000 calls for comments. Monitor your daily credit consumption. You may need to spread extraction across multiple weeks on lower-tier plans.

Loading Data into Gorgias

Gorgias has no native Zoho Desk importer — it offers a built-in importer for Zendesk only. For Zoho Desk, you write directly against the Gorgias REST API.

Gorgias API Rate Limits

Gorgias uses a leaky bucket algorithm for rate limiting. In a leaky bucket system, requests fill a bucket that drains at a fixed rate. You can burst above the sustained rate until the bucket is full, at which point the API returns HTTP 429. This differs from a fixed window (e.g., "100 requests per minute") — you can process a short burst quickly, then must slow down.

The limits depend on your authentication method and plan (see Gorgias rate limit documentation):

Auth Method Requests Window
API Key 40 requests 20 seconds (≈120 req/min sustained)
OAuth2 80 requests 20 seconds (≈240 req/min sustained)
Enterprise (either) Same counts 10-second window (2× throughput)

Every API response includes the X-Gorgias-Account-Api-Call-Limit header showing current usage against the bucket, and a Retry-After header when you receive a 429. Build your import script to read these headers dynamically — do not hard-code sleep intervals.

# Gorgias API client with leaky bucket handling and rate limit headers
import requests
import time
 
class GorgiasClient:
    def __init__(self, account_id, api_key):
        self.base_url = f"https://{account_id}.gorgias.com/api"
        self.session = requests.Session()
        self.session.auth = (f"{account_id}@example.com", api_key)
 
    def post(self, endpoint, payload, retries=5):
        url = f"{self.base_url}/{endpoint}"
        for attempt in range(retries):
            resp = self.session.post(url, json=payload)
            if resp.status_code == 429:
                retry_after = int(resp.headers.get("Retry-After", 5))
                time.sleep(retry_after)
                continue
            resp.raise_for_status()
            return resp.json()
        raise Exception(f"Failed after {retries} retries: {endpoint}")
 
    def create_ticket(self, payload):
        return self.post("tickets", payload)
 
    def create_message(self, ticket_id, payload):
        return self.post(f"tickets/{ticket_id}/messages", payload)
 
    def set_custom_fields(self, ticket_id, fields_payload):
        # replace-all semantics: include every field or it will be cleared
        url = f"{self.base_url}/tickets/{ticket_id}/custom-fields"
        resp = self.session.put(url, json=fields_payload)
        resp.raise_for_status()
        return resp.json()

Import Sequence

Order matters. Gorgias requires referenced objects to exist before you can link them. Skipping this order results in foreign key errors or silent null references.

Step 1: Create Users (Agents). Before importing any tickets, create all Zoho Desk agents as Gorgias users via POST /api/users. Build a mapping table: zoho_agent_id → gorgias_user_id. If a Zoho agent does not exist as a Gorgias user at ticket creation time, the API will either fail or assign the ticket to the authenticated API user.

Step 2: Create Customers. For each Zoho Desk Contact, create a Gorgias Customer via POST /api/customers. Key on email address. If the customer already exists (e.g., from a connected Shopify store), Gorgias returns HTTP 200 with the existing record — not a duplicate or an error. Store the mapping: zoho_contact_id → gorgias_customer_id.

Step 3: Create Tags. Create any tags you need via POST /api/tags — including tags for migrated Zoho statuses, departments, and custom field values that couldn't fit within the 25-field limit.

Step 4: Configure Ticket Fields. Set up your target ticket fields in Gorgias before importing tickets. Remember the 25 active maximum. Available types: Dropdown, Number, Text, Yes/No.

Step 5: Create Tickets with Initial Messages. For each Zoho Desk ticket, create a Gorgias ticket via POST /api/tickets. Include the first message in the creation payload to establish the conversation. Then add subsequent messages (threads and comments in chronological order) via POST /api/tickets/{id}/messages.

Step 6: Set Shopify/Order Integrations. For e-commerce teams, use the integrations field on the Gorgias ticket object to link tickets to Shopify order IDs. This field accepts an array of integration references. If this is omitted during import, agents lose the order sidebar context for historical tickets.

Step 7: Upload Attachments. For each Zoho Desk attachment, download the file via the Zoho API, then upload it to Gorgias via POST /api/upload and reference it in the relevant message. Alternatively, host the downloaded files on a publicly accessible server (S3, Cloudflare R2) and pass the URL in the attachments array of the Message payload — Gorgias will fetch and ingest them. The URL-based approach avoids the double-rate-limit bottleneck.

Step 8: Set Ticket Custom Fields. Use PUT /api/tickets/{id}/custom-fields to set field values. Important: this endpoint uses replace-all semantics. The request body must contain every custom field value you want the ticket to retain. Any field omitted from the payload will be cleared to null.

Preserving Historical Timestamps

If you POST a ticket to Gorgias without specifying dates, it will appear as if it was created at import time. To preserve historical accuracy, pass the original Zoho creation dates using the created_datetime field on both Ticket and Message objects. Gorgias accepts ISO 8601 UTC timestamps.

{
  "customer": {"id": 12345678},
  "subject": "Return request for Order #9999",
  "status": "closed",
  "created_datetime": "2024-03-15T14:32:00Z",
  "tags": [{"name": "dept:returns"}, {"name": "zoho-status:closed"}],
  "messages": [
    {
      "sender": {"id": 12345678},
      "channel": "email",
      "via": "customer",
      "source": {
        "type": "email",
        "from": {"address": "customer@example.com"},
        "to": [{"address": "support@yourbrand.com"}]
      },
      "body_html": "<p>I need to return this item.</p>",
      "created_datetime": "2024-03-15T14:32:00Z"
    }
  ]
}

Note that Gorgias enforces a 998-character limit on ticket subjects. Truncate long Zoho subjects before import to avoid a 400 error.

Handling Attachments and Payload Size

Danger

Payload size limits. Gorgias has a hard limit on ticket payload size. If a Zoho ticket has hundreds of threads with large inline base64-encoded images, the Gorgias API will reject the payload with a 413 Payload Too Large error. Strip all base64 inline images from HTML bodies, replace them with externally hosted URL references (see the inline image fix below), or split massive Zoho tickets into multiple Gorgias tickets (e.g., "Ticket Subject — Part 1", "Ticket Subject — Part 2").

Handling Duplicate Email Detection

When creating a Customer in Gorgias and a record with that email already exists, Gorgias returns HTTP 200 (not 201) with the existing customer object. Your import script must handle this response code explicitly — do not treat a 200 as a new record. Always capture the id from the response body, whether it is 200 or 201, and store it in your mapping table.

The Delta Sync and Cutover

A migration of this size takes days or weeks. By the time you finish loading historical data into Gorgias, your live Zoho Desk instance will have accumulated new tickets and replies. You must perform a delta sync to close this gap.

Delta Sync Strategy

  1. Track high-water marks. During the initial extraction, record the modifiedTime of the most recently updated ticket in Zoho Desk. The Zoho Desk API supports filtering by modifiedTimeRange on the tickets list endpoint: GET /api/v1/tickets?modifiedTimeRange=START_ISO,END_ISO.
  2. Run the delta. On cutover day, query the Zoho API for all tickets where modifiedTime is greater than your high-water mark.
  3. Upsert logic. If the ticket already exists in Gorgias (check your local mapping database), fetch the new threads and comments from Zoho and POST them to Gorgias as new messages on the existing ticket. If it's a completely new ticket, create it from scratch following the full import sequence.
  4. DNS cutover. Once the delta sync is complete, update your email forwarding rules (MX/TXT records) to route incoming support emails from Zoho Desk to your new Gorgias integration address. Disable Zoho Desk email fetching immediately after cutover to prevent message duplication across both systems.

The delta sync window is where most data loss occurs. Keep it as short as possible — ideally under a few hours. Coordinate the cutover during a low-traffic window (Sunday night, early morning).

Warning

Disable Zoho email fetching immediately after cutover. If Zoho Desk continues to fetch emails after your MX records point to Gorgias, the same inbound message may create tickets in both systems. Disable or delete the Zoho mailbox integration before completing DNS propagation.

Edge Cases That Break Migrations

Inline Images in Thread HTML

Zoho Desk threads often contain inline images referenced via Zoho-hosted URLs (e.g., desk.zoho.com/gallery/...). These URLs require valid Zoho session authentication to access. After migration, the raw HTML imported into Gorgias will contain <img src="https://desk.zoho.com/gallery/..."> tags that return HTTP 403 errors when Gorgias or the end-user's browser tries to load them.

Fix: During extraction, parse each thread's HTML body, find <img> tags with Zoho-hosted src attributes, download each image via the Zoho API using your OAuth token, upload to external storage (S3, Cloudflare R2, or similar), and rewrite the src attribute in the HTML before importing the message to Gorgias. This is tedious but required for full visual fidelity.

OAuth Token Expiry Mid-Extraction

Zoho OAuth access tokens expire after 3,600 seconds (1 hour). A multi-day extraction on the Standard plan (50,000 credits/day across 5+ days) will encounter dozens of token expirations. Without automatic refresh logic, your script fails silently with 401 errors. Use the token refresh pattern shown in the extraction code above, triggering a refresh when fewer than 60 seconds remain before the known expiry time.

Agent Attribution Loss

If a Zoho agent does not exist as a user in Gorgias at ticket creation time, the API assignment will fail or default to the authenticated API user. Create all agent mappings (zoho_agent_id → gorgias_user_id) in Step 1 of the import sequence, before importing any tickets.

Merged Tickets

Zoho Desk supports ticket merging — the merged ticket retains threads from all source tickets, which means thread counts can be unexpectedly high. The API returns the merged state, not the pre-merge constituent tickets. On the Gorgias side, merged customers return a 301 Moved Permanently redirect when you attempt to POST to the merged customer's old ID. Build 301 redirect handling into your customer creation and lookup logic.

CC Recipients

Zoho Desk stores CC recipients as an array on threads. Gorgias messages have a sender object and an optional receivers array, but the CC model is less explicit — receivers maps to to addresses, not cc. Store CC addresses in the message body_html footer or as ticket metadata to avoid losing this context entirely.

Automation and Workflow Gaps

Migrating data does not migrate business logic. Zoho Desk Blueprints, Workflow Rules, Assignment Rules, SLA policies, and macros have no import path into Gorgias. You must manually rebuild your critical automations as Gorgias Rules. Gorgias Rules are triggered by ticket events (created, updated, message received) and support conditions on tags, customer data, message content, and channel. Rebuild these before go-live — automation gaps after cutover directly affect first-response times and SLA compliance.

Throughput Planning and Timeline

Here is a realistic throughput estimate for a 50,000-ticket API-to-API migration:

Phase Zoho API Cost Gorgias API Cost Bottleneck
Extract 50K tickets 50,000 credits Zoho daily limit
Extract threads (50K × avg 4 threads) 200,000 credits Zoho daily limit
Extract comments (50K × avg 0.5 comments) 25,000 credits Zoho daily limit
Extract attachments metadata + files ~30,000 credits Zoho daily limit + download bandwidth
Create agents + customers ~15,000 requests Gorgias rate limit
Create tickets + messages ~250,000 requests Gorgias rate limit
Set custom fields ~50,000 requests Gorgias rate limit
Upload attachments ~30,000 requests Gorgias rate limit + upload bandwidth

Gorgias throughput math:

  • API key auth: 40 requests / 20 seconds = 120 requests/minute sustained
  • 345,000 total Gorgias requests ÷ 120 requests/minute ≈ 48 hours of continuous API calls
  • OAuth2 auth: 80 requests / 20 seconds = 240 requests/minute sustained → 24 hours
  • Enterprise (10-second window): up to 480 requests/minute → 12 hours

Zoho extraction math:

  • Standard plan (50,000/day): 305,000 credits ÷ 50,000 = 6–7 days of extraction, requiring 6–7 OAuth token refreshes per day
  • Professional plan (75,000/day): 4–5 days
  • Enterprise plan (100,000/day): 3–4 days

Total realistic timeline for a 50K-ticket migration: 2–3 weeks including script development, testing, extraction, import, delta sync, and validation.

Tip

Run a pilot batch first. Export and import 500 tickets as a validation batch. Check thread ordering, attachment rendering, status mapping, and custom field values before committing to the full run. Catching a mapping error on 500 tickets costs an hour. Catching it on 50,000 costs a week.

Validation Checklist

After migration, verify these items before cutting over live traffic:

  • Ticket count matches. Compare total tickets in Zoho Desk vs. Gorgias. Account for filters (spam, deleted) applied during extraction.
  • Message count per ticket. Spot-check 20–50 tickets. Verify thread count + comment count in Zoho = message count in Gorgias.
  • Timestamps preserved. Verify created_datetime on messages matches original Zoho thread timestamps. Sorting by date should reconstruct the conversation in correct chronological order.
  • Attachments render. Open 10–20 tickets with attachments. Verify images display and files download successfully.
  • Inline images load. Check HTML-heavy threads for broken <img> references — specifically any src still pointing to desk.zoho.com.
  • Custom field values populated. Verify ticket fields and customer fields match source data on spot-checked records.
  • Customer deduplication. If customers existed in Gorgias before migration (from Shopify sync), verify tickets are linked to the correct customer — not to newly created duplicates.
  • Tags applied. Verify department tags, status tags, and custom field overflow tags are present and filterable in Gorgias Views.
  • Shopify order links set. For e-commerce teams, verify that the integrations field on historical tickets contains the correct Shopify order IDs where applicable.
  • Agent attribution correct. Spot-check that ticket assignees and message authors reflect original Zoho agents, not the API import user.
  • OAuth tokens still valid. If you extracted across multiple days, verify the final extraction day's data is complete — not silently truncated by a token expiry.

When to DIY vs. Use a Managed Migration Service

DIY is viable when:

  • Fewer than 10,000 tickets with under 25 meaningful custom fields
  • No heavy reliance on Zoho Desk Accounts/Organizations for B2B routing
  • A developer can commit 2–3 weeks of focused engineering time
  • Partial fidelity is acceptable (e.g., inline images can render as broken for historical tickets)
  • Simple Zoho Desk configuration with no Blueprints or multi-department SLA workflows

A managed service makes financial sense when:

  • 50,000+ tickets with full thread, attachment, and inline image fidelity required
  • Complex custom fields, Blueprints, or multi-department routing that must be replicated in Gorgias Rules
  • Concurrent import required while live support continues (zero-downtime cutover)
  • Previous DIY attempt hit data integrity issues or API throttling failures

Cost model framing: A production-grade ETL pipeline for this migration requires building: OAuth token refresh, API pagination, rate limit backoff with header parsing, HTML sanitization and image rewriting, S3/R2 attachment hosting, delta sync with upsert logic, and a local ID mapping store. At a fully-loaded engineering rate of $150/hour, 80–120 hours of development plus 2–3 weeks of monitoring costs $12,000–$18,000 before QA. This is the breakeven threshold against which to evaluate any managed migration service quote.

If you've compared other migration paths, our guides on Zoho Desk to Zendesk, Zoho Desk to Freshdesk, and Zoho Desk to Intercom cover how those platforms handle the same source data differently.

What to Expect After Go-Live

The first 48 hours post-migration are when most issues surface:

  • Agents can't find old tickets. Gorgias's department-scoped views don't exist natively — agents accustomed to Zoho Desk's department silos need to learn Views and tag-based filtering. Build and share the equivalent Views before go-live, not after.
  • Shopify customer merge conflicts. If Gorgias auto-created customer records from your Shopify store, migrated Zoho contacts with the same email will return existing records (HTTP 200) rather than create new ones. Test this during the pilot batch to confirm your ID mapping logic handles 200 responses correctly.
  • Reporting baseline reset. Gorgias's built-in analytics only cover data created in Gorgias. Historical Zoho Desk metrics — SLA compliance rates, first-response time distributions, resolution time by category — will not carry over as computed values. Export all Zoho Desk reports before decommissioning the instance, and store them externally.
  • Automation gaps. Gorgias Rules do not auto-populate from Zoho Desk Blueprints and Workflow Rules. Identify your top 10 highest-volume automations in Zoho Desk (by tickets affected per day) and rebuild those as Gorgias Rules before go-live. Lower-priority automations can be built iteratively post-launch.
  • Webhook reconfiguration. If your Zoho Desk instance sent webhooks to internal tools (CRMs, ERPs, BI platforms), reconfigure those integrations to consume Gorgias webhooks. Gorgias's webhook system triggers on ticket created, updated, message created, and customer created events.

Frequently Asked Questions

Does Gorgias have a native importer for Zoho Desk?
No. Gorgias has a built-in importer for Zendesk only. Zoho Desk to Gorgias migrations require API-to-API scripting, a third-party migration tool, or a managed migration service.
Does Zoho Desk CSV export include ticket threads and comments?
No. Zoho Desk's CSV export (Setup → Data Administration) exports ticket metadata only — it does not include threads or comments. You need the Data Backup feature or the REST API to extract full conversation history.
How long does a Zoho Desk to Gorgias migration take?
For a typical 50,000-ticket migration, expect 2–3 weeks end to end, including script development, extraction (constrained by Zoho's daily API credit limits), import (constrained by Gorgias's rate limits), delta sync, and validation.
How do Zoho Desk ticket statuses map to Gorgias?
Gorgias has only two API-level statuses: Open and Closed. Zoho Desk's Open and Escalated map to Open. On Hold and Closed map to Closed. Custom statuses should be preserved as tags for post-migration filtering.
What Zoho Desk data cannot be migrated to Gorgias?
Activities (Tasks, Calls, Events), Blueprints, Products, and the full Account/Organization hierarchy have no direct Gorgias equivalent and cannot be migrated as-is. Account names can be stored as customer tags or metadata.

More from our Blog

Zoho Desk to Zendesk Migration: The CTO's Guide
Migration Guide/Zendesk/Zoho Desk

Zoho Desk to Zendesk Migration: The CTO's Guide

Complete guide to migrating Zoho Desk to Zendesk — API limits, object mapping, threading, attachments, and step-by-step architecture for CTOs and engineers.

Raaj Raaj · · 26 min read