← Tahona Billing Pilot enquiries Pilot sign in
Docs · Pilot release 0.4

Running a month in Tahona Billing.

One month in, one invoice per client out. This page covers the setup you do once, the export you make each month, what the close does with it, and what posts to QuickBooks. Everything here names the screens as they appear in the product.

Ten minutes to a priced month.

Pilot workspaces are set up by us. You get an email with a link to choose your password; after that, sign in at the link above. You land on the close page with a Continue setup banner that opens the four-step setup. Any order works; nothing waits on QuickBooks.

  1. Your company Company name, billing email, address, and the invoice prefix (two to eight letters or digits). These print on every invoice. The prefix locks once the first invoice is issued; the rest can change in Settings.
  2. First client and rate card Pick the client you bill most. The form starts from the four charges every 3PL has: pallet storage (prorated daily, or a snapshot on the first), receiving per pallet, pick and pack per order with a number of units included, and the additional-unit rate, plus a monthly minimum. The These rates apply from date defaults to the first of last month, so the month you import next prices in full. Move it earlier if you will import older months; a later version cannot start before this one.
  3. Create a source Under Activity imports, New source, name the system (ShipStation, Shopify, your WMS) and upload one export. The editor reads its column names and guesses which is the client, the date, the quantity, the units per order, and the reference. Fix anything it guessed wrong once; the mapping is saved for every month after. See the export guides below for the exact choices.
  4. Import a month Choose the source, the billing month, and the file. The engine prices storage by the day and applies minimums per month, so import the whole month, not a partial file. A second file from the same source for the same month replaces the first.
  5. Price On Monthly close, press Price this month. You get a run total, a draft invoice per client, and the exceptions: every row the engine could not bill and why.
  6. Clear exceptions Each exception has a one-click fix. Unknown client: map the name to an existing client (it becomes an alias); for a new client, add it under Clients and rate cards first, then map. No rate: add the missing rate to the card in force, or waive the rows with a reason. Quantity outlier: read it and keep it with a note. The close will not issue with an open exception.
  7. Mark reviewed Read each invoice against last month (the vs column) and click into any line to see the activity rows behind it. Then Mark reviewed.
  8. Issue Issue N invoices assigns numbers (PREFIX-2026-09-0001), renders a PDF per client with a usage appendix, locks the run, and posts to QuickBooks if connected. Issued runs are immutable; corrections go on next month's run.
  9. Send Download the PDF from Invoices, or let QuickBooks send it (see below). The Leakage report shows what you recovered this month and what is still open.
Why last month first. A 3PL's first close is always the month that just ended, and a rate card version can never start before the latest one. That is why the first rate card defaults to the first of last month, and why the close page opens on last month.

What to export, and how to map it.

Version one imports CSV. Each source has a saved column mapping: which column is the client, the date, the quantity, and so on. A charge code and a unit can come from a column or be the same for every row in the file. Dates need a format; the three below are the common ones.

ShipStation: Shipments export

Shipments → Export. One row per shipment; the Items column is the unit count, which drives the included-units and additional-unit charges.

Mapping fieldChooseNote
Client nameStoreEach store name becomes a client alias the first time you map it
Activity dateShip Date, format M/d/yyyyUS format as ShipStation writes it
QuantityItems
Units per orderItemsSame column: one order, N units
ReferenceOrder #Prints in the usage appendix
Charge codeThe same for every row: pick.order
UnitThe same for every row: orders

Shopify: Orders export

Orders → Export → CSV. Shopify writes one row per line item. Filter to fulfilled orders before exporting: an unfulfilled order has an empty Fulfilled at, and the import refuses the whole file at the first blank date, naming the row. An order with several line items exports as several rows and prices as several orders; prefer the ShipStation export when you have it, or consolidate rows by Name first.

Mapping fieldChooseNote
Client nameVendorWhen each client is a vendor in one store; use a separate export per store otherwise
Activity dateFulfilled at, format yyyy-MM-dd HH:mm:ss zzzShopify includes the time zone
QuantityLineitem quantity
Units per orderLineitem quantity
ReferenceNameThe order number, like #2101
Charge codeThe same for every row: pick.order
UnitThe same for every row: orders

A warehouse system's activity export

Most WMS exports carry an activity or transaction code per row. Map it as the charge code column, then tell the source what each of your codes means (code aliases): PLT-IN → receive.pallet, PICK → pick.order, and so on. Unknown codes show up as No rate exceptions with the raw text, so you can add the alias and re-price.

Mapping fieldTypical columnNote
Client nameClient
Activity dateActivity Date, format yyyy-MM-ddChange the format to match the file
Charge codeFrom a column: ActivityPlus code aliases
QuantityQty
UnitFrom a column: UOMSee the unit spellings below
ReferenceRef
Pallet counts by hand. If nothing exports a daily pallet count, put it in the spreadsheet template: one storage.pallet.month row per day with the pallets on hand that day. The engine adds up the daily rows and divides by the days in the month; it never carries a count forward, so a month with only three count rows bills three days of storage. If you count less often, repeat the last count for each day until the next count.

One sheet that imports cleanly.

For activity no system exports (pallet counts, kitting hours, returns), or for a 3PL whose whole month lives in a workbook. The columns are the importer's own, the codes are the seeded catalog, so the mapping editor recognises every column and the import lands with zero unresolved rows. The example month carries thirty daily pallet counts (38 pallets, then 40 from the 25th), which is what prorated storage needs.

