Releases: seamapi/python
Release list
v3.8.0
v3.7.0
v3.6.1
v3.6.0
v3.5.0
v3.4.0
v3.3.0
v3.2.0
v3.1.0
v3.0.0
Migrating from seam v2 to v3
This guide covers upgrading from seam v2.x to v3 of the Seam Python SDK.
Version 3 replaces the underlying HTTP library, adds client-side validation and explicit null support, and regenerates the API surface against the latest Seam API. Most application code — authentication, method names, resource models, action attempts, and pagination — works unchanged. The breaking changes are concentrated in client configuration and error handling.
Installation
pip install --upgrade 'seam>=3,<4'Summary of breaking changes
| Change | Affects you if... |
|---|---|
| Python 3.11+ required | You run Python 3.10 |
| httpx replaces niquests | You pass niquests_options, catch niquests exceptions, or touch seam.client directly |
retries takes an httpx_retries.Retry |
You pass a custom retries option |
| Endpoints validate parameters client-side | You call endpoints with no parameters, or rely on the server's 400 response |
lts_version removed |
You read Seam.lts_version or the seam-lts-version header |
| Preferred HTTP methods and URL search params | You inspect traffic in a proxy, mock server, or firewall rules |
Python 3.11 or later is required
Version 2 supported Python 3.10. Version 3 requires Python >= 3.11 and is tested on Python 3.11 through 3.14.
httpx replaces niquests
The SDK's HTTP layer is now httpx instead of niquests. This surfaces in three places.
The niquests_options option is renamed to httpx_options
Options are now passed to the underlying httpx.Client, so both the option name and its contents change. For example, connection pool limits:
# v2
seam = Seam(
api_key="your-api-key",
niquests_options={"pool_connections": 20, "pool_maxsize": 25},
)
# v3
from httpx import Limits
seam = Seam(
api_key="your-api-key",
httpx_options={
"limits": Limits(max_connections=25, max_keepalive_connections=20),
},
)This applies to Seam(), Seam.from_api_key(), Seam.from_personal_access_token(), and SeamWithoutWorkspace.
Transport-level exceptions are httpx exceptions
Requests that time out now raise httpx.TimeoutException instead of niquests.exceptions.Timeout, and connection failures raise httpx transport errors (httpx.ConnectError, etc.) instead of niquests/urllib3 ones.
# v2
import niquests
try:
seam.devices.list()
except niquests.exceptions.Timeout:
...
# v3
import httpx
try:
seam.devices.list()
except httpx.TimeoutException:
...Seam API errors are unchanged: SeamHttpApiError, SeamHttpInvalidInputError, and SeamHttpUnauthorizedError are raised exactly as in v2.
seam.client is an httpx.Client
If you access the client directly, it is now an httpx.Client subclass rather than a niquests Session. Notably, response hooks are registered via event_hooks instead of hooks.
Retry configuration uses httpx-retries
The retries option now takes a Retry object from httpx-retries instead of urllib3.util.retry.Retry. The class is re-exported from seam for convenience:
# v2
from urllib3.util.retry import Retry
seam = Seam(api_key="your-api-key", retries=Retry(total=3))
# v3
from seam import Seam, Retry
seam = Seam(
api_key="your-api-key",
retries=Retry(total=3, backoff_factor=0.5, status_forcelist=[503]),
)The default retry policy is now explicit and documented. Out of the box, the SDK makes up to three attempts: the initial request and two retries. Retries are limited to GET, HEAD, OPTIONS, PUT, and DELETE requests that fail because of a transport error, timeout, HTTP 429 response, or HTTP 5xx response. POST and PATCH requests are never retried. Retries use exponential backoff with jitter, and a Retry-After header is honored instead of the calculated backoff.
In v2, the default was urllib3's implicit Retry() (connection-level retries only, with no retries on HTTP status codes such as 429 or 5xx). If you depended on requests never being retried on 429/5xx, pass an explicit policy, e.g. retries=Retry(total=0).
Client-side parameter validation
Endpoints that require at least one parameter now raise ValueError locally instead of sending the request and letting the server reject it:
# v2: raises SeamHttpInvalidInputError after a round trip to the server
# v3: raises ValueError("At least one parameter is required for /locks/get")
seam.locks.get()create_paginator is validated the same way. It raises ValueError when given a non-paginated endpoint, and when given an endpoint that requires parameters without any:
# v3: raises ValueError - /devices/get is not paginated
seam.create_paginator(seam.devices.get)If you catch SeamHttpInvalidInputError around calls that could be sent with no parameters, also handle ValueError (or fix the call site).
lts_version is removed
The Seam.lts_version / SeamWithoutWorkspace.lts_version attribute and the seam-lts-version request header no longer exist. There is no replacement; use the package version instead:
from importlib.metadata import version
version("seam")Endpoints use preferred HTTP methods
In v2, every endpoint was called with POST and a JSON body. In v3, endpoints use the HTTP method the Seam API prefers:
- Read endpoints (
get,list, and friends) useGET, with parameters sent as URL search params serialized per Seam's URL search params standard. - Update endpoints use
PATCHorPUT. - Delete endpoints use
DELETE. - Create and action endpoints (
create,lock_door, etc.) remainPOST.
Method signatures, arguments, and return values are unchanged — this only matters if something outside your code observes the HTTP traffic: proxy or firewall rules that allowlist methods, request logging, or test mocks registered against POST routes. Note the interaction with the new retry defaults: because reads are now GET, they are retried by default, which they were not in v2 (as POST).
If you call the Seam API with your own HTTP client, the serializer used for GET params is exported:
import httpx
from seam import serialize_url_search_params
httpx.get(
"https://connect.getseam.com/devices/list",
params=serialize_url_search_params({"device_ids": ["device1", "device2"]}),
headers={"Authorization": "Bearer your-api-key"},
)New in v3
These are additions, not breaking changes, but they are worth adopting while you migrate.
Explicit null with NULL
The Seam API distinguishes an omitted parameter from one explicitly set to null: in an update request, an omitted parameter leaves the current value unchanged, while a null parameter unsets it. Version 2 had no way to send null — None always meant "omit". Version 3 keeps that behavior for None and adds a NULL sentinel for sending an explicit null:
from seam import NULL, Seam
seam = Seam()
# Leaves the name unchanged (same as v2).
seam.devices.update(device_id="your-device-id", name=None)
# Unsets the name (new in v3).
seam.devices.update(device_id="your-device-id", name=NULL)Only parameters the Seam API documents as nullable are typed to accept NULL, so a type checker will flag misuse. The sentinel's type is exported as Null for annotating your own code.
New exports
seam now exports NULL, Null, Retry (from httpx-retries), UrlSearchParams, serialize_url_search_params, update_url_search_params, and UnserializableParamError, alongside everything exported in v2.
Migration checklist
- Upgrade your runtime to Python 3.11 or later.
- Update the dependency:
seam>=3,<4. - Rename
niquests_optionstohttpx_optionsand translate its contents tohttpx.Clientoptions. - Replace
urllib3.util.retry.Retrywithseam.Retry(httpx-retries) in anyretriesargument, and review the new default retry policy. - Replace handling of
niquests/urllib3exceptions with thehttpxequivalents (httpx.TimeoutException,httpx.ConnectError, ...). Seam error classes are unchanged. - Remove any use of
lts_versionor theseam-lts-versionheader. - Handle
ValueErrorfrom endpoints andcreate_paginatorwhere calls might carry no parameters. - If proxies, firewalls, or test mocks assume all requests are
POST, update them forGET/PATCH/PUT/DELETE. - Optionally, adopt
NULLwhere you need to unset nullable values.
Migrating from seam v1 to v2
If you are still on v1.x, migrate to v2 first (or apply both guides together). Version 2 is a much smaller upgrade than v3: client configuration, authentication, endpoint methods, and error handling are all unchanged. The break...