Thai VAT tax ID lookup with 10/13-digit support (RD VATINFO)
Project description
phasi-kit
Thai VAT tax ID lookup client for the Revenue Department (RD) VATINFO service.
Overview
- NEW: Smart unified API - Auto-detects 10/13 digits, handles single/multi results intelligently
- NEW: Full async support - High-performance async client with connection pooling
- Auto-routing - Automatically validates and routes 10 or 13-digit tax IDs
- Parse TIS-620 HTML into structured
TaxInfoobjects - Robust requests with retries, backoff, and rate limiting
- Detailed logging via loguru for debugging
Requirements
- Python 3.10+
Installation
- Using pip (editable):
pip install -e . - Using uv (fast installer):
- Create/activate a virtualenv
- Install editable:
uv pip install -e . - With test extras:
uv pip install -e ".[test]"
Quickstart
New Unified API (Recommended)
from phasi_kit import lookup, lookup_async
# Smart sync lookup - auto-detects 10/13 digits
result = lookup("0107555000023") # Works with spaces/dashes too: "0107-555-000023"
# Intelligently handles single or multiple results
if result.is_single:
print(result.company_name) # Direct access for single result
else:
for info in result: # Iterate through multiple branches
print(f"Branch {info.branch_no}: {info.company_name}")
# Or simply use .first for the most common case
print(result.first.company_name)
# Async version for high performance
import asyncio
async def check_tax():
result = await lookup_async("3031571440") # Auto-detects 10-digit
return result.first.company_name
company = asyncio.run(check_tax())
Legacy API (Still Supported)
from phasi_kit import get_tax_info, get_tax_infos
# First matching result
info = get_tax_info("0107555000023")
print(info.company_name, info.address, info.status)
# All rows (multiple branches)
rows = get_tax_infos("0107555000023")
for r in rows:
print(r.branch_no, r.company_name)
API
New Unified API
-
lookup(tax_id: str, branch_no: str | None = None) -> TaxInfoResult- Smart sync lookup with auto-detection of 10/13 digits
- Returns
TaxInfoResultwrapper that handles single/multi results intelligently - Automatically cleans input (removes spaces, dashes)
-
lookup_async(tax_id: str, branch_no: str | None = None) -> TaxInfoResult- Async version with same smart features
- Uses connection pooling for high performance
-
TaxInfoResult- Smart wrapper with:.is_single- Check if single result.first- Get first result (works for any case).all- Get all results as list.count- Number of results- Direct iteration:
for info in result: - Branch helpers:
.get_branch("0"),.hq,.branches
Clients
-
VATInfoClient- Enhanced sync client with:- Auto-routing for 10/13 digit tax IDs
- Connection pooling (
max_connections,max_keepalive_connections) - Automatic retries with exponential backoff
- Rate limiting support
-
AsyncVATInfoClient- Full async client with:- All features of sync client
- Async/await support
- Request coalescing for concurrent identical requests
- Context manager support:
async with AsyncVATInfoClient() as client:
Legacy API (Backward Compatible)
get_tax_info()- Returns singleTaxInfoget_tax_infos()- Returnslist[TaxInfo]- Original
VATInfoClientmethods still available
Examples
Smart Result Handling
from phasi_kit import lookup
# Auto-detects format and cleans input
result = lookup("0107-555-000023") # Works with dashes
result = lookup("0107 555 000023") # Works with spaces
result = lookup("0107555000023") # Works with clean input
# Smart accessors
print(result.company_name) # Direct attribute access (proxies to first)
print(result.first.address) # Explicitly get first result
print(result.count) # Number of results
# Branch operations
if result.has_branch("1"):
branch1 = result.get_branch("1")
print(branch1.company_name)
hq = result.hq # Get headquarters (branch "0")
print(f"Branches: {result.branches}") # List all branch numbers
Async High Performance
import asyncio
from phasi_kit import AsyncVATInfoClient
async def check_multiple():
async with AsyncVATInfoClient(
max_connections=20, # Connection pooling
enable_coalescing=True, # Dedupe concurrent identical requests
) as client:
# These run concurrently
results = await asyncio.gather(
client.lookup_smart("0107555000023"),
client.lookup_smart("3031571440"),
client.lookup_smart("0105547127301"),
)
return [r.first.company_name for r in results]
companies = asyncio.run(check_multiple())
Validation with Auto-Routing
from phasi_kit import validate_and_route_tax_id
# Validate and get routing info
validation = validate_and_route_tax_id("0107-555-000023")
if validation.is_valid:
print(f"Type: {validation.tax_id_type}") # "13"
print(f"Cleaned: {validation.cleaned_id}") # "0107555000023"
else:
print(f"Error: {validation.error_message}")
Logging
- This package uses loguru. Configure sinks/levels in your app:
from loguru import logger
logger.remove()
logger.add(sys.stderr, level="INFO")
Messages include request attempts, backoff decisions, not-found cases, and parsing fallbacks.
Features
Auto-Routing
- Automatically detects 10 vs 13 digit tax IDs
- Cleans input (removes spaces, dashes, dots)
- Detailed validation with specific error messages
- Caches validation results for performance
Performance
- Connection pooling for reusing HTTP connections
- Async support for concurrent lookups
- Request coalescing (deduplicates concurrent identical requests)
- Optional response caching with TTL
Robust Error Handling
TaxValidationError: Invalid tax ID format or checksumTaxNotFoundError: Valid ID but no record foundTaxLookupError: Network/HTTP failures- Automatic retries with exponential backoff
- Detailed loguru debugging throughout
Environment
PHASI_VATINFO_URL: Override the default RD endpoint if needed.
Notes
- Auto-detection works with any format: "0107555000023", "0107-555-000023", "0107 555 000023"
- The smart API eliminates the need to know beforehand if a tax ID has multiple branches
- RD HTML is TIS-620 encoded; decoding is handled automatically
- Branch numbers:
0= HQ,1-99998= branch offices - All async operations use connection pooling for optimal performance
Development
- Run tests:
pytest -q
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 phasi_kit-0.2.1.tar.gz.
File metadata
- Download URL: phasi_kit-0.2.1.tar.gz
- Upload date:
- Size: 36.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16589856a86114d6214807144965a79369b49d74eb987f5565d4f449f1167e65
|
|
| MD5 |
c6c37f59efc3cb124de441791c11f304
|
|
| BLAKE2b-256 |
2ec53ebe971170bc68c9263371c96f287e1e86f39cad4366cf55fe1ef93d5313
|
File details
Details for the file phasi_kit-0.2.1-py3-none-any.whl.
File metadata
- Download URL: phasi_kit-0.2.1-py3-none-any.whl
- Upload date:
- Size: 27.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a08c0547e0e8100ae2172d2d87784b1017a8869518c8ab609239802020a9d335
|
|
| MD5 |
13b38d4186cbeb0908235d57d46935d7
|
|
| BLAKE2b-256 |
27a363eae456801692e0ced08e6df41c4d4f8bc8010d4edb5f8ecddf1d688deb
|