Destination-Based Sales Tax Needs a Destination
The rate depends on where your customer is. Our customer record holds a latitude to seven decimal places and has no field for the state. What a destination-based rate needs from a customer record, what ours holds today, and why half the plumbing being there changes the estimate.
US sales tax is destination-based. The rate is set by the state, and usually by a county or a city underneath it, and which one applies turns on where the customer takes delivery. So the rate is a property of the destination, and the destination is a property of the customer record. That single sentence is the whole design constraint, and it is the one that a system built for value-added tax will not satisfy — not because it is missing a feature, but because it is keyed on the wrong thing.
Nothing here is tax advice, and nothing here will tell you where you have an obligation to collect. That is a legal determination about your own activity and it belongs to your adviser. What follows is about data modelling, and we are going to use our own schema as the specimen because it is the one we can open up.
The customer record, as it actually is
Here is the tax-relevant half of our customer table. Read the last two rows before the first four.
| Field | Type | What it can answer |
|---|---|---|
| country | varchar(100) | A country. Enough for a VAT jurisdiction and nothing below it. |
| address | varchar(255) | One free-text line. A person can read a state out of it; nothing can key a rate to it. |
| latitude | decimal(10,7) | A position to roughly a centimetre. |
| longitude | decimal(10,7) | The same again. |
| state or province | no column | Nothing. The field does not exist. |
| postal code | no column | Nothing. Also absent. |
We can place a customer precisely enough to identify a loading dock, and we cannot say which state they are in. Those two facts sit in the same row of the same table.
It is worth saying why the coordinates are not a solution dressed as a joke. A point can be resolved to a taxing jurisdiction — that is what boundary datasets are for, and it is a real product that real companies maintain. It is not a thing you get for free by having stored two decimals, and it is not something we have built or would claim. What we will not do is the cheap version: a regular expression over a free-text address line, deciding real tax on real money, failing silently on every address that does not fit the pattern.
Where the question sits in the schema today
The customer’s jurisdiction is absent from the record, but the places a jurisdiction would plug into are not. Three of them are worth knowing, and every one is checkable by reading the code behind it.
-
A tax resolver that reads the customer
Tax on a sales document is resolved from the organization, the tax type and the default rate — and from the customer, for one question: whether that customer is exempt. An exempt customer is untaxed on invoices, quotations and point-of-sale sales alike. The resolver takes only what it reads, so every argument passed to it matters.
-
A jurisdiction column that selection does not filter on
Our rate table has a jurisdiction region column alongside a jurisdiction country column. It is written by the settings screens. Rate selection filters on organization, tax type and default flag — the jurisdiction is not yet part of the query.
-
A per-customer tax settings table
Registration status, registration number, registration date, an exemption flag, an override rate and an international-trade flag, written by the customer form and shown on the customer page. The exemption flag is applied to every sales document. The override rate is stored and not applied: a per-customer rate is a feature in its own right, and switching it on changes what customers are charged, so it is a decision for a scoped build rather than a side effect.
Why half the plumbing changes the estimate
A missing capability tells you what to build. A capability whose shape is already present in the code — columns, a table, a resolver that already reads the customer — tells you something more useful: that the work is connection rather than invention. That is the ordinary result of a product growing up in a market where the country-level answer is correct.
It also changes the quote. "We do not support destination-based tax" sounds like a rewrite. "There is a jurisdiction column that rate selection does not filter on, a per-customer override rate that is stored and not applied, and a resolver that already reads the customer" is a list of connections, plus one genuinely new field on the customer record. Those are very different quotes, and the second is the accurate one.
The general lesson, which is not about tax
Parameters that are accepted and not read are a specific kind of debt, and they are worse than a missing parameter, because they are indistinguishable from a working one at every call site. Somebody passing a customer id to a resolver that ignores it has every reason to believe it matters. The signature is a promise, and an unread parameter breaks it at every call.
- Grep your own codebase for function parameters that never appear in the body. Static analysis finds these and most configurations do not fail the build on them.
- Look for columns written by a form and read by nothing. A migration plus a form plus a detail panel is the signature of a feature that was designed and then not wired.
- Look for return values that are always the same literal, especially one with a suppression comment beside it — honest, and exactly what an audit should be searching for.
- For anything you find, ask the question that sorts them: can a user set this and reasonably believe it does something? If yes, it is a defect and not a gap.
What we would build, and the one thing we would decline
The buildable sequence is short and specific: a jurisdiction field on the customer and on the sale; the override rate on that same customer record, which is stored and not yet applied; and the interface a specialist tax service plugs into, so the rate comes from something that does nothing but rates. What we would decline is maintaining a US rate table ourselves. Thousands of jurisdictions with rules that move is not a side line, and the responsible answer is an integration rather than a table we keep.
What AWRA OpsHub does today
- A jurisdiction country and jurisdiction region column on the rate table — half the plumbing, and it is genuinely there.
- Per-customer tax exemption, read and applied — a customer marked exempt on their own record is not charged, on any sales document.
- A document vault with a scheduled retention and purge job, which is where an exemption certificate would live as evidence.
- Machine-readable exports in CSV, XLSX and JSON, which is what any downstream tax engine needs from us.
- Procurement, inventory, projects and governance, which is the operational half and is not affected by any of this.
More we can add to your workspace
- A jurisdiction on the customer record: a state, province, region or postal code. This is the field everything else waits on.
- Rate selection by jurisdiction, using the region column the rate table already carries.
- The per-customer override rate applied to sales. The exemption flag beside it is applied today; the override rate is stored on the customer, ready to be wired into rate selection.
- Exemption certificate handling with an issuing state, an expiry and a link to how a sale is taxed. A file in the vault is not that.
- A US sales tax calculation, filing or return, at state or local level.
Where we point you to a specialist
- We will not tell you where you have nexus. It turns on facts about your own activity and it is a legal determination.
- We will not read a state out of an address string. It is the obvious shortcut, it is demonstrable, and it produces confidently incorrect returns.
- We will not maintain a US rate table. Thousands of jurisdictions with moving rules belongs to a service that does nothing else.
- We would decline a US sales tax build as a first engagement, because it is the largest single piece of work on our list and the worst possible introduction.
A jurisdiction field on the customer and the sale, the override rate on the customer record, and an interface to a specialist rate service — in that order, and priced as three pieces rather than one module. The precedent that market-specific tax work gets finished here is Kenya: a live tax-authority integration and a maintained statutory payroll engine, both built to specification and both still ours to run. A written specification, a timeline and a price agreed before anything starts, and a date in a quote rather than on a public page.
The jurisdiction field on the customer is the item on the middle list we would do first: rate selection, the override rate and any specialist rate service all wait on it.
What we can build for the United States on top of the standard product
Everything listed above as something we can add describes what ships in the standard product today — it is a starting point for the United States, not a limit on what AWRA OpsHub can do there. Kenya's eTIMS integration and its maintained payroll engine are in the product because Kenyan clients needed them and commissioned them; neither appeared by itself. The same door is open here. If a jurisdiction on the record, and settings that are actually read, a bank or mobile money feed, a statutory return format, a rule specific to how your operation runs, or a link to a system you already have is what stands between you and a decision, tell us and we will scope it as a build — written spec, timeline and price — before you commit to anything.
Three builds, and we would decline the fourth
A jurisdiction field on the customer and on the sale — a real field, not a state parsed out of a free-text address line, which is the cheap version and produces confidently wrong returns. Then per-customer tax settings that are read rather than only stored: the exemption flag, the registration number and the override rate all exist on the customer record today and no tax calculation looks at any of them, which is a defect fix rather than a feature. Then the interface a specialist tax service plugs into, so the rate comes from something that does nothing but rates. What we would decline is the fourth build — a US rate table we maintain ourselves. Thousands of jurisdictions with rules that move is not a thing to own as a side line, and we would rather say so in a specification than discover it in year two.
Banks and payments
ACH origination and bank statement feeds wired into the Payments Register, so money in and out reconciles against the documents that authorised it rather than against a spreadsheet.
The operational work, which is what most commissions actually are
An extra approval stage in a chain that does not match the standard one, a custom field set on employees or assets that only your sector needs, an expiry that has to block an order rather than send an email, a report your board asks for in a shape nothing produces, or a scanner or weighbridge feeding the goods-in door. These are the commissions we are asked for most often and the smallest ones we quote — and unlike a revenue-authority pipeline, none of them waits on a regulator.
Payroll and statutory returns
A US payroll engine with federal and state withholding, FICA, quarterly and annual returns, state unemployment insurance and multi-state allocation for employees who cross state lines. None of it exists today.
Systems you already run
The accounting package, CRM, online store or custom database you intend to keep — connected through our API so a fact is entered once and appears everywhere it is needed.
How it works: you describe the requirement, we return a written scope, timeline and cost, and once agreed it is built into your environment and maintained as part of the product. No roadmap slide, and no pretending in a demo that something exists when it does not.
Tell us what you need integratedThe one-line version
Destination-based tax needs a destination on the record, and a coordinate is not one. Before you evaluate any vendor's US tax capability, ask which field on the customer the rate is keyed to — and if the answer is the address line, ask what happens to the addresses that do not parse.
Ask us what our schema holds
Every field above is checkable, and we would rather walk you through them than have you discover one in an audit.
Read the United States page