Support Ticket Export Template
Four documents and four sheets that recover the ticket fields a CSV export drops, then prove which reported numbers were wrong.
Free download · No account needed
Restated Figures
Redbourne, Q2 2026, CSV report pulled 14 July
One quarter of a veterinary practice management help desk, reconciled against a JSON export of the same range and the ticket API. Illustrative figures for a fictional company.
The figure that passed review
| Untagged rate, from the Tags column | 1,547 | 14.9% |
| Untagged rate, from the Root cause field | 1,596 | 15.3% |
Half a point apart, so it was quoted with confidence and a remediation list was generated from it. They are not the same tickets.
| In both sets, genuinely untagged | 1,082 |
| On the list, field already populated | 465 |
| Field empty, hidden by a macro's tag | 514 |
| Rows where the two disagree | 979 |
Thirty percent of the work list is wrong, in both directions, and the two errors nearly cancel in the total.
| Reported figure | Reviewed | Actual |
|---|---|---|
| Largest root cause | Training | Data import |
| Open tickets at quarter end | 381 | 176 |
| Platform group volume | 1,611 | 2,823 |
| Urgent inside the 4-hour target | 70.8% | 63.7% |
| Resolved within the hour | 1,396 | 1,135 |
| Tickets handled in Q2 | 10,528 | 10,413 |
Nine figures moved. Every behaviour behind them is in the vendor's export documentation and none of it is visible in the file.
A help desk export looks like one dataset offered in a choice of formats, so everybody takes the one that opens in a spreadsheet. It is not one dataset. Zendesk's CSV report, its JSON export and its ticket API return different rows for the same date range, different fields, and different values for the same field on the same ticket. Every one of those differences is written down in Zendesk's own export documentation, and none of them is visible anywhere in the file.
This pack pulls the range every way the vendor offers, reconciles the pulls against each other row by row, and restates what you already published with the documented reason on each number that moved. Row by row is the part that matters. Two totals agreeing is not evidence they describe the same tickets, and it is the most common way a broken support figure survives review, because a plausible number is a number nobody investigates.
Redbourne sells practice management software to veterinary clinics. Its Q2 review reported 14.9% of tickets with no root cause recorded, counted from the Tags column because the multi-select field is not in a CSV. The real rate was 15.3%, so the figure was quoted with confidence, and 979 rows disagreed underneath it. Nine of Redbourne's figures moved, including which root cause was the largest in the quarter. None of them moved because anybody did anything wrong.
What's in the pack
Field Map
One row per field: its type, whether each export path returns it, whether it is history or a snapshot of right now, which pull to take it from, and what specifically breaks if it comes from the CSV. Build it before touching the data, because it is the one artefact that stays true after the data changes.
Ticket Register
The deliverable. One row per ticket, carrying the multi-select, multi-line text and custom date fields recovered from the JSON export. Durations arrive in native minutes instead of rounded hours, timestamps carry both clocks, and each snapshot field sits next to its value when the work was done.
CSV to JSON Reconciliation
An arithmetic bridge from what the file returned to the population the question was about, one line per named reason, balancing to zero. Nothing downstream is quotable until it balances. It also records the clock and pull moment for each path, since two pulls an hour apart are two datasets.
Restated Figures
The sheet anyone who read the original report needs. Per published number: the corrected value, the documented export behaviour that moved it, and whether the row sets agree. Ranked by consequence rather than by size of move, so the figure that changed a decision comes first.
Export Procedure
The three pulls, in order, with what each one is for and what to record about it. Widen the range by a month either side, take the cursor form of the incremental endpoint rather than the time-based one, and side-load the metric records in the same pass.
Field Completeness Note
Which fields each path omits and what a report loses per omission, including the four separate reasons a Tags column is not the multi-select field behind it. Pairs with the naming convention pack when the fix is the tag namespace rather than the report, and with the support ticket categorization template when the recovered field turns out to hold categories nobody can apply.
Measurement Definitions
Every reported figure with the timestamp that selects its rows, the clock it is computed on, the unit it comes from, and whether its field is history or a snapshot. The metric definitions pack does the same job across the whole business, and the SLA reporting template applies the same discipline to a breach rate specifically.
Reconciliation Findings
The worked example end to end: nine reported figures, what each one actually was, and the documented behaviour behind each move. Written so it reads as an explanation rather than an accusation against whoever built the original report.
How it works
- 1
Start from the report, then map the fields
Send the export you reported off and the deck that circulated. River reads your custom field list against what each export path carries and names what is missing from the file. On the worked example three of four custom fields were absent, and two were what the review was about.
- 2
Pull the range three ways, widened
The tabular report as the artefact under investigation, the structured export for the omitted fields and UTC timestamps, and the API with metric records side-loaded for durations in minutes. A month either side, because the range does not filter on creation.
- 3
Balance the row set before any figure
A bridge from the file to the population your question meant, one named reason per line, to zero. River reports the gross error ahead of the net one, since the net error is what let the report through and every breakdown inherits the swaps.
- 4
Compare sets by row, then restate
For each figure, the intersection and both differences rather than just the two numbers. Then each published number with its corrected value and the vendor's documented behaviour in one clause, ranked by which one changed a decision.
Frequently asked questions
Which fields does a Zendesk CSV export actually leave out?
Multi-line text, multi-select and custom date fields are excluded from CSV reports and available in the JSON and XML ones. Ticket comments, descriptions and deleted tickets are also absent by design. Read that list against your own custom field list, because it usually describes the fields your report is about.
Can I just count the Tags column instead of the multi-select field?
No, and it fails in four ways at once. Macros and triggers write into the same namespace without setting the field, a retired option leaves its tags behind, a renamed tag string splits one value in two, and tags are a snapshot at export time rather than history.
Why does my export return a different number of tickets than I expected?
The date range filters on a system-generated timestamp, normally the most recent update rather than the creation date, so a quarter-shaped range returns tickets touched in the quarter. Widen the pull and select on creation afterwards. Filtering the file you already have cannot recover rows it never returned.
Does this work with Intercom, or only Zendesk?
Both, and the differences matter. Intercom's dataset export carries reporting metadata without message content, filters on conversation created rather than last update, and captures user attributes as at the start of the conversation. That last convention is the inverse of Zendesk's, so a joined column holds two meanings.
Why are my resolution times different in every report?
A CSV report rounds Resolution time to the nearest whole hour and carries two more duration columns measuring different events. Take minutes from the incremental export API with metric records side-loaded. Where the target is written in business hours, compute it in the hours the policy defines, as the sales and marketing SLA pack does.
My totals reconcile. Is that enough?
No. Two totals agreeing is not evidence they describe the same tickets, and errors in opposite directions cancel. On the worked example an untagged rate was half a point out and 979 rows disagreed, so a third of the remediation list was wrong. Compare ticket ids, not counts.
Can I report group or assignee volume for a past quarter?
Not from the field. Group, assignee, status, priority, type and tags are the value at the time of export, so a reorg inside the period rewrites the table retrospectively. Take historical values from the audit or metric event history, or group by something historical instead.