TaxQL Python SDK
Official Python client for the TaxQL API. Address-accurate U.S. sales tax lookups across all 50 states + DC, plus Canada (GST/HST/QST for all 13 provinces and territories, in beta).
pip install taxql
Quickstart
from taxql import TaxQL
client = TaxQL(api_key="your-key")
response = client.lookup(
state="tx",
address="6515 Cottonwood Creek Dr, Frisco, TX 75034",
)
print(f"Rate: {response.combined_rate * 100:.4f}%")
print(f"State: {response.rate.state} County: {response.rate.county}")
print(f"Confidence: {response.confidence}")
Output:
Rate: 8.2500%
State: TX County: COLLIN
Confidence: exact
Why TaxQL
- Address-accurate, not ZIP-approximated. We resolve to the jurisdiction at the address (including SPDs / ESDs / MUDs), not the city in the address line.
- Best rate by default. Each lookup returns a single applicable
rate plus a
confidencesignal and any advisorywarnings. - Historical queries. Pass
as_of=date(2026, 6, 1)to retrieve the rate in effect on that date. - Half the price of incumbent providers.
Lookup modes
Provide exactly one input mode per call:
# Address (highest precision) — pass a full single-line address
client.lookup(state="tx", address="6515 Cottonwood Creek Dr, Frisco, TX 75034")
# ZIP only (single best rate; lower confidence on straddling ZIPs)
client.lookup(state="wa", zip="98039")
# Location name (DoR-published place name)
client.lookup(state="wa", location="Seattle")
# Lat/lng
client.lookup(state="ca", lat=34.05, lng=-118.25)
Response shape
lookup() returns a TaxResponse with a rate block and a meta
block. Convenience properties cover the common path:
r = client.lookup(state="tx", address="...", city="...", zip="...")
r.combined_rate # float — total applicable rate, e.g. 0.0825
r.confidence # "exact" | "high" | "medium" | "low" | "none"
r.warnings # list of advisories (see below)
r.rate.state # "TX"
r.rate.county # "COLLIN"
r.rate.state_rate # 0.0625
r.rate.combined_district_rate # sum of special-district rates
Rate fields arrive from the API as fixed 5-decimal strings and are
parsed to floats for you. For the verbose per-jurisdiction body (every
candidate row, component breakdown, resolved-place detail), request
mode=full on the raw HTTP API.
Warnings
response.warnings is a list whose items are either plain strings or
structured objects carrying a code:
for w in response.warnings:
if isinstance(w, dict) and w.get("code") == "place_input_mismatch":
print(f"input '{w['customer_input_place']}' resolved to "
f"'{w['resolved_place_name']}'")
elif isinstance(w, str):
print(w)
Async client
import asyncio
from taxql import AsyncTaxQL
async def main():
async with AsyncTaxQL(api_key="your-key") as client:
# Three concurrent lookups
responses = await asyncio.gather(
client.lookup(state="tx", zip="75034"),
client.lookup(state="wa", zip="98039"),
client.lookup(state="ca", zip="94022"),
)
for r in responses:
print(r.rate.state, f"{r.combined_rate * 100:.4f}%")
asyncio.run(main())
Historical queries
Pass as_of to retrieve the rate in effect on a specific date:
from datetime import date
# Q2 2026 (current as of 2026-06-01)
q2 = client.lookup(state="wa", zip="98039", as_of=date(2026, 6, 1))
# Q3 2026 (loaded ahead of effective date)
q3 = client.lookup(state="wa", zip="98039", as_of=date(2026, 7, 15))
Supported on states with effective-period history (TX, CA, FL, WA,
NY, and all SST states). Single-snapshot states (NM, MO, IL, CO, LA,
AL, AZ, AK) return the current rate regardless of as_of.
Error handling
from taxql import (
TaxQL, AuthError, PaymentRequiredError, ForbiddenError,
RateLimitError, NotFoundError, ValidationError, ServiceError, TaxQLError,
)
try:
client.lookup(state="tx", zip="75034")
except AuthError:
print("Invalid API key — sign up at https://taxql.com/signup")
except PaymentRequiredError:
print("Billing/subscription issue — check the dashboard") # 402
except ForbiddenError:
print("Your plan doesn't include this") # 403
except RateLimitError as e:
print(f"Rate limited; retry after {e.retry_after}s")
except NotFoundError:
print("Address could not be resolved")
except ValidationError as e:
print(f"Bad input: {e}")
except ServiceError:
print("Upstream temporarily down")
except TaxQLError as e:
print(f"Other API error [{e.error_code}] (ref {e.support_reference})")
The SDK automatically retries 429 (rate limit) and 5xx
(service error) responses up to max_retries=3 times with
exponential backoff (and honors the Retry-After header on 429).
4xx errors other than 429 raise immediately — no point retrying a
malformed request. Every exception carries status_code and the
parsed response_body (e.g. exc.response_body["error"]["code"]).
Configuration
TaxQL(
api_key="your-key",
base_url="https://api.taxql.com", # default
timeout=10.0, # seconds
max_retries=3, # 429 + 5xx + timeout
http_client=None, # inject your own httpx.Client
)
If you inject your own httpx.Client, the SDK won't close it on
__exit__ — manage its lifecycle yourself. Useful for sharing a
connection pool across multiple SDK instances or for custom transport
(e.g., adding proxies or TLS cert pinning).
Forward compatibility
The response models use extra="allow" so newer API versions adding
fields don't break older clients. You can always access the raw
response dict via response.model_dump().
Examples
Runnable examples live in examples/:
examples/basic.py— sync address lookup, single stateexamples/async_lookup.py— async, multiple states in parallelexamples/historical.py—as_ofcomparison across quarters
Documentation
Full API docs at https://docs.taxql.com. OpenAPI spec at https://api.taxql.com/openapi.json.
License
Commercial — see https://taxql.com/terms.
Support
support@taxql.com — or open an issue at
https://github.com/taxql/taxql-python/issues.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file taxql-0.1.1.tar.gz.
File metadata
- Download URL: taxql-0.1.1.tar.gz
- Upload date:
- Size: 16.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9f43650ec7bc9845756066143be5b1a52acd4cc2ff733089308b02e34b5c3b0
|
|
| MD5 |
217e446f77bb7df23b570343cf4430e5
|
|
| BLAKE2b-256 |
e1c042cb97242a2ae322569657aa4bbae51df02442d95c0100e3fc39ec72c310
|
File details
Details for the file taxql-0.1.1-py3-none-any.whl.
File metadata
- Download URL: taxql-0.1.1-py3-none-any.whl
- Upload date:
- Size: 13.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b4003167d9218a9fe9a5f29db7773d21e0d7f1ebea6f03d3a839d89e73b340d
|
|
| MD5 |
0735654e1737803ba3ad0ed37bb50210
|
|
| BLAKE2b-256 |
924eb5143e029d8a4d93a0cf4b3e5206a458f856345b905b0384a3ae59d8138e
|