AI Adoption GuideFinanceInvoice
Tax and jurisdiction assignment
Classifier assigns VAT, sales tax, and withholding codes per region, using tools like Avalara or Stripe Tax.
Finance processPlanBudgetInvoiceCollectPayCloseReportAudit
By Don, DoneThat’s AI coach · updated
The quality bar is a cited code, not a guessed rate
A usable tax assignment is a jurisdiction code plus two cites: the ship-to or bill-to field that supplied the location, and the tax-engine rule that mapped that location and the product's taxability to a VAT, sales-tax, or withholding code. The rate is not the artifact. The code is. If the location field is empty, the code stays empty. Nobody invents a rate so the invoice looks complete.
Billing needs a code the engine will accept so the invoice can post. Tax needs an audit trail that still holds when a return is prepared. A number with no cite fails both jobs. A blank with a reason keeps fiction off the invoice and shows tax which records still need a person.
The classifier does not file, create nexus, or decide that a customer probably ships to a state because the sold-to address is there. Engines in this class (Avalara, Stripe Tax, and the tax modules inside Workday and SAP) return a code when you give them a jurisdiction and a taxability profile. They do not repair missing geography.
If commercial terms are still being assembled, finish contract-to-invoice generation first. Tax assignment runs on a document that already has parties, ship-to, bill-to, and line taxability.
Load location and taxability before anything else
Pull two facts before the classifier calls the engine: where the transaction is treated as occurring, and whether the product or service is taxable in that place.
Location is a specific field, not "the customer." For goods, that is usually ship-to. For some services and for withholding, bill-to or the customer's registered establishment can be the right field under the rule set you already use. Record which field you used. Do not silently fall back from ship-to to bill-to to sold-to until something is non-blank. A fallback without a cite is how a sales-tax line gets a headquarters state instead of a delivery state.
Product taxability is the second input. A subscription, a professional-services hour, and a physical good do not share a code even when they share a ship-to. Load the tax category from the SKU master, the same way invoice pre-flight check already demands complete header and line fields before an invoice posts. If the SKU has no taxability, stop. Do not infer "tangible" from a product name.
Withholding still needs a location field and a rule. It applies when the customer's jurisdiction requires the buyer to withhold on a type of payment, such as royalties or certain services. Do not invent a withholding code because the invoice is international.
When inputs are missing, do not call the engine to see what it returns. An engine given a blank jurisdiction will error, default, or guess. Default and guess look like assignments. They are not.
One path, not a measured case: a billing clerk has a software-license invoice. Ship-to is a warehouse in Illinois. Bill-to is a shared-services entity in Delaware. The SKU is marked taxable software. The classifier sends Illinois plus that taxability profile to the engine, stores the Illinois sales-tax code the engine returns, and cites the ship-to field plus the engine rule identifier. It does not store a handmade percentage. If ship-to had been empty, Delaware would not have been used to keep things moving. The code would have stayed blank for billing review.
Assign with a cite to the field and the engine rule
Once location and taxability are present, call the tax engine and write the code, the source field, and the rule onto the line.
The code is the engine's VAT, sales-tax, or withholding identifier. Copy it. Do not turn it into a rate you typed from memory. Rates change. The cite is what lets tax re-run the engine at filing time.
The source field is a pointer. Write the ship-to or bill-to field name, or the equivalent in Workday or SAP, and the value that was sent. A reviewer should find that field and see the same geography the engine saw. Name the field that drove this line, not the field that usually drives invoices of this type.
The engine rule is the identifier Avalara, Stripe Tax, Workday, or SAP returns as the reason for that code. You are documenting the mapping so tax can see which invoices were assigned under an old rule book.
Do not assign a rate when ship-to, or the designated location field, is missing. A rate on a line with no jurisdiction is a number with no legal hook. It will not survive a notice.
Do not invent nexus. The classifier does not decide that selling into a state creates a collection obligation because a ship-to exists. If the engine says the company is not registered or not obligated there, the honest outputs are no collection, an exempt or zero-rated code the engine actually returned, or a blank plus a review flag.
If ASC 606 revenue recognition split breaks a contract into distinct performance obligations, each invoiceable line still needs its own location cite and taxability. Do not copy the header tax code onto every split line.
Leave the code blank when the jurisdiction field is missing
Empty stays empty. If ship-to is blank and the rule requires ship-to, do not write a code. The same holds for bill-to. If the engine returns an error or an unspecified jurisdiction, do not substitute last quarter's code for that customer.
A blank is a control: billing cannot post a clean tax line, so the invoice goes to exception review. Filling the blank to clear a validation rule is how bad codes reach the subledger.
Teams hide the blank by copying bill-to into ship-to so the engine has something, by reusing the last posted code for that customer, or by picking a rate from a public table after a timeout. Those invent geography, continuity, or a rate. None of them is an engine rule.
Route blanks to a queue that names the missing field. Master data fixes ship-to or bill-to, then the classifier runs again. Do not let a manager pick a state in the queue.
Cash application via remittance parsing will match a payment to an invoice. It will not repair a tax code that was guessed so the invoice could go out. Wrong tax on a paid invoice is a refund and a return adjustment, not a lockbox problem.
Billing reviews the assignment; tax still owns the filing
Billing confirms the cite points at a real field, the engine returned a code or a documented no-tax result, blanks are still blank in the exception queue, and nobody typed a rate next to an empty ship-to.
Billing does not certify nexus, sign the return, or treat the code as proof that VAT was remitted or sales tax was filed. Treating the assignment as a filed return is a failure mode. A code on an invoice is an input to the return process. It is not the return.
Tax owns filing, registration, and whether withholding should have applied when the customer is the withholding agent. When the engine disagrees with a tax policy memo, the memo wins, the engine rule is updated, and the invoice is reclassified. Do not patch invoices with handwritten codes the next engine run will overwrite.
Keep the review artifact with the invoice: field name, field value, engine, rule id, code, timestamp, and reviewer. That is what a notice response needs.
Is this worth automating for you?
Whether this pays back depends on how much time it takes your team today. Most teams estimate that from memory, and the estimate is usually wrong in one direction or the other.
DoneThat reconstructs where the time actually went, with no timers to forget, so you can measure the baseline before committing to a project and check the gain afterward.
Measure the baseline first