Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,129 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.3.0-beta] - 2026-08-07

Brings the SDK up to the v6.0 API surface documented at https://docs.zip.tax.
The headline addition is the **merchant layer**: 19 endpoints on
`api.zip-tax.com` that let a platform manage merchants and their transactions
using a single Ziptax API key, replacing per-merchant TaxCloud credentials.

Everything here is additive. No existing function changed its signature,
endpoint, or return type.

### Added

- **Merchant management** (Pro and Enterprise plans):
- `CreateMerchant(request)` -> `POST /merchant/create`
- `UpdateMerchant(request)` -> `POST /merchant/update`
- `DeleteMerchant(merchant_id)` -> `POST /merchant/delete`
- `GetMerchant(merchant_id)` -> `POST /merchant/get`
- `ListMerchants()` -> `GET /merchant/list`
- `SetMerchantCredentials(request)` -> `POST /merchant/credentials/set`
- `DeleteMerchantCredentials(merchant_id)` -> `POST /merchant/credentials/delete`
- **Merchant transactions**:
- `MerchantCalculateCart(request)` -> `POST /merchant/cart/calculate`
- `MerchantCreateOrder(request)` -> `POST /merchant/order/create`
- `MerchantCreateOrderFromCart(request)` -> `POST /merchant/order/create-from-cart`
- `MerchantGetOrder(request)` -> `POST /merchant/order/get`
- `MerchantUpdateOrder(request)` -> `POST /merchant/order/update`
- `MerchantCreateRefund(request)` -> `POST /merchant/refund/create`
- **Exemption certificates** (Enterprise):
- `CreateExemptionCertificate(request)` -> `POST /merchant/cert/create`
- `GetExemptionCertificate(request)` -> `POST /merchant/cert/get`
- `ListExemptionCertificates(request)` -> `POST /merchant/cert/list`
- `DeleteExemptionCertificate(request)` -> `POST /merchant/cert/delete`
- **TIC data and system**:
- `GetTicData()` -> `GET /data/tic` (full TIC list with category hierarchy)
- `GetTicSearchSchema()` -> `GET /schemas/ticsearch`
- `GetAccountUsage()` -> `GET /account/metrics` (core, geo, and merchant pools)
- `GetHealth()` -> `GET /system/health`
- `GetSystemMetadata()` -> `GET /system/metadata`
- **New v6.0 rate-lookup parameters** on `GetSalesTaxByAddress` and
`GetSalesTaxByGeoLocation`:
- `adjustment` ("auto", "origin", "destination")
- `address_detail_extended` - adds `address_detail.address` components
- `shipping_extended` - adds `shipping.shipping_extended`
- `sat_item_total` - Tennessee Single Article Tax
- `city` and `state` on the address lookup, for disambiguation
- `taxability_code` on the geolocation lookup
- **New parameters on `GetRatesByPostalCode`**: `state`, `city`, `county`,
`historical`, and `sat_item_total`
- **US territory country codes**: `country_code` now accepts `PRI`, `ASM`,
`GUM`, `MNP`, and `VIR` alongside `USA` and `CAN`
- **New response models**: `V60ProductDetail`, `V60TaxabilityCode`,
`V60RateRule`, `V60AddressComponents`, `V60ShippingExtended`,
`V60SingleArticleTax`, plus the full merchant, certificate, TIC data, and
system model set in the new `src/ziptax/models/merchant.py` module
- **Pagination fields on TIC search**: `ProductCodeSearchResponse.next_cursor`
and `.schema_url` (`$schema`). `results` also relaxed from required to
defaulting to `[]`, matching the published spec, which lists only `$schema`
and `query` as required. A response omitting `results` now parses to an
empty list rather than raising. The API sends `results: []` explicitly when
a query genuinely has no matches
- **Validators**: `validate_adjustment`, and `validate_merchant_id`, which
checks UUID format client-side so a malformed merchant ID fails fast with a
clear message rather than returning a 403 from the ownership check.
Ownership itself stays server-side
- **90 new tests** across `tests/test_merchant.py` (57) and
`tests/test_functions.py` (33), covering both merchant compliance models,
request serialization, response parsing, and validation. Suite is 249 tests
at 98% coverage

### Fixed

- **`RecommendProductCode` no longer raises on a failed prediction.** The API
returns `status: "fail"` with `error` populated and every other field null.
All `ProductCodeRecommendation` fields except `status` are now `Optional`,
so a failed prediction parses instead of raising a `ValidationError`.
Branch on `status` before reading `tic_id`.

