Python SDK
The Python SDK wraps the customer API behind a synchronous Client and an
asynchronous AsyncClient. Both clients expose the same services, for example
client.objects and client.tasks. The only runtime dependency is
httpx, and the package is fully typed.
See the SDKs overview for the concepts all SDKs share and
common workflows for side-by-side examples.
- Package: seventhings-customer-api on PyPI
- Repository: github.com/seventhingsCompany/customer-api-python
- Requires Python 3.10 or newer.
Installation
Section titled “Installation”pip install seventhings-customer-api# oruv add seventhings-customer-apiThe import name is seventhings.
Creating a client
Section titled “Creating a client”Every client takes your instance URL. The SDK appends /customer-api/v1 for
you.
Use credentials when your application should log in during client setup:
from seventhings import Client
with Client.with_credentials( "https://your-instance.seventhings.com", "user@example.com", "password", "your-client-id",) as client: ...Use an existing token when another part of your application already completed the auth flow:
client = Client( "https://your-instance.seventhings.com", token="access-token", client_id="your-client-id",)Construct a client without a token for manual login or custom transport setup.
Pass http_client to reuse your own httpx.Client. The SDK never closes a
client you pass in. The default timeout is 30 seconds; timeout=None disables
it.
import httpx
client = Client( "https://your-instance.seventhings.com", http_client=httpx.Client(timeout=10),)tok = client.auth.login("user@example.com", "password", "your-client-id")# login stores tok.access_token and the client ID on the client.The other auth methods are client.auth.refresh(refresh_token),
client.auth.login_sso(provider, auth_code, client_id, app_target), and
client.auth.revoke_tokens(). You can read or replace the current bearer token
through the client.token attribute.
AsyncClient mirrors Client. The differences are:
- every method is a coroutine,
- the
all()iterators are async iterators, - the client is closed with
aclose()orasync with.
from seventhings import AsyncClient
async with await AsyncClient.with_credentials(url, user, password, client_id) as client: obj = await client.objects.get(uuid) async for room in client.rooms.all(): print(room.name)Resource methods
Section titled “Resource methods”Resources are services on the client:
objects,rooms,locationspersons,usersfiles,tasks,rentals,reportsfield_definitions,circularity_hub
objects = client.objects.list()uuid = client.objects.create({"inventory_name": "MacBook Pro 16"})obj = client.objects.get(uuid)client.objects.patch(uuid, {"inventory_name": "MacBook Pro 16 M4"})client.objects.delete(uuid)Schema-free records. Objects, rooms, locations and Circularity Hub items
are plain dicts, because their field keys are configured per instance.
Persons are a typed Person whose complete record is also available as
person.fields.
Typed resources. Tasks, rental cases, users, files, field definitions and
Circularity Hub orders are frozen dataclasses from seventhings.models.
Enums subclass str. If the API sends an enum value the SDK does not know yet,
it is kept as a plain string.
Listing and filtering
Section titled “Listing and filtering”Use ListOptions for the list endpoints of objects, rooms, locations, rental
cases and the Circularity Hub:
from seventhings.models import ListOptions, SortDirection, in_, like
opts = ( ListOptions(page=1, per_page=50) .sort_by("updated_at", SortDirection.DESC) .where(like("inventory_name", "Laptop"), in_("status", "active", "pending")))objects = client.objects.list(opts)The filter helpers are eq, neq, gt, gte, lt, lte, the *_or_null
variants, like, not_like, in_ and nin. The helper for in is spelled
in_ because in is a Python keyword.
Users and persons have their own option types:
from seventhings.models import PersonListOptions, UserListOptions, UserSortBy, UserSortOrder
users = client.users.list(UserListOptions(per_page=50, sort_by=UserSortBy.EMAIL, order=UserSortOrder.ASC))persons = client.persons.list(PersonListOptions(per_page=50, sort_by="last_name", order=UserSortOrder.ASC))Tasks use TaskListOptions. The tasks endpoint does not use the shared
page/per-page query model; it returns up to 10,000 matching tasks.
Pagination iterators
Section titled “Pagination iterators”The all() iterators walk every page for you:
for obj in client.objects.all(ListOptions(per_page=100)): print(obj.uuid, obj.get_str("inventory_name"))Iterators are available on:
objects,rooms,locations,rentals,personsandusers(asall()),- the Circularity Hub (as
circularity_hub.all_items()).
opts.page is ignored because the iterator controls paging. opts.per_page
sets the page size and defaults to 100. Objects, rooms, locations and hub
items are yielded as Fields. Fields is a dict with typed accessors such
as get_str, get_int, get_float, get_bool and get_time.
Field definitions and mandatory fields
Section titled “Field definitions and mandatory fields”Use field definitions to discover instance-specific fields for assets, rooms, and persons. The helpers skip system-managed keys, because the server fills those in.
from seventhings.models import AssetTrackingTemplate
defs = client.field_definitions.list(AssetTrackingTemplate.ASSET)
missing = client.field_definitions.missing_mandatory_fields( AssetTrackingTemplate.ASSET, {"inventory_name": "MacBook Pro 16"})if missing: ... # prompt for the missing field keys before calling objects.createHistory and reports
Section titled “History and reports”Objects, rooms, locations, persons, tasks and rental cases have a paged
history():
from seventhings.models import CreateReport, HistoryListOptions
hist = client.tasks.history(task_uuid, HistoryListOptions(per_page=20))pdf: bytes = client.reports.create(CreateReport(template_uuid, [object_uuid]))Error handling
Section titled “Error handling”Every exception derives from seventhings.SeventhingsError:
APIError: a response with status code400or higher.NetworkError: a connection failure or timeout.DecodeError: an unexpected response shape.
from seventhings import APIError
try: objects = client.objects.list()except APIError as err: if err.is_unauthorized: ... # refresh the token, then retry elif err.is_feature_inactive: ... # the module (e.g. rentals) is not active on this instance raise
