Sales Tax
If you sell taxable goods or services, you collect sales tax on behalf of the tax authority and remit it on schedule. Sales tax isn't your revenue — it's a liability you owe to the state, county, or country. Solid Accounting tracks it through tax codes (single-rate definitions) and tax groups (combinations of multiple codes for jurisdictions where multiple taxes stack).
The accounting model
Sales tax flows through three accounts:
- Sales Tax Payable (a Current Liability) — what you've collected and not yet remitted
- Income (specific to each sale) — your actual revenue, separate from the tax
- Bank (or AR) — the customer's full payment, including tax
When you invoice a customer for $100 of services with 8% tax:
DR Accounts Receivable 108.00 (what they owe you)
CR Service Income 100.00 (your revenue)
CR Sales Tax Payable 8.00 (held for the state)
When the customer pays:
DR Bank 108.00
CR Accounts Receivable 108.00
When you remit to the state at month- or quarter-end:
DR Sales Tax Payable [accumulated]
CR Bank [check to state]
The Sales Tax Payable account should always equal what you've collected but not yet remitted. Reconciling it monthly is one of the standard sales-tax workflow steps.
Tax codes
A tax code is one rate for one jurisdiction. The schema:
| Field | Notes |
|---|---|
| Code | Short identifier — CA-STATE, NY-NYC-LOCAL, ON-HST |
| Name | Human-readable — California State Sales Tax |
| Rate | Basis points — 725 = 7.25% |
| Tax type | sales, use, gst, hst, pst, vat |
| Jurisdiction | Free text — US-CA, CA-ON, EU-DE |
is_compound | Tax-on-tax — whether this code's rate applies to a base amount that already includes other tax |
is_exempt | Zero-rate code for exempt sales (still tracks the exemption) |
| Effective + expiration dates | When the rate is valid from/to |
is_active | Inactive codes don't appear in pickers |
| Source | system (built-in), downloaded (from a tax-rate service), custom (you defined) |
The tax_type field matters for reports — sales tax in the U.S., GST/HST/PST in Canada, VAT in Europe — are different liabilities tracked separately.
Tax groups
Some jurisdictions stack multiple taxes on the same sale. New York City sales: 4% state + 4.5% city + 0.375% MTA = 8.875% total. Each piece is a separate tax code; the group ties them together as one selection.
A tax group is just a name and a list of codes. When you apply a group to a line, all member codes apply, and the GL posting splits the tax across multiple Sales Tax Payable sub-accounts (one per code) so you can remit to each authority separately.
Tax Group: NYC Sales — 8.875%
Member codes:
NY-STATE 4.000%
NY-NYC-CITY 4.500%
NY-MTA 0.375%
When this group applies to $100 of taxable sales, the GL posts $4 to Sales Tax Payable — NY State, $4.50 to Sales Tax Payable — NYC, and $0.375 to Sales Tax Payable — MTA. Each is reported separately.
Compound taxes
Some jurisdictions calculate one tax on a base that already includes another tax. This is rare in the U.S. but common in Canada (Quebec's QST is sometimes compound on top of GST) and parts of Europe.
The is_compound flag on a tax code tells Solid to compute its rate against the post-other-tax amount instead of the pre-tax amount:
$100 sale, 5% GST (not compound), 9.975% QST (compound):
GST: $100 × 5% = $5.00
QST: ($100 + $5) × 9.975% = $10.474
Total tax: $15.474
Total invoice: $115.474
Get this wrong and the customer's invoice total mismatches the authorities' expected remittance. Solid handles it correctly when you mark the right code as compound; manual calculation is error-prone.
Where tax codes apply
Three places in the UI accept tax codes:
| Where | Effect |
|---|---|
| Per item | Default tax code for that item; populates new invoice/sales-receipt lines |
| Per customer | Default tax code for that customer's invoices (overrides item-level default) |
| Per line | Override on a specific invoice/sales-receipt/estimate line |
The precedence is line override > customer default > item default. Customers in non-taxable states don't pay sales tax even if the item is taxable; that's the customer-default winning.
Tax-exempt customers
Customers who are tax-exempt (resellers, nonprofits, government) can be flagged with an is_exempt tax code. The flag posts the line at zero tax and records the exempt code on the entry — useful for auditing later (the state may want proof of exemption).
For each exempt customer, you should also store their exemption certificate somewhere (paper file, attached document, or a custom field on the customer record). Solid doesn't validate certificates; that's a compliance task on you.
The Sales Tax Liability report
Solid's Sales Tax Liability report aggregates by tax authority for a period:
Sales Tax Liability — Q1 2026
NY State (NY-STATE)
Taxable sales: 42,500.00
Tax collected: 1,700.00
Already remitted: 0.00
Owed at end of period: 1,700.00
NYC (NY-NYC-CITY)
Taxable sales: 42,500.00
Tax collected: 1,912.50
Already remitted: 0.00
Owed at end of period: 1,912.50
...
Run this before each filing period. The "owed at end of period" is what you'd remit; once remitted, the corresponding Sales Tax Payable balance returns to zero.
Remitting
When you write the check to the state:
- Look up the Sales Tax Liability report for the period
- Write a Check (or Pay Bill if the state has issued you a bill) for the total
- Distribute the lines across the matching Sales Tax Payable sub-accounts:
DR Sales Tax Payable — NY State 1,700.00 DR Sales Tax Payable — NYC 1,912.50 DR Sales Tax Payable — MTA 159.38 CR Bank 3,771.88 - After posting, the Sales Tax Payable accounts for that period zero out
For automated multi-jurisdiction filing, services like Avalara and TaxJar plug into Solid via API integrations. The basic remittance via Check entry works for any jurisdiction.
Use tax
use tax is the inverse of sales tax — what you owe on out-of-state purchases when the seller didn't collect sales tax. Solid tracks this through the same tax-code system; tag bills with use-tax codes when applicable, and the use-tax owed accumulates in Use Tax Payable.
The same Sales Tax Liability report covers use tax (filtered by tax_type = 'use').
VAT and international
For European VAT, Canadian GST/HST/PST, and similar, the model is identical — different tax_type, different rates, different filing cadence. Reverse-charge VAT (where the buyer accounts for the tax) is supported via use-tax-style codes.
Common gotchas
Sales Tax Payable accumulates and never zeroes out. You set up the codes correctly but never recorded the remittance. Run the Sales Tax Liability report, write a Check for each authority, and the balance clears.
Sales Tax Payable goes negative. Means you've remitted more than you collected. Causes: a refund/credit memo to a customer (which credits Sales Tax Payable, lowering the balance) without a corresponding sales-tax adjustment; or a remittance for an amount that included pre-period activity. Investigate the offending entry.
The customer's invoice total doesn't match what you'd expect at the rate. Check whether the rate is per-line or per-invoice — if you have a tax group with three codes at 4%, 4.5%, and 0.375%, the calculation depends on is_compound flags. Check each member code.
Tax rate just changed (state raised the rate); old invoices showing the wrong rate. Old invoices stay at the old rate (correct — that's what you collected). For new invoices, edit the tax code's rate_basis_points and set an effective_date. Better: create a new code with the new rate and effective date, deactivate the old one, and let users pick the new one going forward.
Tax code not appearing in customer's tax dropdown. Check is_active and the effective/expiration dates. A code with an expiration in the past, or with is_active = 0, is hidden.
Cross-references
- Accounts Receivable → Invoicing — where tax codes apply on the AR side
- Accounts Payable → Bills — where use-tax codes apply on the AP side
- Reports → Tax reports — the Sales Tax Liability report