Combining Harvest and QuickBooks Exports
Your hours are in one system and your invoices in another, and every useful services metric needs both. The join is the whole job, and it fails in five predictable places.
Every metric worth having in a services firm needs both sides of this join. Realization needs hours and invoices. Project margin needs cost and invoices. Effective rate needs both. And the two live in different systems that have never agreed on how to spell a client name.
Getting the two files
Harvest. Reports, then Time, set the date range, then Export and choose the detailed CSV. You get roughly:
Date, Client, Project, Task, Person, Notes, Hours, Billable?, Billable Rate, Billable Amount
The Client column is the important one and it is why Harvest is pleasant to work with here — many time exports carry only a project, which leaves you resolving projects to clients before you can do anything.
QuickBooks. Reports, then Sales by Customer Detail, or the Invoice List, exported to Excel. You want line detail rather than totals, for the reason covered in the realization piece: an invoice total carries neither hours nor rate, so half your metrics die with it.
Save both as CSV in one folder with a consistent naming pattern. harvest-2026-08.csv and qbo-2026-08.csv is enough; what matters is that next month looks the same, because a Power Query refresh points at a path.
The join key
Two candidates, and you usually get the weaker one.
- Project. Precise, and frequently absent on the accounting side, where a month of work for a client goes out as one invoice with a description rather than a project code.
- Client. Always present on both sides, coarser, and good enough for realization, effective rate and margin at client level.
Join on client unless both files genuinely carry the project. If you want project-level answers permanently, the durable fix is in QuickBooks rather than in Excel: put the project code at the front of every invoice item description, or use Customer:Job so the job carries through to the export.
The mapping table, which is the actual work
Harvest says Acme Ltd. QuickBooks says Acme Limited. Somebody typed ACME in 2024. No formula fixes this, so make it explicit:
HarvestClient QBOCustomer CanonicalClient Acme Ltd Acme Limited Acme Bright & Co Bright and Co. Bright Northwind Northwind Trading Northwind
Then map both sides to CanonicalClient and join on that. It is twenty to fifty rows for most firms and an afternoon of work, and it is the thing that makes the report survive into next month instead of being rebuilt.
Resist fuzzy matching. It works until it silently merges two clients with similar names, and by then the figures have been in three board packs.
The merge in Power Query
- Data, Get Data, From File, From Text/CSV for each of the three files — Harvest, QuickBooks, and your mapping table. Load each as a connection only.
- On the Harvest query, Merge Queries with the mapping table on
ClienttoHarvestClient, and expandCanonicalClient. Do the same on the QuickBooks side withQBOCustomer. - Add a month column to each: Add Column, Date, Month, Start of Month.
- Group each side to the grain you want — canonical client, month — and sum hours on one side and invoiced amount on the other.
- Merge the two summaries on client and month, using a full outer join, then expand.
The full outer join matters. An inner join drops any client that appears on only one side, which is exactly the case you most need to see: hours logged with nothing invoiced. An inner join makes that problem disappear from the report rather than showing it, which is a general hazard when joining files and not specific to these two.
If Power Query is unfamiliar, the merging CSV files walkthrough covers the same mechanics on a simpler example.
Five reasons the totals will not agree
They will not agree, and four of the five reasons are legitimate:
- Timing. August work invoiced in September. Real, and the reason hours bucket by work date and invoices by invoice date.
- Unbilled hours. Non-billable time, written-off time, and work in progress not yet invoiced. Real, and often the most useful thing in the whole report.
- Credit notes. Negative invoice lines that reduce the invoiced side with no hours behind them.
- Retainers. An invoice covering work not yet done, so the invoice arrives before the hours.
- Name mismatches. The only one that is a genuine defect, and the mapping table is the fix.
Do not force the two sides to agree. Report the difference as a column and label it, because the difference is the finding.
Or skip the join
The reason this is fiddly is that you are doing a database join in a spreadsheet, monthly, by hand.
Quiriz takes both exports as separate uploads and resolves the relationship between them when you ask a question, so realization rate by client reads across both files without a merge step. You still need the client names to line up — that is a fact about your data, not about the tool — but the mapping is a dataset you upload once rather than a query you rebuild.
The judgement call: if you do this join once a quarter, Power Query is genuinely fine and free. If you do it every month and other people ask you for slices of it, the joining is not the expensive part — the being asked is.
Ask across both exports without merging them first
Upload your time and invoice exports and ask for realization, effective rate or margin by client in plain English. Free to start.
Try Quiriz free →