> ## Documentation Index
> Fetch the complete documentation index at: https://docs.landedfees.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK

> Install, configure, and call every LandedFees v1 endpoint from Python 3.9+.

## Install

```bash theme={null}
pip install landedfees
# or
uv add landedfees
# or
poetry add landedfees
```

Python 3.9 or higher. The only runtime dependency is `requests`.

## Quick start

```python theme={null}
import os
from landedfees import LandedFeesClient

client = LandedFeesClient(api_key=os.environ["LANDEDFEES_API_KEY"])

response = client.calc({
    "destination_country": "US",
    "origin_country": "CN",
    "incoterm": "FOB",
    "transport_mode": "ocean",
    "currency": "USD",
    "freight": 250,
    "insurance": 45,
    "line_items": [{
        "description": "Wireless earbuds",
        "hs_code": "8517.62.00",
        "quantity": 500,
        "unit_value": 12.50,
        "origin_country": "CN",
        "weight_kg": 0.15,
    }],
})

print(response["result"]["total_landed_cost"], response["result"]["currency"])
```

## Full method surface

```python theme={null}
client.calc(body, *, idempotency_key=None, timeout=None)
client.calc_bulk(body, *, idempotency_key=None, timeout=None)
client.classify(body, *, idempotency_key=None, timeout=None)
client.compare(body, *, idempotency_key=None, timeout=None)
client.rates(country, hs, *, origin=None, calculation_date=None, timeout=None)
```

Every method returns the parsed JSON response body as a `dict`.

## Constructor options

```python theme={null}
LandedFeesClient(
    api_key: str,
    base_url: str = "https://www.landedfees.com",
    timeout: float = 30.0,      # seconds
    max_retries: int = 1,       # extra attempts on 429 / 5xx
    user_agent: str = "landedfees-python/0.1",
)
```

## Idempotency

Pass an `idempotency_key` to make retries safe. Repeat the same key
within 24 hours to get the cached response.

```python theme={null}
import uuid

key = str(uuid.uuid4())
first  = client.calc(payload, idempotency_key=key)
second = client.calc(payload, idempotency_key=key)
assert first["id"] == second["id"]
```

## Error handling

Non-2xx responses raise `ApiError`. The exception carries the status,
machine `code`, the parsed body, and `retry_after` (populated on
`429`).

```python theme={null}
from landedfees import ApiError

try:
    client.calc(payload)
except ApiError as err:
    if err.status == 429:
        time.sleep(err.retry_after or 60)
    elif err.status == 422 and err.code == "MISSING_HS_CODE":
        # Classify first, then retry.
        pass
    else:
        raise
```

The client retries once by default on `429` and `5xx`. Set
`max_retries=0` on the constructor to disable.

## Docstrings

Every method has a full docstring. In a REPL:

```python theme={null}
>>> from landedfees import LandedFeesClient
>>> help(LandedFeesClient.calc)
```

## Type checking

The package ships a `py.typed` marker. `mypy --strict` and `pyright`
both pass against the public surface. Response bodies are typed as
`Dict[str, Any]`; for stricter typing, layer the [OpenAPI spec](/api-reference/openapi.yaml)
through `datamodel-code-generator` or `openapi-python-client`.

## Repository and issues

* Source: [github.com/landedfees/sdk-python](https://github.com/landedfees/sdk-python)
* Issues: [github.com/landedfees/sdk-python/issues](https://github.com/landedfees/sdk-python/issues)
* License: Apache-2.0
