TypeScript SDK
The TypeScript SDK wraps the customer API and has no runtime dependencies. It
uses the standard fetch API, so it runs on Node.js, Bun, Deno, browsers and
edge runtimes. Resources are grouped into services on the client, for example
client.objects. See the SDKs overview for the concepts all SDKs share,
and common workflows for side-by-side examples.
- Repository: github.com/SeventhingsCompany/customer-api-typescript
- Package:
@seventhingscompany/customer-api(ESM, CommonJS and type declarations) - Requires Node.js 22 or newer, or any runtime with
fetch.
Installation
Section titled “Installation”npm install @seventhingscompany/customer-apiCreating a client
Section titled “Creating a client”Pass your instance URL. The SDK appends /customer-api/v1 itself.
To log in while creating the client, use credentials:
import { SeventhingsClient } from '@seventhingscompany/customer-api';
const client = await SeventhingsClient.withCredentials({ instanceUrl: 'https://your-instance.seventhings.com', username: 'user@example.com', password: 'password', clientId: 'your-client-id',});If another part of your application already completed the auth flow, pass the existing token:
const client = new SeventhingsClient({ instanceUrl: 'https://your-instance.seventhings.com', token: 'access-token', clientId: 'your-client-id',});To log in manually, construct the client first. The constructor also accepts a
default timeout, extra headers and a custom fetch:
const client = new SeventhingsClient({ instanceUrl: 'https://your-instance.seventhings.com', timeoutMs: 30_000, headers: { 'User-Agent': 'my-app/1.0' },});
const tok = await client.auth.login('user@example.com', 'password', 'your-client-id');// login stores tok.accessToken on the client.The other auth methods are:
client.auth.refresh(refreshToken)client.auth.loginSSO(provider, authCode, clientId, appTarget)client.auth.revokeTokens()
client.token and client.setToken(token) read and replace the current bearer
token. client.clientId returns the stored OAuth client ID.
Resource services
Section titled “Resource services”Each resource group is a property of the client: auth, objects, rooms,
locations, persons, users, tasks, rentals, fieldDefinitions,
files, reports and circularityHub. Every method returns a Promise.
const objects = await client.objects.list();const uuid = await client.objects.create({ inventory_name: 'MacBook Pro 16' });const object = await client.objects.get(uuid);await client.objects.patch(uuid, { inventory_name: 'MacBook Pro 16 M4' });await client.objects.delete(uuid);Objects, rooms, locations and CircularityHub items have field keys configured
per instance, so they are returned as Record<string, unknown>. Wrap a record in
Fields to read values with the right type:
import { Fields } from '@seventhingscompany/customer-api';
const obj = new Fields(await client.objects.get(uuid));obj.string('inventory_name'); // string | undefinedobj.time('purchase_date'); // Date | undefinedThe SDK types the common person columns (person.firstName, person.email,
and so on). It also keeps the complete field map, including custom fields, in
person.fields.
Tasks, rental cases, users, files, field definitions and CircularityHub orders are typed with camelCase properties. The SDK converts them to and from the API’s snake_case field names.
Listing and filtering
Section titled “Listing and filtering”Objects, rooms, locations, rental cases and CircularityHub lists take
ListOptions:
import { Filter, SortDirection } from '@seventhingscompany/customer-api';
const objects = await client.objects.list({ page: 1, perPage: 50, sort: { updated_at: SortDirection.Desc }, filters: [Filter.like('inventory_name', 'Laptop'), Filter.in('status', 'active', 'pending')],});Users and persons take sortBy and order:
const users = await client.users.list({ perPage: 50, sortBy: 'email', order: 'asc' });const persons = await client.persons.list({ perPage: 50, sortBy: 'last_name', order: 'asc' });Tasks take filters (status, deadlineFrom, deadlineTo, assignee,
author, referenceType). They don’t use the shared page/per-page model:
the API returns up to 10,000 matching tasks.
Pagination iterators
Section titled “Pagination iterators”all() returns an async iterator that fetches every page for you:
for await (const object of client.objects.all({ perPage: 100 })) { console.log(object.uuid, object.string('inventory_name'));}all() exists on objects, rooms, locations, persons, users and rentals. On
CircularityHub it is called allItems().
- It ignores
page, because the iterator controls paging. perPagesets the page size and defaults to100.- A
breakstops further requests.
Field definitions and mandatory fields
Section titled “Field definitions and mandatory fields”const defs = await client.fieldDefinitions.list('asset'); // 'asset' | 'room' | 'person'
const missing = await client.fieldDefinitions.missingMandatoryFields('asset', { inventory_name: 'MacBook Pro 16',});if (missing.length > 0) { // prompt for the missing field keys before calling objects.create}These checks skip system-managed keys, because the server fills them in.
Error handling
Section titled “Error handling”A response with status code 400 or higher rejects with an ApiError:
import { ApiError, isFeatureInactive, isNotFound } from '@seventhingscompany/customer-api';
try { await client.objects.get(uuid);} catch (err) { if (isNotFound(err)) { // handle a missing object } else if (err instanceof ApiError && err.isUnauthorized()) { // refresh the token, then retry } throw err;}isFeatureInactive(err) returns true when a module such as rentals is not
enabled on the instance.
For other failures:
- A request that gets no response (DNS, connection or TLS failure) rejects with
NetworkError. The original error is inerr.cause. - Aborts and timeouts reject with the runtime’s native
AbortErrororTimeoutError.
Cancellation and timeouts
Section titled “Cancellation and timeouts”Every method accepts an optional final options argument:
const controller = new AbortController();await client.objects.list(undefined, { signal: controller.signal });await client.reports.create(input, { timeoutMs: 120_000 });