Download the template (CSV)
client,date,code,quantity,unit,child_quantity,reference
HARBOR,2026-09-01,storage.pallet.month,38,pallet,,Pallet count 1 Sep
HARBOR,2026-09-02,storage.pallet.month,38,pallet,,Pallet count 2 Sep
…one storage row for every day of the month…
HARBOR,2026-09-03,receive.pallet,5,pallet,,Receipt 7
HARBOR,2026-09-02,pick.order,1,order,3,#1001
HARBOR,2026-09-09,returns.unit,4,each,,RMA 14
HARBOR,2026-09-15,labor.kitting.hour,1.5,hour,,Kitting WO 3
ColumnWhat goes in it
clientThe client's name or any alias you have given it (HARBOR, Harbor Goods Co.)
dateThe day the activity happened, yyyy-MM-dd
codeA charge code from the table below, or one of your custom codes
quantityHow many units. Decimals are fine (1.5 hours). For storage, the pallets on hand that day, one row per day
unitWhat the quantity counts: pallet, carton, each, order, hour, or any spelling in the unit table
child_quantityOnly on pick.order rows: the units in that order. Leave empty otherwise
referenceOrder number, receipt, RMA, work order. Prints in the usage appendix so a client can check any line

Save as CSV (UTF-8) and import it like any other source. Rows dated outside the billing month are ignored and counted on the close page.

The fourteen codes every 3PL bills.

Seeded in every workspace. Add your own under Settings, Charge catalog; custom codes are lowercase dotted names like labor.assembly.hour.

CodeNameCategoryDefault unitWhat counts as one
storage.pallet.monthPallet storageStoragepalletsPallets on hand on a day; the engine prorates by the day or snapshots on a day you choose
storage.pallet.dayPallet storage, dailyStoragepalletsPallet-days billed as counted, no proration
storage.bin.monthBin storageStoragebinsBins on hand
storage.cuft.monthCubic foot storageStoragecu ftCubic feet on hand
receive.palletReceivingHandlingpalletsPallets received
receive.cartonReceivingHandlingcartonsCartons received
receive.unitReceivingHandlingunitsUnits received
pick.orderPick and packHandlingordersOne shipped order; the rate card says how many units are included
pick.unit.additionalAdditional unitsHandlingunitsUnits beyond the included count; derived from the order's unit count, never imported
pack.cartonPackagingPackagingcartonsCartons packed or supplied
returns.unitReturns processingReturnsunitsUnits returned and processed
labor.hourLaborLaborhrGeneral labor by the hour
labor.kitting.hourKitting laborLaborhrKitting or assembly by the hour
minimum.monthMonthly minimumMinimumNever imported: the engine adds the shortfall when a client is under the minimum

Spellings the importer understands.

Case does not matter. A row whose unit does not match the rate line's unit is an exception, never a silent conversion.

UnitAccepted spellings
Palletpallet, pallets, plt, skid
Binbin, bins
Cubic footcubicfoot, cubic foot, cubic feet, cuft, cu ft, ft3
Cartoncarton, cartons, ctn, case, cases
Eacheach, ea, unit, units, pc, pcs, piece, pieces
Orderorder, orders, shipment, shipments
Hourhour, hours, hr, hrs

Issue here, invoice there.

Connect once from Settings, QuickBooks Online, Connect QuickBooks Online. Intuit asks you to sign in and pick the company; you land back in Settings connected. The first connect creates one service item, Tahona Billing services, under your first income account; every invoice line references it and carries the charge description.

  1. Per client: draft or send On a client's page, Edit details, Invoices to QuickBooks: save as a draft in QuickBooks, or send to the customer from QuickBooks. Sending uses the email on the QuickBooks customer; with no email, the invoice is saved as a draft and the status says so.
  2. At issue Each invoice posts under the QuickBooks customer whose display name matches the client's name; a missing customer is created. The invoice number, dates, lines, and total are the same as the PDF, to the cent.
  3. Status On the close page after issue: Draft, Sent, Paid, or Failed with Intuit's message. Refresh QuickBooks status reads them again; Retry push to QuickBooks re-posts any invoice that did not land, without creating duplicates.
  4. Reconnect If QuickBooks stops accepting the connection (tokens expire after about a hundred days without use), the status reads Reconnect QuickBooks and Settings offers the button. Nothing else stops: invoices still issue as PDFs.
Pilot deployments. Until the Intuit app is set up for your deployment, Settings says QuickBooks is not set up. Everything else works; past invoices can be pushed once it is.

Things people ask in the first week.

Why can't I change a rate that is already on the card?
Rate card versions are never edited in place; you add a version effective from a date. The old version keeps the invoices it already produced, so a dispute six months later can be traced to the rates that applied. One exception: a missing rate can be added to the version in force from the exception itself, because nothing has been issued against it yet.
Why does "No rate card in force" appear for every day of the month?
The client's first version starts after the activity. A version with an earlier effective date cannot be added once a later one exists, so set the first version's date before the month you import. The setup wizard defaults to the first of last month for this reason.
What is "Recovered this month"?
The money billed under rates you added during this close, for charges that had no rate before. It is the part of the 3 to 15 percent that a spreadsheet would have dropped.
Where do the PDFs live?
With the invoice, under Invoices, for as long as the workspace exists. Issued invoices and their PDFs never change.
Can I import the same month twice?
Yes, until it is issued. A second file from the same source replaces the first; a file from a different source adds to it. After issue, imports into that month are refused.
How do I add a charge my clients pay that is not in the list?
Settings, Charge catalog, Add a custom charge code. Then put the code on the client's rate card and in your export (or a code alias on the source).