Skip to main content

opensalestax-python

PyPI License Python CI

Python SDK for OpenSalesTax — calculate US sales tax via the engine's v1 HTTP API.

A thin, well-typed wrapper around the engine's four endpoints. Used by the OpenSalesTax connectors for Odoo and ERPNext, and suitable for any Python application that needs destination-based US sales-tax calculation.

Install

pip install opensalestax

Requires Python 3.10+.

Quickstart

from decimal import Decimal
from opensalestax import OpenSalesTaxClient, Address, LineItem

with OpenSalesTaxClient(base_url="http://localhost:8080") as client:
    result = client.calculate(
        address=Address(zip5="55401"),  # Minneapolis, MN
        line_items=[
            LineItem(amount=Decimal("100.00"), category="general"),
        ],
    )

    print(f"Subtotal:  ${result.subtotal}")
    print(f"Tax:       ${result.tax_total}")
    for line in result.lines:
        for j in line.jurisdictions:
            print(f"  {j.name} ({j.type}) {j.rate_pct}%: ${j.tax}")

Output (against engine v0.54+):

Subtotal:  $100.00
Tax:       $9.0250
  Minneapolis (city) 0.50000%: $0.5000
  Hennepin County (county) 0.15000%: $0.1500
  Minnesota (state) 6.87500%: $6.8750
  Hennepin County Transit Sales Tax (district) 0.50000%: $0.5000
  Metro Area Transportation Sales Tax (district) 0.75000%: $0.7500
  Metro Area Sales and Use Tax for Housing (district) 0.25000%: $0.2500

API

OpenSalesTaxClient

OpenSalesTaxClient(
    base_url: str,                    # engine URL, e.g. "http://localhost:8080"
    api_key: str | None = None,       # optional Bearer token
    timeout: float = 10.0,            # seconds
    user_agent: str | None = None,    # appended to default UA
    verify: bool = True,              # TLS verification
)

Use as a context manager (recommended) or call client.close() manually.

Methods

Method Endpoint Returns
health() GET /v1/health HealthResponse
states() GET /v1/states list[StateCoverage]
rates(zip5, zip4=None) GET /v1/rates RateStack
calculate(address, line_items) POST /v1/calculate CalculationResult

Models

All models are immutable (frozen=True) Pydantic v2. Money and rates use decimal.Decimal to preserve precision; rates are expressed as percents (e.g. Decimal("6.875") means 6.875%).

  • Address(zip5, zip4=None) — engine v1 is ZIP-only
  • LineItem(amount, category="general") — pre-tax amount as Decimal
  • JurisdictionBreakdown(name, type, rate_pct, tax) — one taxing authority
  • CalculatedLine(amount, category, tax, rate_pct, jurisdictions, note)
  • CalculationResult(subtotal, tax_total, lines, disclaimer)
  • RateStack(input, jurisdictions, combined_rate_pct, disclaimer)
  • HealthResponse(status, version, database_connected)
  • StateCoverage(abbrev, name, has_sales_tax, sst_member, tier, notes)

Errors

Flat hierarchy — connectors typically catch one or two:

from opensalestax import (
    OpenSalesTaxError,            # base class
    OpenSalesTaxNetworkError,     # timeout, connection refused, DNS, TLS
    OpenSalesTaxAPIError,         # non-2xx HTTP response (.status_code, .response_body)
    OpenSalesTaxValidationError,  # response shape didn't match SDK models
    NonUSDError,                  # non-USD or non-US address
)

Recommended pattern in a connector:

try:
    result = client.calculate(address=addr, line_items=items)
except OpenSalesTaxNetworkError:
    fall_back_to_catalog_rate()      # engine unreachable
except OpenSalesTaxAPIError as e:
    if e.status_code >= 500:
        fall_back_to_catalog_rate()  # engine glitch
    else:
        surface_to_merchant(e)       # 4xx — config / data issue

Compatibility

SDK version Engine version Python
0.1.x 0.22+ (recommended 0.54+) 3.10, 3.11, 3.12, 3.13

The engine's v1 HTTP API is the contract. Internal Python modules are not — connectors must use this SDK or call the HTTP API directly.

Calculation only

Tax calculations are provided as-is for convenience. The merchant is solely responsible for tax-collection accuracy and remittance to the appropriate jurisdictions. Verify against your state Department of Revenue before remitting.

This SDK does not:

  • File tax returns or remit collected tax (engine constitution §13)
  • Validate addresses
  • Cache calculations (caller's responsibility — caching policy is platform-specific)
  • Retry transient errors (caller's responsibility)

Connectors that use this SDK

Development

git clone https://github.com/ejosterberg/opensalestax-python.git
cd opensalestax-python
uv venv
uv pip install -e ".[dev]"

# Quality gate
ruff check src tests
ruff format --check src tests
mypy --strict src/opensalestax
pytest --cov=opensalestax --cov-fail-under=90

# Live tests against an actual engine (skipped by default)
RUN_LIVE_TESTS=1 OST_BASE_URL=http://localhost:8080 pytest -m live -v

Contributing

See CONTRIBUTING.md. All commits must carry a DCO sign-off (git commit -s). No AI co-author trailers.

License

Apache 2.0. Apache 2.0 + DCO sign-off + SPDX header on every source file.

Release files for opensalestax 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for opensalestax 0.3.1
File Size Uploaded
opensalestax-0.3.1.tar.gz 29.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for opensalestax 0.3.1
File Interpreter ABI Platform
opensalestax-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 46.7 kB

Release files / opensalestax-0.3.1.tar.gz

Download URL opensalestax-0.3.1.tar.gz
Size 29.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a20291e52052ed8b3da436f0535ecf9054c43c2f70f5ca7ce4647774bd0c29b7
BLAKE2b-256 checksum
How to use checksums
9070c56147e3791ba1ce4665cfd1d0f59da5c1f0b3873abb1784a3dcad90590f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 19, 2026.

Transparency log

Release files / opensalestax-0.3.1-py3-none-any.whl

Download URL opensalestax-0.3.1-py3-none-any.whl
Size 16.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0868c2af2fa78af982ebae54b78d7f942fe52442f7d5bffca63dfada78af0c3d
BLAKE2b-256 checksum
How to use checksums
4ac081146c69bc3276edac59796d446f3dccf44abc5bcf03e49e8e50a57bd295
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page