Workspaces

Workspaces

client.workspaces creates, lists, configures and deletes the workspaces that hold your uploaded files, and ingests those files. Every method that works on one workspace takes its workspace_id first; one that isn't yours, or was deleted, raises NaceNotFoundError (workspace_not_found). An id holding anything but letters, digits, - and _ raises NaceError before any request. Managing workspaces costs nothing and works at any balance. See Workspaces for what a workspace is, and the API reference for every field.

Every call that creates a job (ingest, files.delete and both searches) carries an Idempotency-Key, yours or one minted per call, so a retry never starts a second job, and takes wait_seconds (0 to 60) to hold the request open until the job finishes, up to that long. Follow the job with client.jobs.wait or client.jobs.events.

Create a workspace

client.workspaces.create(*, name, domain_slug=None, access=None, retry=None)

ParameterTypeRequiredDescription
namestrYes1 to 120 characters, not blank. It can't be changed later. Unique in the account, ignoring case: a name in use raises NaceConflictError.
domain_slugstr | NoneNoThe published domain the workspace sorts its files into: generic, one your account published, or one Nace provides. It pins the newest published version. A slug that names none raises NaceUnprocessableEntityError. Can't be changed later. Default: None (the server uses generic).
accessdictNoAccess labels, with the keys below. They can't be changed later. Default: no labels.

Each dict option takes these keys.

KeyTypeDefaultDescription
access.labelslist[dict][]Up to 16 {"name", "description"}. Ingestion gives each file one label, using its description as the classifier's prompt. Each name is lowercase letters and digits joined by _. [] turns labels off.
access.default_labelstr | NoneNoneThe label a file gets when the classifier can't decide. Required when labels has any, and must be one of them.

It returns a Workspace. A create isn't retried unless you pass retry: a retry after the first create landed would make a second workspace. See Create a workspace.

create_workspace.py
from nace_sdk import NaceClient

with NaceClient() as client:
    workspace = client.workspaces.create(name="fy25-audit")
    print(workspace.workspace_id)

List workspaces

client.workspaces.list(**options)

ParameterTypeRequiredDescription
name_containsstrNoOnly workspaces whose name contains this, ignoring case.
limitintNo1 to 200. Default: 50.
cursorstrNoThe previous page's next_cursor. Keep going until it's None.

It returns a WorkspacePage: one page of the workspaces your key can use, oldest first.

list_workspaces.py
page = client.workspaces.list(name_contains="audit", limit=20)
print([workspace.name for workspace in page.items], page.total_count)

Iterate over workspaces

client.workspaces.iter_all(**options)

ParameterTypeRequiredDescription
name_containsstrNoOnly workspaces whose name contains this, ignoring case.

It returns an Iterator[Workspace] that follows every page, 200 workspaces at a time.

iter_workspaces.py
for workspace in client.workspaces.iter_all(name_contains="audit"):
    print(workspace.workspace_id, workspace.name)

Read a workspace

client.workspaces.get(workspace_id)

ParameterTypeRequiredDescription
workspace_idstrYesThe workspace.

It returns a Workspace.

get_workspace.py
workspace = client.workspaces.get(workspace_id)
print(workspace.status)

Workspace stats

client.workspaces.stats(workspace_id)

ParameterTypeRequiredDescription
workspace_idstrYesThe workspace.

It returns a WorkspaceStats: file and byte counts, files per ingestion status, and the size of the search index.

workspace_stats.py
stats = client.workspaces.stats(workspace_id)
print(stats.files_total, stats.files_by_ingestion_status.get("stale", 0))

Delete a workspace

client.workspaces.delete(workspace_id, *, confirm_name)

ParameterTypeRequiredDescription
workspace_idstrYesThe workspace.
confirm_namestrYesExactly the workspace's name. Anything else raises NaceUnprocessableEntityError.

It returns a DocumentJob | None: the workspace_delete job, or None when the document service had already let the workspace go and no job is left to read. The delete removes every file, output and the search index, and can't be undone. The job's result has files_deleted, index_documents_deleted, prefix_deleted and verified. Only the account's owners and admins, or whoever created the workspace, can delete it; anyone else raises NacePermissionDeniedError. The workspace raises NaceNotFoundError as soon as the delete is accepted, so deleting it again raises that and changes nothing; the call takes no idempotency key and doesn't wait. See Delete a workspace.

delete_workspace.py
job = client.workspaces.delete(workspace_id, confirm_name="fy25-audit")
if job is not None:
    done = client.jobs.wait(job.job_id)
    print(done.result["verified"], done.result["files_deleted"])

Ingest files

client.workspaces.ingest(workspace_id, **options)

ParameterTypeRequiredDescription
workspace_idstrYesThe workspace.
file_idslist[str]NoIngest these files, 1 to 1000. Not with path_prefix.
path_prefixstrNoIngest the files under this path. Not with file_ids. Leave both out for the whole workspace.
stale_onlyboolNoWith path_prefix, or for the whole workspace, only files that changed since they were last ingested. Not with file_ids. Default: False.
reingest_unchangedboolNoRebuild files that are already ingested and unchanged, instead of skipping them. Default: False.
wait_secondsintNo0 to 60. Default: None, which returns at once.
idempotency_keystrNoUp to 200 characters. Default: one minted per call.

It returns a DocumentJob of kind ingestion. Ingestion builds the search index, metadata and outputs, and is the only call that makes files searchable. One bad file doesn't fail the run: the result's outcomes reports each file. file_ids with path_prefix, stale_only with file_ids, or an empty file_ids raises NaceError before any request. See Ingest files.

ingest.py
job = client.workspaces.ingest(workspace_id, path_prefix="reports/", stale_only=True)
done = client.jobs.wait(job.job_id)
for outcome in done.result["outcomes"]:
    print(outcome["path"], outcome["status"])

On this page