### Deprecated

- The five direct-to-TaxCloud functions now emit a `DeprecationWarning`. They
call `api.v3.taxcloud.com` directly, which is no longer the documented
integration path. They continue to work unchanged.

| Deprecated | Replacement |
|---|---|
| `CreateOrder` | `MerchantCreateOrder` |
| `CreateOrderFromCart` | `MerchantCreateOrderFromCart` |
| `GetOrder` | `MerchantGetOrder` |
| `UpdateOrder` | `MerchantUpdateOrder` |
| `RefundOrder` | `MerchantCreateRefund` |

See "Migrating to the Merchant Layer" in the README.

### Notes

- `CalculateCart` is **not** deprecated and is unchanged. It uses the
account-level `POST /calculate/cart` endpoint, which still runs but is no
longer part of the published v6.0 API surface. Platform integrations serving
multiple merchants should prefer `MerchantCalculateCart`.
- `POST /merchant/credentials/get` exists in the API but is not published in
the documentation or OpenAPI spec, and returns stored TaxCloud credentials.
It is deliberately **not** exposed by the SDK.
- The merchant proxy rejects request bodies containing `apiKey`,
`connectionId`, or `xApiKey` with a 400. The SDK never sends these on
merchant transaction calls; credentials go only to
`SetMerchantCredentials`, which is a management endpoint.
- v6.0 postal-code-only lookups continue to return the legacy (v5.0-shaped)
flat response, so `GetRatesByPostalCode` still returns
`V60PostalCodeResponse`.
- Two API fields are genuinely snake_case among camelCase siblings, and the
SDK matches them deliberately: the `merchant_type` body field on
`POST /merchant/create`, and the `sat_item_total` query parameter on
`GET /request/v60`. Both are verified against the published OpenAPI spec
and the API source, and are commented in the code so they are not
"corrected" to camelCase later.

### Changed

- Version bumped from `0.2.6-beta` to `0.3.0-beta`
- `GetAccountMetrics` docstring clarifies that it targets
`GET /account/v60/metrics`; the new `GetAccountUsage` covers
`GET /account/metrics`

## [0.2.4-beta] - 2026-03-11

### Added
Expand Down
89 changes: 79 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ ziptax-python/
│ ├── exceptions.py # Custom exceptions
│ ├── models/ # Pydantic data models
│ │ ├── __init__.py
│ │ └── responses.py # API response models
│ │ ├── responses.py # Rate lookup, TIC search, cart, TaxCloud models
│ │ └── merchant.py # Merchant, certificate, TIC data, system models
│ ├── resources/ # API endpoint functions
│ │ ├── __init__.py
│ │ └── functions.py # ZipTax and TaxCloud functions
Expand All @@ -57,7 +58,8 @@ ziptax-python/
│ ├── http.py # HTTP client wrapper
│ ├── retry.py # Retry logic
│ └── validation.py # Input validation
├── tests/ # Test suite
├── tests/ # Test suite (see tests/test_merchant.py
│ # for the merchant layer)
├── examples/ # Usage examples
├── docs/ # Documentation
│ └── spec.yaml # OpenAPI-style specification
Expand Down Expand Up @@ -334,7 +336,8 @@ coverage report --fail-under=80
```
tests/
├── test_client.py # Client initialization and lifecycle
├── test_functions.py # API endpoint functions
├── test_functions.py # Rate lookups, TIC search, cart, TaxCloud
├── test_merchant.py # Merchant layer, TIC data, system endpoints
├── test_http.py # HTTP client functionality
├── test_retry.py # Retry logic
└── conftest.py # Shared fixtures
Expand Down Expand Up @@ -555,9 +558,39 @@ This file is used as a reference for code generation and documentation.
**Authentication**: X-API-Key header

**Endpoints**:
- `GET /request/v60/` - Tax rate lookup by address or geolocation
- `GET /account/v60/metrics` - Account usage metrics
- `POST /calculate/cart` - Cart tax calculation with per-item rates
- `GET /request/v60/` - Tax rate lookup by address, geolocation, or postal code
- `GET /account/v60/metrics` - Account metrics, simplified v6.0 shape
- `GET /account/metrics` - Account usage across core, geo, and merchant pools
- `GET /data/tic` - Full TIC list with category hierarchy
- `GET /schemas/ticsearch` - JSON Schema for the TIC search response
- `POST /search/tic` - Product code search
- `POST /search/tic/recommend` - AI-powered product code recommendation
- `GET /system/health` - Health check
- `GET /system/metadata` - Build and host info
- `POST /calculate/cart` - Cart tax calculation (legacy; see note below)

**Merchant endpoints** (all `POST` unless noted, all on `api.zip-tax.com`):
- `/merchant/create`, `/merchant/update`, `/merchant/delete`, `/merchant/get`
- `GET /merchant/list`
- `/merchant/credentials/set`, `/merchant/credentials/delete`
- `/merchant/cart/calculate`
- `/merchant/order/create`, `/merchant/order/create-from-cart`,
`/merchant/order/get`, `/merchant/order/update`
- `/merchant/refund/create`
- `/merchant/cert/create`, `/merchant/cert/get`, `/merchant/cert/list`,
`/merchant/cert/delete`

**Do not expose these** (present in the API, absent from the docs):
- `POST /merchant/credentials/get` - returns stored TaxCloud credentials
- `GET /request/v10` through `/v50` and their `/account/vN0/metrics` siblings
- `GET /request/v60/schema`, `GET /account/metadata`,
`GET /metadata/response.json`, `GET /request/error`
- The `tracerate=true` query parameter (undocumented diagnostic)

The rule: anything documented at https://docs.zip.tax may be exposed as an SDK
function. Anything present only in the API source must not be. When adding a
function, confirm it appears in
`https://docs.zip.tax/openapi/api-reference.json` first.

