Skip to content
.seventhings.com

Prefill your credentials

Fill in your non-secret values to have them appear in the examples below. Stored locally in your browser.

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.

Terminal window
pip install seventhings-customer-api
# or
uv add seventhings-customer-api

The import name is seventhings.

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() or async 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)

Resources are services on the client:

  • objects, rooms, locations
  • persons, users
  • files, tasks, rentals, reports
  • field_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.

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.

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, persons and users (as all()),
  • 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.

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.create

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]))

Every exception derives from seventhings.SeventhingsError:

  • APIError: a response with status code 400 or 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