Python SDK for the Neo Tariff API
Project description
neo-tariff
Python SDK for the Neo Tariff API — US tariff duty calculation, HTS code search, and trade data.
Installation
pip install neo-tariff
Or install a specific pre-release:
pip install neo-tariff --pre
Release channels
mainchannel: publishes stable builds to PyPI (https://pypi.org/project/neo-tariff/).developchannel: publishes.devbuilds to TestPyPI (https://test.pypi.org/project/neo-tariff/), intended for integration with the develop TRD environment.
Maintainer runbook (sync + publishing pipeline):
- Internal
tariff-reference-datarepo:docs/SDK_RELEASE_PROCESS.md
Install from TestPyPI:
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple neo-tariff --pre
Quick start
from neo_tariff import NeoTariff
# Zero-config: reads NEO_TARIFF_API_KEY (and optional base URL/retry settings)
client = NeoTariff()
result = client.rates.evaluate_entry(
hts_code="7208.10.15",
country_of_origin="CN",
cost=10_000,
qty=1_000,
)
data = result.data # CalcResponse (typed Pydantic model)
if data.summary:
net = data.summary.duty_totals.get("net")
if net:
print(f"Total duty: ${net.total:,.2f}")
Authentication
The SDK auto-detects your API key from the NEO_TARIFF_API_KEY environment variable:
export NEO_TARIFF_API_KEY="ntf_..."
from neo_tariff import NeoTariff
# Zero-config: reads NEO_TARIFF_API_KEY from environment
client = NeoTariff()
# Or pass explicitly (overrides env var)
client = NeoTariff(api_key="ntf_...")
The base URL can also be configured via environment variable for dev/staging:
export NEO_TARIFF_BASE_URL="https://staging.tariff-data.enterprise-neo.com"
You can also configure timeout/retry behavior with environment variables:
export NEO_TARIFF_TIMEOUT="30" # seconds
export NEO_TARIFF_MAX_RETRIES="2" # non-negative integer
If your project keeps credentials in a local .env file, load directly with:
from neo_tariff import NeoTariff
client = NeoTariff.from_env_file(".env")
Resources
Rates — Tariff duty calculation
# Single entry
result = client.rates.evaluate_entry(
hts_code="7208.10.15",
country_of_origin="CN",
cost=10_000,
qty=1_000,
reciprocal=True, # Include Ch.99 reciprocal tariffs
)
# result.data → CalcResponse
# Batch (up to 1000 entries)
result = client.rates.evaluate_entries(
data=[
{"hts_code": "7208.10.15", "country_of_origin": "CN", "cost": 10000, "qty": 1000},
{"hts_code": "8471.30.01", "country_of_origin": "JP", "cost": 5000, "qty": 100},
]
)
# result.data → list[CalcResponse]
# Multi-country comparison for one HTS code
result = client.rates.evaluate_multicountry(
hts_code="7208.10.15",
countries=["CN", "DE", "JP"],
cost=10_000,
qty=1_000,
)
# result.data → list[CalcResponse]
Search — HTS code lookup
# Search by description
result = client.search.hts(query="steel plates", limit=10)
# result.data → list[APIRespSearchHtsItem]
for item in result.require_data():
print(f"{item.hts_code}: {item.description}")
# Autocomplete by code prefix
result = client.search.autocomplete_hts(prefix="7208", limit=5)
# result.data → list[APIRespAutocompleteHtsItem]
# Natural language description search
result = client.search.hts_by_description(query="cold rolled steel sheets")
# result.data → list[APIRespAutocompleteHtsItem]
# Full-text document search (sections, chapters, codes, notes)
result = client.search.hts_docs(query="steel", limit=10)
# result.data → dict (untyped — complex nested structure)
Context — HTS structure and country data
# HTS code context with rates
result = client.context.get_hts_code("7208.10.15")
# result.data → APIRespDataHtsCodeHub
# Detailed code info
result = client.context.get_hts_details("7208100000")
# result.data → APIRespDataHtsCodeContext
print(result.data.description, result.data.indent_level)
# Batch HTS hub context
result = client.context.get_hts_hub_batch(["7208.10.15", "8471.30.01"])
# result.data → dict[str, Any]
# List HTS sections
result = client.context.list_sections()
# List chapters in a section
result = client.context.list_chapters_by_section("1")
# Country lookup
result = client.context.get_country("CN")
# result.data → CountryRecord
print(result.data.country_name, result.data.programs)
# Batch country lookup
result = client.context.get_countries_batch(["CN", "DE"])
# result.data → dict[str, CountryRecord]
# All countries
result = client.context.list_countries()
# result.data → list[CountryRecord]
Compare — Version and country diffs
# Compare tariff across countries
result = client.compare.tariff(
hts_code="7208.10.15",
countries=["CN", "DE"],
cost=10_000,
qty=1_000,
)
# result.data → dict[str, CalcResponse]
# Compare HTS rates between versions
result = client.compare.hts_rates(
"7208.10.15",
year_a=2025, version_a=15,
year_b=2025, version_b=25,
)
# result.data → CompareRatesResponse
# Compare two source versions
result = client.compare.sources(
year_a=2025, version_a=15,
year_b=2025, version_b=25,
)
# result.data → CompareSourcesResponse
Versions — Available HTS revisions
result = client.versions.list()
# result.data → list[HtsSourceVersion]
for v in result.require_data():
print(f"Year {v.year} v{v.version} {'(active)' if v.is_active else ''}")
Async usage
Every resource method has an async counterpart:
from neo_tariff import AsyncNeoTariff
async def main():
async with AsyncNeoTariff(api_key="ntf_...") as client:
result = await client.rates.evaluate_entry(
hts_code="7208.10.15",
country_of_origin="CN",
cost=10_000,
qty=1_000,
)
print(result.data.totals)
Response envelope
All methods return APIResponse[T]:
result = client.versions.list()
result.success # bool
result.data # T (the typed payload)
result.meta # APIMeta | None (timestamp, operation, hts_year, etc.)
result.errors # list[APIRespError] | None
# Convenience: raises NeoTariffError if data is None
data = result.require_data()
Raw response access
For debugging or when you need the raw HTTP response:
raw = client.with_raw_response.versions.list()
raw.http_response.status_code # 200
raw.parsed # APIResponse or None
Error handling
from neo_tariff import (
NeoTariffError, # Base for all SDK errors
NeoTariffHTTPError, # Non-2xx HTTP response
AuthenticationError, # 401/403
NotFoundError, # 404
ValidationError, # 422
RateLimitError, # 429
ServerError, # 500+
NeoTariffAPIError, # 2xx but success=False
NeoTariffConnectionError, # Network/timeout errors
)
try:
result = client.rates.evaluate_entry(...)
except AuthenticationError:
print("Check your API key")
except RateLimitError:
print("Slow down!")
except NeoTariffHTTPError as e:
print(f"HTTP {e.status_code}: {e.message}")
except NeoTariffAPIError as e:
print(f"API error: {e.errors}")
except NeoTariffConnectionError:
print("Network issue")
Retry logic
The SDK automatically retries transient failures (408, 429, 500, 502, 503, 504 and network errors) with exponential backoff:
client = NeoTariff(api_key="ntf_...", max_retries=2) # Default: 2 retries
client = NeoTariff(api_key="ntf_...", max_retries=0) # Disable retries
client = NeoTariff(api_key="ntf_...", max_retries=5) # More retries for batch jobs
Configuration
client = NeoTariff(
api_key="ntf_...", # Or NEO_TARIFF_API_KEY env var
base_url="https://tariff-data.enterprise-neo.com", # Or NEO_TARIFF_BASE_URL env var
timeout=30.0, # Or NEO_TARIFF_TIMEOUT env var
max_retries=2, # Or NEO_TARIFF_MAX_RETRIES env var
)
| Environment variable | Description |
|---|---|
NEO_TARIFF_API_KEY |
API key (used when api_key= not passed) |
NEO_TARIFF_BASE_URL |
API base URL (used when base_url= not passed) |
NEO_TARIFF_TIMEOUT |
Request timeout in seconds (used when timeout= not passed) |
NEO_TARIFF_MAX_RETRIES |
Retry count for transient failures (used when max_retries= not passed) |
NEO_TARIFF_LOG |
Set to debug to log HTTP requests/responses |
Typed response models
All models use ConfigDict(extra="allow") — new API fields are preserved without breaking existing code.
| Method | Return type |
|---|---|
rates.evaluate_entry() |
APIResponse[CalcResponse] |
rates.evaluate_entries() |
APIResponse[list[CalcResponse]] |
rates.evaluate_multicountry() |
APIResponse[list[CalcResponse]] |
search.hts() |
APIResponse[list[APIRespSearchHtsItem]] |
search.autocomplete_hts() |
APIResponse[list[APIRespAutocompleteHtsItem]] |
search.hts_by_description() |
APIResponse[list[APIRespAutocompleteHtsItem]] |
search.hts_docs() |
APIResponse[Any] |
context.get_hts_code() |
APIResponse[APIRespDataHtsCodeHub] |
context.get_hts_details() |
APIResponse[APIRespDataHtsCodeContext] |
context.get_hts_hub() |
APIResponse[Any] |
context.get_hts_hub_batch() |
APIResponse[dict[str, Any]] |
context.get_hts_history() |
APIResponse[Any] |
context.get_document_index() |
APIResponse[Any] |
context.get_document() |
APIResponse[Any] |
context.list_sections() |
APIResponse[Any] |
context.list_chapters_by_section() |
APIResponse[Any] |
context.get_countries_batch() |
APIResponse[dict[str, CountryRecord]] |
context.list_countries() |
APIResponse[list[CountryRecord]] |
context.get_country() |
APIResponse[CountryRecord] |
compare.tariff() |
APIResponse[dict[str, CalcResponse]] |
compare.hts_rates() |
APIResponse[CompareRatesResponse] |
compare.sources() |
APIResponse[CompareSourcesResponse] |
versions.list() |
APIResponse[list[HtsSourceVersion]] |
Request models (optional)
For IDE autocomplete on request bodies:
from neo_tariff.types import CalcInputs
inputs = CalcInputs(
hts_code="7208.10.15",
country_of_origin="CN",
cost=10_000,
qty=1_000,
)
result = client.rates.evaluate_entry(**inputs.model_dump())
Requirements
Development
git clone https://github.com/Enterprise-Neo/neo-tariff-python.git
cd neo-tariff-python
pip install -e ".[dev]"
# Run tests
python -m pytest tests/ -q
# Lint
ruff check . --fix && ruff format .
Project details
Release history Release notifications | RSS feed
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 neo_tariff-0.2.0.tar.gz.
File metadata
- Download URL: neo_tariff-0.2.0.tar.gz
- Upload date:
- Size: 41.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf3c4b469ab9d1cc7143fea0ac43d9186033f25b196bc7169129463ad406272a
|
|
| MD5 |
c670fe158d07dc47b92faa81bfbc14b3
|
|
| BLAKE2b-256 |
04130442609e247b6c484cd4c4ae839d2117cbbb8c0c9bdc6123639efce4aa28
|
Provenance
The following attestation bundles were made for neo_tariff-0.2.0.tar.gz:
Publisher:
publish.yml on Enterprise-Neo/neo-tariff-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
neo_tariff-0.2.0.tar.gz -
Subject digest:
cf3c4b469ab9d1cc7143fea0ac43d9186033f25b196bc7169129463ad406272a - Sigstore transparency entry: 1042921840
- Sigstore integration time:
-
Permalink:
Enterprise-Neo/neo-tariff-python@c8a2aa8fe57e67ed3da967d7d80ee8ed26b53232 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Enterprise-Neo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c8a2aa8fe57e67ed3da967d7d80ee8ed26b53232 -
Trigger Event:
push
-
Statement type:
File details
Details for the file neo_tariff-0.2.0-py3-none-any.whl.
File metadata
- Download URL: neo_tariff-0.2.0-py3-none-any.whl
- Upload date:
- Size: 42.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33aa9ede0ad51d17816a99fcf7d493a6ae9a83f4c05f7819dc2b674b007b0a4a
|
|
| MD5 |
01dd7addc82fdea6638f594e5981b49e
|
|
| BLAKE2b-256 |
5e2bc909147e215097c36c9ba5200efab36c88ad3671bd1ee1c5b51fc82d3fbc
|
Provenance
The following attestation bundles were made for neo_tariff-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on Enterprise-Neo/neo-tariff-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
neo_tariff-0.2.0-py3-none-any.whl -
Subject digest:
33aa9ede0ad51d17816a99fcf7d493a6ae9a83f4c05f7819dc2b674b007b0a4a - Sigstore transparency entry: 1042921844
- Sigstore integration time:
-
Permalink:
Enterprise-Neo/neo-tariff-python@c8a2aa8fe57e67ed3da967d7d80ee8ed26b53232 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Enterprise-Neo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c8a2aa8fe57e67ed3da967d7d80ee8ed26b53232 -
Trigger Event:
push
-
Statement type: