Help Scout → Zendesk
Export Help Scout conversations through the Inbox API, then create them with Zendesk's ticket import so closed history can go straight to the archive. In-app reports do not include thread text.
Should you make this move?
Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.
Help Scout
- Shared inboxes, Docs, and Beacon keep email support and self-service in one desk
- Tickets, customer context, knowledge, automation, and service reporting share one operating system
- Import2 skips users, workflows, and the knowledge base, and a full archive leaves through the API
- Conversation visibility, routing logic, SLAs, and reporting history are hard to reproduce exactly
Zendesk
- Mature ticketing, omnichannel support, help centers, routing, SLAs, and ecosystem depth serve complex teams
- Tickets, customer context, knowledge, automation, and service reporting share one operating system
- Customization, administration, licensing, and source-specific ticket semantics make migrations demanding
- Conversation visibility, routing logic, SLAs, and reporting history are hard to reproduce exactly
Zendesk: Mature ticketing, omnichannel support, help centers, routing, SLAs, and ecosystem depth serve complex teams. This removes a major source-side concern: Import2 skips users, workflows, and the knowledge base, and a full archive leaves through the API.
What you lose: Shared inboxes, Docs, and Beacon keep email support and self-service in one desk. What you inherit: Customization, administration, licensing, and source-specific ticket semantics make migrations demanding.
Jump to a section
Know the shape of the move.
This timeline assumes
- A Zendesk admin calls the ticket import API. Help Scout history leaves through the Inbox API. Help Scout says that API is the only way to get data that is not in the report exports.
- You pass status=all. The list defaults to active, newest first. embed=threads truncates chat, so full Beacon threads come from the List Threads endpoint.
- You tag imported Zendesk tickets and keep them out of SLA reports. Zendesk says metrics and SLAs on imported tickets are inaccurate.
- The site already documents Zendesk → Help Scout, which is the Import2 path in the other direction. This direction is an API build.
What survives the move.
“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.
| Item | Outcome | Impact | What happens | Mitigation |
|---|---|---|---|---|
| Thread text in reports | lost | critical | Help Scout can export All Channels, Email, Company, and Happiness reports as CSV or XLSX. Those exports exclude conversation thread contents. Everything else is API-only. | Use the Inbox API for customers, users, and conversations. Use the Docs API for articles. |
| Customer CSV | partial | high | Help Scout can email Account Owners a CSV of customer names and emails on request. That file has no conversation history. | Use it as a contact check. Do not treat it as the ticket archive. |
| Default list filter | partial | critical | List Conversations returns active conversations unless you pass status. status=all is the call that asks for everything. You can also filter by mailbox, folder, tag, and modifiedSince. The sample response is paged. | Page through status=all. Write down the last page you stored. |
| Chat threads on the list call | partial | high | Help Scout says embed=threads on the list truncates chat threads on purpose. Full Beacon chat threads come from List Threads for that conversation. | Call List Threads when the conversation type is chat. |
| Zendesk timestamps | partial | medium | Ticket import can set solved_at, updated_at, and created_at. A created_at or updated_at before 1970 is rounded up to 1970. A comment created_at cannot be before 1970 or in the future. | Clamp dates before you post. Keep the original timestamp in a comment if you had to change it. |
| Closed tickets and the archive | partial | high | archive_immediately true sends a ticket created as closed straight to the archive. Zendesk says to consider it when you are importing 750,000 or more historical tickets and do not want that history to affect active tickets. Archived tickets have extra limits, which Zendesk documents separately. | Use it for closed history once you have read those archive limits. Leave recent closed tickets unarchived if agents must edit them. |
| Triggers, metrics, and mail | partial | critical | Triggers do not run when you import a ticket that is not closed. They run again if someone updates that ticket later. Metrics and SLAs are not supported and will be wrong. Zendesk says to tag imported tickets and exclude them from reports. CCs are not notified on import. Later updates can notify. | Tag every import. Exclude that tag from SLA reports. Avoid updates that would fire triggers until you mean to. |
| Bulk size | manual | medium | POST /api/v2/imports/tickets creates one ticket and is for admins. POST /api/v2/imports/tickets/create_many accepts up to 100 tickets and returns a job you poll. | Batch by 100. Store the job id until the job status is completed. |
| Status words | manual | high | Help Scout's table, read from the Zendesk column back, pairs Active with Open, Pending with On-hold, and Closed with Solved or Closed. Zendesk has both Solved and Closed. Closed plus archive_immediately is the path into the archive. | Map Active to open, Pending to hold, and pick solved or closed for Help Scout's Closed. Write the choice down. |
| Workflows, Docs, and users | manual | high | The export article does not offer a workflow or saved-reply file. Docs are a Docs API project. Zendesk agents are not created by the ticket import. Attachments on Zendesk follow the normal ticket upload: upload the file, then pass the token on the comment. | Create agents first. Copy workflows by hand. Upload files before the comment that needs them. |
Where each thing goes.
| Source | Destination | Method | Notes |
|---|---|---|---|
| Conversation | Imported ticket | transform | Inbox API, then Zendesk ticket import. Tag it. |
| status=all | Full set | manual | Without status, the list is active only. |
| Active | open | transform | Help Scout's table pairs Active with Zendesk Open. |
| Pending | hold | transform | The table pairs Pending with On-hold. |
| Closed | solved or closed | manual | closed with archive_immediately goes to the archive. |
| Thread | Comment | transform | Use List Threads when chat would be truncated. |
| Customer | requester_id | manual | Create or match the Zendesk user before the ticket. |
| Help Scout user | author_id on a comment | manual | The agent must exist in Zendesk. |
| Report CSV | No destination | unsupported | No thread text. |
Make the move recoverable.
Create the source-of-truth backup
Store a paged API archive before you post anything to Zendesk.
- Call List Conversations with status=all and page until the end.
- Call List Threads for chat conversations.
- Save customer ids and emails beside the conversations.
- Keep Help Scout forwarding unchanged until a Zendesk sample looks right.
Proof to capture: The page count, the raw JSON, and a sample ticket id in Zendesk are stored.
Full conversation pull
Avoid the active-only default and truncated chat.
- List conversations with status=all.
- Page to the end and store each page.
- For chat, call List Threads instead of trusting embed=threads.
- Download Docs with the Docs API if articles are in scope.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Ticket import batches
Create history without SLA noise or trigger mail.
- Create requesters and agents first.
- Post up to 100 tickets per job. Tag them imported.
- Set archive_immediately only for closed tickets you have decided to archive.
- Poll the job. Exclude the tag from SLA reports.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
The things most likely to hurt.
These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.
The list is active only
The call omits status.
- Consequence
- Closed and pending history never leaves Help Scout.
- Mitigation
- Require status=all in the client.
Stop if: A closed conversation you know about is missing from the archive.
Imported tickets enter SLA reports
The imported tag is missing or still included in a report.
- Consequence
- Zendesk says those metrics will be incomplete and inaccurate.
- Mitigation
- Tag every ticket and exclude the tag.
Stop if: A production SLA report still includes the tag.
An update fires triggers
Someone edits an imported ticket that was not closed.
- Consequence
- Triggers resume on that update, and a later update can also notify CCs.
- Mitigation
- Leave imported tickets alone until triggers are scoped to skip the tag.
Stop if: You need to bulk-update imports before those triggers are excluded.
Do the work in this order.
- Days 1 to 3 · inventory
Mailboxes and status map
4 to 8 hours active2 to 3 days elapsedAPI credentials waiting- List inboxes.
- Write the status map.
- Create Zendesk agents.
Depends on: Help Scout API access and a Zendesk admin
Stop / go checkpointPull history?
Go when: status=all is the documented call and agents exist.
Stop when: You only have the report export.
- Days 3 to 8 · backup
Page the API
6 to 12 hours active3 to 5 days elapsedPaging waiting- Save every page.
- Save chat threads.
- Save the customer CSV as a side check.
Depends on: Credentials
Stop / go checkpointIs the archive complete?
Go when: A known closed conversation is in the JSON.
Stop when: The client used the default status.
- Days 8 to 12 · pilot
One batch
4 to 8 hours active2 to 4 days elapsedJob status waiting- Import 100 tickets.
- Check tag, dates, and comments.
- Exclude the tag from a test report.
Depends on: Archive
Stop / go checkpointImport the rest?
Go when: The batch matches Help Scout and the report excludes it.
Stop when: A comment date was moved and you did not record the original.
- Days 12 to 16 · cutover
Remaining batches, then mail
4 to 8 hours active2 to 4 days elapsedJobs and forwarding waiting- Finish create_many jobs.
- Switch forwarding after the last page is in.
- Stop Help Scout replies.
Depends on: Passed batch
Stop / go checkpointZendesk owns new mail?
Go when: A new message arrives in Zendesk and the last job completed.
Stop when: A job is still queued.
- Days 16 to 23 · observe
Watch triggers
3 to 5 hours active5 to 7 days elapsedA week of updates waiting- Confirm SLA reports exclude the tag.
- Watch for trigger mail on edits.
- Keep the JSON archive.
Depends on: Cutover
Stop / go checkpointClose Help Scout sending?
Go when: New mail is in Zendesk and imported tickets are out of SLA reports.
Stop when: An edit notified a customer by surprise.
Cut over with a way back.
Cutover
Finish the import jobs, then point new mail at Zendesk.
- Confirm the last status=all page is stored and imported.
- Confirm the imported tag is excluded from SLA reports.
- Switch forwarding to Zendesk.
- Stop replies in Help Scout.
- Send a test message and open one old conversation beside its ticket.
Proof to capture: The test message is a Zendesk ticket, and a known closed Help Scout conversation has a matching imported ticket.
Rollback
Send mail back to Help Scout if the import is partial or triggers misbehave.
- Point forwarding back at the Help Scout inbox address.
- Stop bulk updates of imported Zendesk tickets.
- List tickets created only in Zendesk since the switch.
- Review those before you copy them into Help Scout.
- Keep the JSON archive. The report CSV cannot replace it.
Proof to capture: New mail is in Help Scout, and Zendesk-only tickets are listed.
- A known closed conversation is missing
- Chat text is truncated
- SLA reports include the imported tag
- An update sent mail you did not expect
- A create_many job failed and was not rerun
Prove the migration worked.
Every blocking check must pass. Capture the evidence before cleanup begins.
| Pass | ID | Check | Method | Expected result | Evidence |
|---|---|---|---|---|---|
V-01Blocking | status=all | Read the request URL. | status=all is present and pages are stored through the end. | Request log. | |
V-02Blocking | List Threads | Open a Beacon conversation in the archive. | The thread body came from List Threads, not a truncated embed. | JSON sample. | |
V-03Blocking | 1970 clamp | Search for timestamps you changed. | Originals are recorded wherever Zendesk would have rounded or rejected them. | Date log. | |
V-04Blocking | Job status | Poll each create_many job. | Each job completed, and no batch was over 100. | Job ids. | |
V-05Blocking | imported | Search Zendesk for the tag and open an SLA report. | Every import has the tag, and the report excludes it. | Report definition. | |
V-06Blocking | Map | Compare Active, Pending, and Closed samples. | open, hold, and the solved or closed value you wrote down. | Sample tickets. | |
V-07Blocking | archive_immediately | Read the query string on closed batches. | It is true only for closed tickets you chose to archive. | Request log. | |
V-08Blocking | Forwarding | Send to the public address after the switch. | The message is a new Zendesk ticket. | Test email. |
Remove the scaffolding safely.
Safe after: The last import job completed, new mail lands in Zendesk, and SLA reports exclude the imported tag.
- Keep the JSON archive through the rollback window.
- Leave Help Scout readable.
- Scope triggers so an edit to an imported ticket does not surprise a customer.
- Rebuild workflows and Docs that the export does not package.
- Store job ids with the status map.
- Schedule a second look at any closed tickets you did not archive.
Verify against the primary material.
Platform behavior changes. Check these sources and the review dates above before executing a production migration.
- Help Scout: data export optionsAccessed 2026-11-04
- Help Scout: list conversationsAccessed 2026-11-04
- Zendesk: ticket importAccessed 2026-11-04
- Help Scout: switching help desksAccessed 2026-11-04