How to import tickets into Zendesk using the API
I recently moved our brand in a multibrand Zendesk instance to our own instance.
We use our closed tickets as a knowledge base (did we have this error already? etc.), so we needed to import a lot of our existing tickets. About 99% of the tickets are in the closed state, so that got a lot of attention while figuring out how to migrate.
On Zendesk's own recommendation, I initially evaluated Helpdesk Migration as a service to import all of our tickets. I quickly came to the conclusion that while they offer an interesting service, we'd rather do it ourselves, because we had some special requirements.
So, I started to collect all of the requirements:
- export and import tickets and all of their associated objects, starting at the release date of our last supported release of the product we support using Zendesk.
- Since we cross-linked Zendesk tickets with our development issue tracker (JIRA), we required that the Zendesk tickets in the new instance can be identified knowing their ID in the old instance.
- there are some data security concerns, so we have to be able to map certain requesters, submitters, collaborators and followers to anonymous accounts.
- The imported tickets need to be high fidelity copies of the originals, including screenshots, images, attachments etc. etc.
That's the gist of it.
Researching the topics, I found a few special situations in the API:
- while it offers a ticket import endpoint with a special mode for closed tickets which does not fire triggers for those tickets, it always requires that requesters and submitters are active, not suspended. So, if you have tickets created by ex-employees who have been suspended after leaving the company, the API will balk.
- the API cannot handle empty comment bodies. It is easy to generate such a comment by sending a mail with an attachment, but no text to the Zendesk instance. So, it is more restrictive that the Zendesk client and server software.
- there is no mention of inline attachments (screenshots and images, for instance) in the API documentation. Fact is, while they have a link to the storage backend, those attachments have no attachment record.
- getting attachments onto a ticket works a bit different than downloading them: You upload the file, then get a token back for the upload (among other things). Note that that token is different from the token in the URL for the attachment (these are available in two flavors, branded (mapped_content_url; https://yoursubdomain.yourdomain.tld/..) and unbranded (content_url; https://yourZDaccount.zendesk.com/..) and have the relative path "./attachments/token/<token>/?name=<attachmentfilename.type>".
- you cannot re-cross-link merged tickets because the API does not offer some kind of ticket ID reservation which would be needed to implement this mapping (you need to have both ticket IDs available when commiting the first ticket, but you cannot have the ID of the second ticket at that time).
- There seems to be no support for side conversations in the import ticket endpoint at this time. So, either convert them to (internal) comments, or forget about them.
So, lots of things to consider.
There are some highlights as well, though: While the API documentation states that you need to upload the attachments with a suitable ContentType, in fact, it will check your content and return a suitable ContentType - at least as far as I can tell. Nice one!
I opted to use JSON as the exchange format for all but the attachments themselves.
You can do all the exports before starting the imports. You can interlace, if you are so inclined.
I came up with the following sequence:
export tickets and their comments resulting in ticket.json and comments.json per ticket in a directory tree export/<timestamp>/tickets/<ticketId>.
While exporting the tickets, gather all
- user Ids (requester, submitter, CCs, followers, collaborators, authors, ...)
- organization IDs
- group IDs
- ticket field IDs
- ticket form IDs
- dynamic content items
- design objects (ticket fields, forms, dynamic content, ...)
- master data (users, groups, organizations)
- attachments (both inline and "normal")
set up the new instance
- create the help center
- import or create design elements, always creating mapping tables (export ID, import ID) as csv files
fill the gaps: if you deleted users, groups, organizations involved in the tickets, you need a strategy to cope with this. Either you recreate these missing objects, or you map them to dummy objects.
Now, we're ready for the tickets:
upload all attachments
upload the tickets
These last two steps seem so simple, however, there's lots of details. This is when things like "requester needs to be active" help you make the migration a bit more, well, some may call it, interesting.
There's a lot to cover here when it comes to attachments and their URLs in the exported tickets. I found a lot of unexpected URLs (content_url instead of mapped_content_url and vice versa) in the content, and also some special cases (even attachment URLs from 3rd party Zendesk domains). However, it's up to you to generate a more consistent handling in your import code.
And then, there's some fine points that might be out of the migrator's control. In my case, Zendesk balked that it cannot parse the JSON. Well, the JSON I generated off those Powershell objects has been syntactically correct, however, I handed over the Powershell object directly, as I have done for all the imports and exports before. Well, saving the JSON and then feeding it to Zendesk worked without problems. So, good luck in that case, but a bit scary.
I started to migrate on the last weekend before Christmas, intending to finish everything by Sunday evening.
On New Year's eve, I finally finished things up...
I have implemented the migration code using Powershell core and bash scripts on a Linux OS. Powershell has been what I used to work with the Zendesk API before moving from Windows to Linux, and I didn't want to rewrite all the code right before the migration.
Would I do it that way again? Being in the consultancy business, the answer is obvious: It depends.
I would certainly like Zendesk to expand their API documenation a bit, including an example or two with non-trivial tickets, e.g. including inline and normal attachments etc.
I also suggested to Zendesk to either document or lift the API restrictions mentioned above.
Hope this helps others in a similar quest.
Hi Peter Hochstrasser. Thanks for this detailed post! A lot of great information here. We're planning on expanding our developer documentation to cover data migration in more detail later this year and next. I'll make a note to cover the examples you suggested, among other things. Thanks again!
Looking forward to it, Gary Beichler.