SDK Workflows
This page shows practical workflows that are the same in all official SDKs. For endpoint-level request and response schemas, use the API Reference.
Create schema-free records
Section titled “Create schema-free records”Objects, rooms, locations, and persons use field keys configured in your seventhings instance. The SDKs therefore accept plain maps or arrays instead of fixed request models.
fields := map[string]any{ "inventory_name": "MacBook Pro 16", "serial": "SN-123",}
missing, err := c.MissingMandatoryFields(ctx, models.AssetTrackingTemplateAsset, fields)if err != nil { return err}if len(missing) > 0 { // collect the missing instance-specific field keys before creating}
uuid, err := c.ObjectCreate(ctx, fields)Use models.AssetTrackingTemplateAsset, models.AssetTrackingTemplateRoom, or
models.AssetTrackingTemplatePerson when reading field definitions.
use Seventhings\Models\Enums\AssetTrackingTemplate;
$fields = [ 'inventory_name' => 'MacBook Pro 16', 'serial' => 'SN-123',];
$definitions = $client->fieldDefinitions->list(AssetTrackingTemplate::Asset);$uuid = $client->objects->create($fields);In PHP, check the returned field definitions directly when you need to enforce mandatory instance-specific fields before creating a record.
Python
Section titled “Python”from seventhings.models import AssetTrackingTemplate
fields = { "inventory_name": "MacBook Pro 16", "serial": "SN-123",}
missing = client.field_definitions.missing_mandatory_fields(AssetTrackingTemplate.ASSET, fields)if missing: ... # collect the missing instance-specific field keys before creating
uuid = client.objects.create(fields)TypeScript
Section titled “TypeScript”const fields = { inventory_name: 'MacBook Pro 16', serial: 'SN-123',};
const missing = await client.fieldDefinitions.missingMandatoryFields('asset', fields);if (missing.length > 0) { // collect the missing instance-specific field keys before creating}
const uuid = await client.objects.create(fields);Use 'asset', 'room', or 'person' (or the AssetTrackingTemplate
constants) when reading field definitions.
List, filter, sort, and page records
Section titled “List, filter, sort, and page records”Objects, rooms, locations, rental cases, and CircularityHub list calls share
the same page, perPage, sort, and filters model.
opts := models.NewListOptions(). WithPage(1). WithPerPage(50). SortBy("updated_at", models.SortDESC). Where(models.Like("inventory_name", "Laptop"))
objects, err := c.ObjectsList(ctx, opts)To walk every page, use one of the Go iterator helpers:
for object, err := range c.ObjectsAll(ctx, models.NewListOptions().WithPerPage(100)) { if err != nil { return err } _ = object["inventory_name"]}use Seventhings\Models\FilterEntry;use Seventhings\Models\ListOptions;use Seventhings\Models\Enums\FilterOperator;use Seventhings\Models\Enums\SortDirection;
$page = 1;$perPage = 50;
do { $objects = $client->objects->list(new ListOptions( page: $page, perPage: $perPage, sort: ['updated_at' => SortDirection::Desc], filters: [ new FilterEntry('inventory_name', FilterOperator::Like, ['Laptop']), ], ));
foreach ($objects as $object) { // process each object }
$page++;} while (count($objects) === $perPage);The PHP SDK also provides all() generators that walk every page, for example
$client->objects->all(new ListOptions(perPage: 100)).
Python
Section titled “Python”from seventhings.models import ListOptions, SortDirection, like
opts = ( ListOptions(page=1, per_page=50) .sort_by("updated_at", SortDirection.DESC) .where(like("inventory_name", "Laptop")))objects = client.objects.list(opts)
# Or walk every page (AsyncClient: `async for`):for obj in client.objects.all(ListOptions(per_page=100)): print(obj.get_str("inventory_name"))TypeScript
Section titled “TypeScript”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')],});To walk every page, iterate with all():
for await (const object of client.objects.all({ perPage: 100 })) { console.log(object.string('inventory_name'));}Upload and attach files
Section titled “Upload and attach files”Upload a file first, then attach the returned file UUID to an attachment field on an object.
file, err := os.Open("manual.pdf")if err != nil { return err}defer file.Close()
fileUUID, err := c.FileUpload(ctx, "manual.pdf", file)if err != nil { return err}
_, err = c.ObjectAddFiles(ctx, objectUUID, []models.FileAttachment{ {FieldKey: "documents", FileUUID: fileUUID},})use Seventhings\Models\FileAttachment;
$stream = fopen('manual.pdf', 'rb');$fileUuid = $client->files->upload('manual.pdf', $stream);
$client->objects->addFiles($objectUuid, [ new FileAttachment('documents', $fileUuid),]);Python
Section titled “Python”from seventhings.models import FileAttachment
with open("manual.pdf", "rb") as fh: file_uuid = client.files.upload("manual.pdf", fh)
client.objects.add_files(object_uuid, [FileAttachment("documents", file_uuid)])TypeScript
Section titled “TypeScript”import { readFile } from 'node:fs/promises';
// upload() accepts a Blob, Uint8Array, ArrayBuffer, or ReadableStream.const fileUuid = await client.files.upload('manual.pdf', await readFile('manual.pdf'), { contentType: 'application/pdf',});
await client.objects.addFiles(objectUuid, [{ fieldKey: 'documents', fileUuid }]);Use the field definitions endpoint to discover which object fields are attachment fields in your instance.
Manage a task lifecycle
Section titled “Manage a task lifecycle”Tasks use typed request models. A task must reference at least one asset and have at least one assignee.
deadline := "2026-12-31"
taskUUID, err := c.TaskCreate(ctx, models.CreateTask{ Title: "Review inventory", Deadline: &deadline, Assignees: []string{userUUID}, References: []models.TaskReferenceInput{ {Type: models.TaskReferenceTypeAsset, UUID: objectUUID}, }, Reminders: []models.TimeInterval{ {Unit: models.TimeIntervalDays, Value: 1}, },})if err != nil { return err}
err = c.TaskUpdateStatus(ctx, taskUUID, models.TaskStatusClosed)use Seventhings\Models\CreateTaskRequest;use Seventhings\Models\TaskReferenceInput;use Seventhings\Models\TimeInterval;use Seventhings\Models\Enums\TaskReferenceType;use Seventhings\Models\Enums\TaskStatus;use Seventhings\Models\Enums\TimeIntervalUnit;
$taskUuid = $client->tasks->create(new CreateTaskRequest( title: 'Review inventory', deadline: '2026-12-31', assignees: [$userUuid], references: [new TaskReferenceInput(TaskReferenceType::Asset, $objectUuid)], reminders: [new TimeInterval(TimeIntervalUnit::Days, 1)], recurringSchedule: null,));
$client->tasks->updateStatus($taskUuid, TaskStatus::Closed);Python
Section titled “Python”from seventhings.models import ( CreateTask, TaskReferenceInput, TaskStatus, TimeInterval, TimeIntervalUnit,)
task_uuid = client.tasks.create(CreateTask( title="Review inventory", deadline="2026-12-31", assignees=[user_uuid], references=[TaskReferenceInput(object_uuid)], reminders=[TimeInterval(TimeIntervalUnit.DAYS, 1)],))
client.tasks.update_status(task_uuid, TaskStatus.CLOSED)TypeScript
Section titled “TypeScript”import { TaskStatus } from '@seventhingscompany/customer-api';
const taskUuid = await client.tasks.create({ title: 'Review inventory', deadline: '2026-12-31', assignees: [userUuid], references: [{ type: 'asset', uuid: objectUuid }], reminders: [{ unit: 'days', value: 1 }],});
await client.tasks.updateStatus(taskUuid, TaskStatus.Closed);Use TaskListOptions (all SDKs) to list tasks by status, deadline range, assignee,
author, or reference type.
Persons vs users
Section titled “Persons vs users”Persons are asset-tracking records and can have instance-specific fields such as department, phone number, or custom fields. Users are login accounts.
- Use persons when you need people as assignable or searchable records.
- Use users when you need login-user metadata or task assignees.
- Persons can be fetched by UUID or numeric ID in all SDKs.
- Users can be listed, fetched by UUID, or fetched by numeric ID.
- The customer API does not expose a direct create-user endpoint, but it can create a user from a person through the persons resource.
personUUID, err := c.PersonCreate(ctx, map[string]any{ "email": "max@example.com", "first_name": "Max",})
user, err := c.UserGetByID(ctx, 42)$personUuid = $client->persons->create([ 'email' => 'max@example.com', 'first_name' => 'Max',]);
$user = $client->users->getById(42);Python
Section titled “Python”person_uuid = client.persons.create({ "email": "max@example.com", "first_name": "Max",})
user = client.users.get_by_id(42)TypeScript
Section titled “TypeScript”const personUuid = await client.persons.create({ email: 'max@example.com', first_name: 'Max',});
const user = await client.users.getById(42);CircularityHub IDs and orders
Section titled “CircularityHub IDs and orders”CircularityHub is the main exception to the SDKs’ UUID convention. Items and orders use integer IDs.
err := c.CircularityHubAddObjects(ctx, map[string]models.AddObjectEntry{ objectUUID: {Category: "Electronics", Price: "50.00"},})
orderID, err := c.CircularityHubOrderCreate(ctx, []int{itemID})order, err := c.CircularityHubOrderGet(ctx, orderID)use Seventhings\Models\AddObjectEntry;
$client->circularityHub->addObjects([ $objectUuid => new AddObjectEntry(category: 'Electronics', price: '50.00'),]);
$orderId = $client->circularityHub->createOrder([$itemId]);$order = $client->circularityHub->getOrder($orderId);Python
Section titled “Python”from seventhings.models import AddObjectEntry
client.circularity_hub.add_objects({ object_uuid: AddObjectEntry(category="Electronics", price="50.00"),})
order_id = client.circularity_hub.create_order([item_id])order = client.circularity_hub.get_order(order_id)TypeScript
Section titled “TypeScript”await client.circularityHub.addObjects({ [objectUuid]: { category: 'Electronics', price: '50.00' },});
const orderId = await client.circularityHub.createOrder([itemId]);const order = await client.circularityHub.getOrder(orderId);Use the integer ID returned by createOrder() for later order reads or
updates.

