AgentTax Python SDK
Sales tax, use tax, and capital gains for AI agents. Full docs at agenttax.io/api-docs.
Install
pip install agenttax
Quickstart — no signup required
from agenttax import AgentTaxClient
client = AgentTaxClient() # keyless: demo mode, 10 calls/day
result = client.calculate(
role="buyer", # buyer side needs no nexus setup
amount=1000.00,
buyer_state="TX",
transaction_type="compute",
counterparty_id="agent_seller_001",
)
print(result["total_tax"]) # use tax owed on the purchase
print(result["combined_rate"]) # the location's composed rate (state + local)
print(result["applied_rate"]) # the rate actually applied to compute total_tax
print(result["confidence"]) # {"score": ..., "level": ...}
Demo mode returns the tax figure, the rate and a confidence score. It omits the
audit trail, jurisdiction breakdown and advisories, and it keeps no history.
The response also carries resolution (a resolved, partial or unknown status for location, nexus and taxability) and intent, which is always "estimate" on a keyless call.
API Key
Get a free API key at agenttax.io — 1,500 calls/month at no cost — for the full response plus transaction history, nexus monitoring, capital gains tracking and 1099 export.
client = AgentTaxClient(api_key="atx_live_...")
Why role="seller" returns $0.00 on a new account
A seller only has to collect tax where it has economic nexus, and a new account
has none configured — so every seller-side calculation correctly returns
total_tax 0 with final_determination: "no_nexus" until you set nexus up:
import requests
requests.post(
"https://agenttax.io/api/v1/nexus",
headers={"X-API-Key": "atx_live_..."},
json={"nexus": {"TX": {"hasNexus": True, "reason": "Economic nexus"}}},
)
Or pass nexus_override={"TX": {"hasNexus": True}} to calculate() to model a
seller position without saving it. Note the shape — a bare list of state codes
is read as "no nexus" and silently returns $0.00. Buyer-side calls need none of
this, which is why the quickstart above starts there.
Methods
calculate(**kwargs)
Calculate sales tax for a transaction.
| Parameter | Type | Required | Description |
|---|---|---|---|
role |
str | ✓ | "seller" or "buyer" |
amount |
float | ✓ | Transaction amount in USD |
buyer_state |
str | ✓ | Two-letter state code |
transaction_type |
str | ✓ | "saas", "compute", "consulting", etc. |
counterparty_id |
str | ✓ | Counterparty identifier |
work_type |
str | What the work is. One of "compute", "research", "information_service", "content", "consulting", "trading", "payment_processing", "web_hosting", "software_maintenance", "it_support", "custom_software" |
|
is_b2b |
bool | Business-to-business transaction | |
use_context |
str | "enterprise_system", "individual", or "mixed" — Maryland-only in v1, declares whether the purchase is solely for commercial use in an enterprise computer system (TB-56); absent = unchanged is_b2b-proxy default |
|
buyer_zip |
str | 5-digit ZIP for local rate lookup | |
seller_remitting |
bool | Buyer mode: the seller already collected the tax | |
nexus_override |
dict | Model nexus for this one call, e.g. {"TX": {"hasNexus": True}} |
|
idempotency_key |
str | Sent as the Idempotency-Key header; a retry with the same key and body replays the first response for 24 hours |
|
intent |
str | "estimate" or "record" (since 0.3.0) — see below |
|
seller_state |
str | Seller's two-letter state code (since 0.3.0) | |
seller_zip |
str | Seller's 5-digit ZIP. Required for TX, UT, AZ and TN origin-sourced intrastate sales, and for intrastate OH license or digital_good sales (since 0.3.0) |
|
marketplace_role |
str | "seller", "facilitator" or "direct" (API default "direct") (since 0.3.0) |
|
exemption_certificate |
str | Exemption certificate reference, up to 200 characters (since 0.3.0) | |
description |
str | Free-text description, up to 1000 characters, recorded with the transaction (since 0.3.0) | |
digital_content_type |
str | With transaction_type="digital_good" only. What the download is: "ebook", "audio", "video", "art_image", "photograph", "printable_document", "software", "data" or "other". Absent = the generic digital_good answer (since 0.3.0) |
|
payment_provider_type |
str | With transaction_type="payment_processing_fee". Who provides the processing: "bank", "licensed_money_transmitter", "card_network", "processor_routing_to_bank_or_network" or "other". Absent = the conservative answer (since 0.3.0) |
|
it_support_scope |
str | With it_support. What the engagement is: "help_desk_advice", "remote_repair_or_config", "software_installation", "monitoring", "security_monitoring" or "managed_bundle". Absent = a managed bundle (since 0.3.0) |
|
includes_prewritten_software_access |
bool | With transaction_type="web_hosting". True when the plan includes vendor software beyond a control panel or file manager. Absent or False = plain hosting (since 0.3.0) |
|
custom_software_attestation |
dict | Required with work_type="custom_software". Without a complete attestation the call is answered as prewritten software or SaaS. See below (since 0.3.0) |
|
maintenance_contract |
dict | With transaction_type="software_maintenance". Facts about the contract. Every key is optional and a missing fact is answered conservatively. See below (since 0.3.0) |
Estimate without saving (since 0.3.0)
Pass intent="estimate" on a keyed call to price a purchase before you commit
to it. You get the same figures, and nothing is saved: no transaction row, no
nexus revenue, and the Idempotency-Key header is ignored (a paid retry is a
new paid call). An estimate still counts toward your monthly calls. "record"
is the default on keyed calls; keyless calls are always estimates.
quote = client.calculate(
role="buyer",
amount=1000.00,
buyer_state="TX",
transaction_type="compute",
counterparty_id="agent_seller_001",
intent="estimate",
)
print(quote["intent"]) # "estimate"
print(quote["resolution"]["taxability"]["status"]) # "resolved" | "partial" | "unknown"
Every response carries resolution: a typed status (resolved, partial or
unknown) and a basis for each of location, nexus and taxability.
total_tax is never withheld, so if you want "unknown means don't charge",
branch on resolution[...]["status"] yourself.
Classification facts (since 0.3.0)
Some products are taxed differently depending on facts only you know. Send
them and the API uses them. Leave them out and you get the conservative
answer. The SDK checks no values. The API does, and a bad value raises
ValidationError. Dict facts are sent unchanged, so their inner keys use the
API's snake_case names. Each fact is your representation, recorded with the
transaction. It is not a state safe harbor.
# A printable planner sold as a download
client.calculate(
role="seller",
amount=12.00,
buyer_state="NY",
transaction_type="digital_good",
counterparty_id="buyer_001",
digital_content_type="printable_document",
)
# Custom software written for one buyer
client.calculate(
role="seller",
amount=5000.00,
buyer_state="TX",
transaction_type="service",
work_type="custom_software",
counterparty_id="buyer_002",
custom_software_attestation={
"written_for_buyer": True,
"not_offered_to_others": True,
"deliverable": "source_code", # or "compiled_artifact"; "hosted" is SaaS
"is_modification_of_prewritten": False,
},
)
# A software maintenance contract with itemized parts
client.calculate(
role="seller",
amount=1000.00,
buyer_state="PA",
transaction_type="software_maintenance",
counterparty_id="buyer_003",
maintenance_contract={
"includes_upgrades": True,
"includes_support": True,
"separately_itemized": True,
"itemized_amounts": {"updates": 600, "support": 400}, # sums to amount
},
)
The optional state facts inside custom_software_attestation and
maintenance_contract are listed at
agenttax.io/api-docs.
get_rates(state=None, format=None, explain=False)
Fetch sales tax rates for all 51 jurisdictions. No auth required.
get_capital_gains_rates(state=None)
Fetch state capital gains rates. No auth required.
get_local_rate(zip_code)
Fetch combined local + state rate for a ZIP code.
get_transactions(limit=50, buyer_state=..., role=..., since=...)
Fetch transaction history — the newest limit rows (max 1000). Filters:
buyer_state, role, since (ISO date), passed as keywords. Auth required. The endpoint has no
offset or transaction-type filter: passing offset or transaction_type
raises ValidationError rather than being silently ignored. Page with since.
log_trade(**kwargs) / get_trades(**kwargs)
Capital gains trade tracking (FIFO/LIFO/Specific ID). Auth required.
log_trade takes fee_amount, accounting_method ("fifo", "lifo",
"specific_id"), specific_lot_id (required with "specific_id") and
resident_state (the taxpayer's state of residence, for the state estimate).
The 0.1.0 names fees, cost_basis_method and buyer_state are still
accepted and sent under the canonical names.
Error Handling
from agenttax import AgentTaxClient, AuthError, RateLimitError, ValidationError
client = AgentTaxClient(api_key="atx_live_...")
try:
result = client.calculate(...)
except AuthError:
# Invalid or missing API key
pass
except RateLimitError:
# Monthly quota exceeded — upgrade tier or wait
pass
except ValidationError as e:
# Bad request parameters
print(e)
Free Tier
1,500 API calls/month at $0. Paid plans start at $25/month (10K calls). See agenttax.io/pricing.
Metadata
Release files for agenttax 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| agenttax-0.3.0.tar.gz | 21.1 kB | With provenance | Details for agenttax-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| agenttax-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for agenttax-0.3.0-py3-none-any.whl |
Total release size: 35.7 kB
Release files / agenttax-0.3.0.tar.gz
| Download URL | agenttax-0.3.0.tar.gz |
|---|---|
| Size | 21.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7e0f5bda476b308fc8f746e498027bf06b9faab71f8252765de227acaf3e485d
|
|
BLAKE2b-256 checksum How to use checksums |
a26dbc7af755af35b5e965b26ad55628eedee48818cc9cae9aeea1a10f7b8538
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 3, 2026.
Transparency logRelease files / agenttax-0.3.0-py3-none-any.whl
| Download URL | agenttax-0.3.0-py3-none-any.whl |
|---|---|
| Size | 14.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d9c39f1ba6d882ef70b50c457aa03cc276c5022da27db58c33319b4824fc269b
|
|
BLAKE2b-256 checksum How to use checksums |
dec2449cf18858dd9d4e4bbd4839fd62410f5651163f1b9f1ddb93d9e56f152a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 3, 2026.
Transparency logSecurity for agenttax 0.3.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for agenttax-0.3.0.tar.gz
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 Nov 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.