Skip to content

Importing tickets

Enterprise feature (new in 1.19.1, helpdesk). See the Helpdesk overview.

Desk settings → Import brings your history across from another helpdesk: tickets, their conversations and their contacts. It needs the desk capability Helpdesk settings (Admins, out of the box). Nothing is created until you confirm, and the import never emails anyone.

It works in four steps: Upload, Map, Dry run and Import.

Under Choose what you’re importing, pick one:

  • Zoho Desk export: the .zip from Zoho Desk’s data export or backup.
  • CSV file: a Tickets file (.csv), and optionally a Messages file (.csv, optional) with one row per message.

Then Upload and continue. Uploads can be up to 200 MB by default; an admin can raise Largest upload (MB) under Upload limit, up to 2048. Big files are read as they stream, so the server’s memory stays low.

The import recognises the files in the zip by name: Tickets (or Cases), Threads (or Conversations), Comments, Contacts, Agents and Departments. Split files such as Tickets_001.csv are read in order. Attachments are read from the zip’s attachments folder.

The tickets file has one row per ticket, with a header row. It needs a column for a Ticket id or Ticket number, a Subject and a Created date. It can also have: Description, Status, Priority, Department or team, Owner (agent) name or email, Requester name and email, Closed or solved, Tags, Category and Channel.

The messages file has one row per message: the Ticket id it belongs to and the Message text, and optionally the author’s name and email, Sent, Public or private, and Author type (agent or customer) or Direction (in or out). Without either of those, a message from a known agent’s email counts as the agent’s.

Columns shows which column holds each part of a ticket, recognised from the headers. Change one only if it picked the wrong column.

Then match what the export says to your helpdesk:

  • Departments → teams: each department’s tickets go to an existing team, to a new team the import creates, or to No team.
  • Statuses: each status becomes one of yours, optionally with a tag to keep what it said (Escalated becomes Open with the tag “escalated”).
  • Priorities.
  • Agents: matched to accounts by email. An agent with no account shows as Former agent on their replies, and their tickets come in unassigned. An agent is made the assignee only if they can work the ticket’s team.
  • Requesters and dates: whether a date like 03/04/2026 means Month first (March 4) or Day first (3 April) (detected for you), and the Time zone of the export’s times for times written without one (the helpdesk’s time zone by default).

Requesters are matched to accounts by email. Anyone else keeps their name and email on the ticket, as an outside sender.

Saving the mapping keeps what you chose: the columns, Not in the file for a column the import guessed (from 1.19.2 it stays chosen instead of being guessed again), and the source name below. It reads the export again only when you change a column or attach a messages file. That second read runs in the background, as Reading your export again, and can’t be stopped.

For a CSV file, Where these tickets come from names the system the file came from (the file’s name, unless you change it). Ticket ids are kept per source: use the same name when you import from that system again, so its tickets are updated, not duplicated, and a different name for another system, so two systems’ ids never overwrite each other. The dry run says when tickets were “already imported from” that name.

Run the dry run counts what the import would do, without writing anything. From 1.19.2 it runs in the background: Checking your export shows a progress bar, the tickets (then conversations) checked so far, the time left (“about 3 minutes left”), and the counts so far (To create, To update, Contacts matched and Skipped so far).

You can leave the page. The bell tells the person who started it when the dry run is ready, or if it failed (Import checks in their notifications). Stop ends a dry run that is running; nothing was written, and you are back at the mapping.

When it’s done, the page shows:

  • tickets to create, and those already imported that would be updated;
  • contacts matched to people in the directory, and contacts kept as outside senders;
  • rows skipped, with see why: a CSV of every skipped row and its reason (up to 5,000 rows);
  • replies, internal notes, attachments and new teams.

The mapping summary says how numbers work: each ticket gets the next number in your helpdesk, and its old number is kept as Zoho #1201 (or Imported # for a CSV) and shown on the ticket.

Back to mapping to change something, or Import N tickets to go.

A dry run always uses an up-to-date read of the export. If reading the export with new columns or files failed, the dry run won’t use the old read: “The export hasn’t been read with these columns and files yet. Save the mapping to read it again, then run the dry run.” Saving the mapping again reads it, then the dry run works. The first read, when you upload, still happens straight away, so an upload problem shows on the form.

The import runs in the background, with its progress on the page. You can leave the page.

  • Stop import stops after the current batch. What was imported stays.
  • Resume import carries on from the last row it finished.

When it is done, the page shows the tickets created and updated, replies and notes, and rows skipped (Download the list).

What the import keeps, and what it doesn’t do

Section titled “What the import keeps, and what it doesn’t do”
  • Kept: created, solved and closed times; each message’s author and time; the source’s channel; the old ticket number.
  • Not run: no email, notification, assignment, automation, rule or workflow runs for an imported ticket, and no system lines are added.
  • Reply targets: solved and closed tickets get none. Open tickets start their targets at the time of the import, on their team’s calendar, and tickets waiting or on hold start paused. If the source shows an agent already replied, the first reply counts as made.
  • Text: HTML is turned into safe text, and images become links. In a Zoho export, a ticket’s description repeated as its first message is imported once.
  • Attachments come in when the file is in the zip and the helpdesk’s usual type and size rules allow it, up to 10 per message. A file is taken only from a folder named exactly for its own ticket’s or message’s id, or from the exact path the row names, never from another ticket’s folder. A file that isn’t imported is named in a note on its message, with the reason.

An import is safe to run again with a newer export of the same helpdesk (for a CSV, under the same source name). Tickets already imported are updated, not duplicated, open tickets keep their reply targets, and files are never doubled.

A ticket anonymised since it was imported is never written again: it and its messages are skipped, and the skipped-rows list says “This ticket was anonymised in CompassDocs, so it isn’t imported again”.

Only one import from each source runs at a time.

Recent imports lists earlier imports. Discard deletes an import’s uploaded file; tickets it already imported stay. Uploaded files are deleted when an import finishes, or after 7 days.

Action Shown as
helpdesk.import.started Started a ticket import (with the dry run’s counts)
helpdesk.import.completed Finished a ticket import (with the counts)
helpdesk.import.cancelled Stopped a ticket import
helpdesk.import.check_started Started checking a ticket import (1.19.2: a dry run, or reading the export again)
helpdesk.import.check_stopped Stopped checking a ticket import (1.19.2)

Teams the import creates are recorded as helpdesk.team.created, and a change to the upload limit as helpdesk.settings.updated.

The page uses the same API an admin’s script can call (desk capability Helpdesk settings). From 1.19.2 the dry run doesn’t answer with its counts:

  • POST /api/helpdesk/admin/import/<id>/dry-run answers 202 at once, with the job in status checking.
  • Poll GET /api/helpdesk/admin/import/<id> until the status is ready (the counts are in dry_run), or back to uploaded with the reason in check.error. check.progress holds how far it has got.
  • POST /api/helpdesk/admin/import/<id>/stop-check stops a dry run.
  • A dry run on an out-of-date read of the export answers 409.

A script written for 1.19.1, which read the counts from the dry run’s own answer, must poll instead.