**Response Format**: JSON with nested structure

Expand All @@ -573,7 +606,42 @@ This file is used as a reference for code generation and documentation.
}
```

### TaxCloud API
### Merchant Layer (preferred path for transactions)

**Base URL**: `https://api.zip-tax.com/`

**Authentication**: the caller's Ziptax `X-API-Key`. Merchants are addressed by
`merchantId` in the request body; per-merchant TaxCloud credentials are stored
server-side via `/merchant/credentials/set`.

Ziptax routes each call on the merchant's compliance model:

| | Self-managed (`external_compliance`) | TaxCloud-connected |
|---|---|---|
| Calculation | In-process Ziptax rate engine | Forwarded to TaxCloud |
| Persisted | No | Yes |
| Discounts | Not supported | Supported |
| Endpoints | `/merchant/cart/calculate` only | All |
| Plan | Pro and Enterprise | Enterprise |

Two constraints that shape the SDK code:

1. **Reserved keys are rejected.** The proxy 400s on any request body
containing `apiKey`, `connectionId`, or `xApiKey` (case-insensitive). Never
put credentials in a transaction request body. `SetMerchantCredentials` is a
management endpoint, not a proxy endpoint, so it is the one exception.
2. **Response shape varies by model.** `/merchant/cart/calculate` returns
`connectionId`, `transactionDate`, `deliveredBySeller`, and `exemption` only
on the TaxCloud path. `MerchantCalculateCartResponse` marks all four
`Optional` so a single model covers both.

### TaxCloud API (Deprecated)

Deprecated as of 0.3.0. `CreateOrder`, `GetOrder`, `UpdateOrder`,
`RefundOrder`, and `CreateOrderFromCart` call TaxCloud directly and emit a
`DeprecationWarning` via `_warn_taxcloud_direct()`. They still work; do not
remove them without a major version bump. New transaction work goes through the
merchant layer above.

**Base URL**: `https://api.v3.taxcloud.com/`

Expand Down Expand Up @@ -765,7 +833,8 @@ The project uses GitHub Actions (when configured) to:
### Code Examples

- `examples/basic_usage.py` - Basic ZipTax usage
- `examples/taxcloud_orders.py` - TaxCloud order management
- `examples/merchant_compliance.py` - Merchant management and transactions
- `examples/taxcloud_orders.py` - TaxCloud order management (deprecated path)
- `examples/async_usage.py` - Concurrent operations
- `examples/error_handling.py` - Error handling patterns

Expand All @@ -786,6 +855,6 @@ For API-specific questions:

---

**Last Updated**: 2025-02-19
**SDK Version**: 0.2.6-beta
**Last Updated**: 2026-08-07
**SDK Version**: 0.3.0-beta
**Maintained By**: ZipTax Team
Loading
Loading