Sales Tax and Nexus
Track where your business owes sales tax, watch economic-nexus thresholds by state, calculate tax on US invoices, and download filing-ready packets per state.
Sales Tax is how Muin helps US-based tenants answer three related questions: where are we obligated to collect sales tax, where are we getting close to that obligation even if we are not registered yet, and how do we file once we are collecting. A lightweight nexus registry, a deterministic advisor over invoice volume by state, and an on-demand filing packet cover the day-to-day without demanding that every tenant stand up a full tax-engine integration on day one.
The finance lead uses the same surface whether they are a single-state startup that barely needs to think about sales tax or a multi-state operation that needs to watch thresholds and file in half a dozen jurisdictions each quarter.
Where Sales Tax Lives
Today the active surface for sales tax is Settings → Finance → Sales Tax, where the configuration toggle and the nexus registry live as two stacked panels. The navigation item under Finance > Tax & Compliance > Sales Tax is marked Coming Soon and will eventually host a dedicated reporting page — until then the settings panels are the authoritative place to register nexus states, download filing packets, and watch approaching-threshold warnings.
| Panel | Purpose |
|---|---|
| Sales Tax Configuration | Master on/off toggle + optional Stripe Tax account reference |
| Sales Tax Nexus | Per-state registry with thresholds, filing-packet download, and the approaching-nexus advisor banner |
The Configuration Toggle
The Enable Sales Tax checkbox at the top of the panel is the master switch. When it is off, Muin’s invoice tax calculator returns zero for every invoice regardless of what is in the nexus registry or the customer address — the toggle is checked first, before any state-level logic runs.
When it is on, two optional fields appear:
| Field | What It Is | When To Set It |
|---|---|---|
| Stripe Tax Account ID | A reference to your connected Stripe Tax account | Only when the tenant is using Stripe Tax to compute rates; otherwise leave blank |
| Default Product Tax Code | A tax code applied to invoice line items that do not specify their own | When most of your products share a single Stripe Tax product code (e.g. general goods vs. SaaS vs. non-taxable service) |
Both fields are blank by default and are only meaningful when Stripe Tax is actually wired up on the backend. A tenant can flip the toggle on for nexus tracking and filing-packet generation without ever connecting Stripe Tax — the computed tax amount will stay at zero until the underlying calculator is enabled, but the registry and advisor still work.
The Nexus Registry
The nexus registry is the declarative list of states where your business has declared it has sales-tax collection obligations. Each row has:
| Field | Meaning |
|---|---|
| State | Two-letter USPS code. One active row per state at a time — if obligations change, delete and re-add |
| Reason | Why you have nexus: economic (crossed the state’s sales/transactions threshold), physical (office, warehouse, employees), or voluntary (registered ahead of the threshold on purpose) |
| Established | The date the obligation took effect — the day you crossed the threshold, the day the office opened, the day you voluntarily registered |
| Sales Threshold | Optional override of the state’s economic-nexus sales threshold in dollars, if the default no longer matches current state law |
| Transaction Threshold | Optional transaction-count threshold for states that use one |
| Notes | Free-text context your future self will thank you for — registration confirmation number, filing portal URL, accountant contact |
Inline editing is intentionally omitted: if a threshold changes, the workflow is delete-and-re-add, which keeps the audit trail honest and avoids silent-edit confusion when a state changes its rules mid-year.
The Approaching-Nexus Advisor
Above the nexus table is the approaching nexus banner. It surfaces US states where your invoice volume is at or above 80% of the state’s economic-nexus sales threshold and you are not yet registered. Registered states do not appear in the banner — they already show on the table and are handled through the filing-packet flow instead.
The advisor is deterministic at its core:
Aggregate last 12 months of US invoices by ship-to state →
Compare total sales to state economic-nexus threshold →
Flag states at ≥ 80% where you are not registered
| Parameter | Default | What It Controls |
|---|---|---|
| Lookback window | 12 months | How far back to aggregate invoice volume |
| Warn threshold | 80% | When a state is flagged as approaching — lower this to see earlier signals |
The aggregation only counts invoices in real-revenue statuses: sent, viewed, partial paid, paid, and overdue. Drafts are excluded because they may never be finalized. Voided and cancelled invoices are excluded because nothing was collected against them. Non-US customers and customers without a two-letter state code are ignored entirely — Muin does not yet calculate VAT or GST through this pipeline.
How Thresholds Are Determined
Muin starts from the post-Wayfair baseline — $100,000 or 200 transactions — which most US states adopted between 2018 and 2022. A short list of state-specific overrides adjusts that baseline for states that publish different rules:
| State | Sales Threshold | Transaction Threshold |
|---|---|---|
| California (CA) | $500,000 | — (sales only) |
| New York (NY) | $500,000 | 100 |
| Texas (TX) | $500,000 | — (sales only) |
| Tennessee (TN) | $100,000 | — (sales only) |
| Washington (WA) | $100,000 | — (sales only) |
| Massachusetts (MA) | $100,000 | — (sales only) |
| Colorado (CO) | $100,000 | — (sales only) |
| Kansas (KS) | $100,000 | — (sales only) |
| All other states | $100,000 | 200 |
These are reference defaults only — not a tax-law source of truth. If a state publishes a new rule, override it on the matching nexus row via the Sales Threshold or Transaction Threshold fields and Muin will honor your number instead of the baseline. Unknown state codes fall back to the Wayfair baseline on the assumption that flagging early is safer than silently missing a state.
The Narrative
When at least one state is flagged, the advisor asks the platform LLM to write a one-sentence action prompt per state — plain English, 15–35 words, framing the message as “register before you cross” for unregistered states and “keep filings on schedule” for states that are already registered but showing real volume. If the LLM is unavailable, slow, or returns malformed output, a deterministic per-state template takes over so the banner is always actionable even without AI. Each risk entry carries a narrative_source of either ai or template so the origin of the sentence is visible on the response.
How Tax Gets Calculated on Invoices
Tax is applied when a customer invoice is created or updated and its tax_amount is zero — that is, nothing was explicitly typed in. The calculator walks a short list of preconditions, and returns zero if any fail:
- Is the sales-tax toggle on for this tenant? If not, return zero.
- Is the customer’s ship-to country
US? If not, return zero. (Country-level VAT/GST runs through a separate pipeline.) - Is there a two-letter state on the customer address? If not, return zero.
- Is there an active nexus row for this tenant and this state? If not, return zero — you are not registered to collect there.
- Otherwise, delegate to the configured tax calculator. The platform default is a no-op that returns zero until Stripe Tax is enabled; once it is, Stripe Tax computes the rate per jurisdiction.
The practical result: a tenant can turn sales tax on, register three states in the nexus registry, and immediately start watching the advisor for a fourth — all without needing Stripe Tax wired up. Once Stripe Tax is connected, invoices shipped into any of those three registered states will start carrying a computed tax line automatically.
Filing Packets
Once you are collecting sales tax in a state, you will need to file a return for it on whatever cadence that state requires — monthly, quarterly, or annually. The Download Packet button on each nexus row opens a period picker and generates a filing-ready ZIP on demand.
| Artifact | What It Contains |
|---|---|
{state}-sales-{period}.csv |
One row per invoice shipped into the state during the period — invoice number, issue date, customer name and city, taxable amount, tax collected |
{state}-sales-{period}.pdf |
A cover summary + the same table, formatted for a finance lead to hand straight to a tax preparer |
The default period is the most recent completed calendar quarter, which matches the most common filing cadence across states. You can override the start and end dates to match monthly or annual filings. The period must be a non-empty range with end on or after start.
Filing packets are strictly read-only: nothing about the source invoices is mutated, no “filed” flag is written, and the packet can be regenerated at any time for the same period — the resulting CSV + PDF are deterministic given the same data. This is important because reviewing the packet before filing is normal, and re-downloading after a correction or back-dated invoice lands cleanly reflects the updated picture.
Response headers on the download carry an at-a-glance summary of what is inside the packet:
| Header | Meaning |
|---|---|
X-Filing-Packet-Invoices |
Count of invoices included |
X-Filing-Packet-Total-Sales-Cents |
Sum of invoice totals across the packet (in cents) |
X-Filing-Packet-Total-Tax-Cents |
Sum of collected sales tax across the packet (in cents) |
How Sales Tax Connects to Other Surfaces
| Surface | What It Does With Sales-Tax Data |
|---|---|
| Invoices | When the toggle is on and a nexus row matches the customer’s ship-to state, computed tax appears on the invoice automatically |
| AR Aging | Overdue invoices continue to count toward nexus-risk aggregation until they are voided — partial-paid and overdue are both counted statuses |
| Tax & Reporting (POS) | The “Sales Tax Collected (POS)” panel on /finance/tax/reporting is a separate report for point-of-sale transactions; it is distinct from this invoice-side flow |
| Reports | Filing packets live alongside other finance reports — same CSV + PDF pattern used elsewhere in the module |
The POS path and the invoice path deliberately stay separate: POS sales are typically single-state, handled at the register, and reported via /finance/tax/reporting; invoice sales can land in any US state a customer ships to and run through the nexus registry described here.
Good Practice
- Register the obvious states first. If you know you have a physical office or warehouse in a state, add it with reason
physicaland the move-in date as the established date. That anchors the registry before you need to think about economic nexus. - Watch the advisor monthly, not weekly. The 12-month rolling window moves slowly; checking once a cadence (end of month, quarter-end) is enough. Looking daily will not tell you anything new.
- Turn the warn threshold down before a growth spike. If you are launching into a new geography, drop the warn threshold from 80% to 50% for a quarter so the advisor warns earlier. Bump it back once things settle.
- Keep the notes field useful. Registration confirmation numbers, filing portal URLs, the name of the accountant who handles that state — all of that belongs in the nexus row’s notes field where it will not get lost.
- Review the packet before filing. Open the PDF first; the cover summary is the same number you will enter on the state’s portal. If the total looks wrong, adjust the period picker or check for voided invoices before filing.
- Do not treat the baseline thresholds as gospel. The state-by-state rules change. If a state publishes a new threshold, override it on the nexus row. The advisor will immediately reflect your override on the next read.
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Invoice tax is zero even though I enabled sales tax | Either the customer’s country is not US, or there is no active nexus row for their state | Check the customer address and the registry; the calculator returns zero silently when either precondition fails |
| Advisor banner is empty but I am selling in multiple states | All flagged states are already registered (the banner only shows unregistered states), OR no state has crossed the 80% warn threshold yet | Lower the warn threshold temporarily to see earlier signals, or check the registry for states that have quietly become active |
| Filing packet PDF is blank | No invoices matched the state + period filter — the period may be wrong, the state may have had no shipments, or all invoices in the range are still in draft | Widen the period, confirm there are non-draft invoices shipped into the state, and re-download |
| Advisor narrative is generic | LLM was unavailable during the request; the deterministic template ran instead | Refresh the advisor in a moment; the response carries a narrative_source field indicating ai vs template so the origin is always visible |
| I can’t find the Sales Tax link under Finance nav | The /finance/tax/sales-tax nav item is intentionally marked Coming Soon |
Go to Settings → Finance → Sales Tax for the full configuration + registry + advisor + filing-packet experience today |
| Deleted a nexus row by mistake | Soft-delete only — the row is hidden, not destroyed, and the state can be re-added with its original established date | Re-add the state through the Add State dialog with the same established date; nothing else needs to change |
Related Features
- Invoices — Where the tax calculator actually runs; invoices shipped into a registered state carry tax automatically when Stripe Tax is connected
- AR Aging and Collections — Overdue and partial-paid invoices continue to count toward nexus aggregation until they are voided
- Payments Received — Payment transactions do not change nexus math on their own; what matters is the issued invoice in a counted status
- Bills — The payables-side counterpart; vendor bills are not sales-tax events for your tenant
Need Help?
If tax is not being calculated the way you expect:
- Confirm the master toggle is on (Settings → Finance → Sales Tax → Sales Tax Configuration)
- Confirm the customer’s ship-to address has
country: USand a valid two-letter state code - Confirm there is an active nexus row for that state — if not, no tax is computed (that is correct behavior, not a bug)
- Confirm Stripe Tax is actually connected if you expect non-zero rates; without it the calculator is a no-op that returns zero even when all preconditions pass
- For filing packet questions, check the
X-Filing-Packet-*response headers — the totals there match what the PDF cover page shows - Contact support through the in-app help widget with the tenant ID, the state code, and the invoice number in question — the audit log will show exactly which precondition failed