Skip to main content
A workspace is a container for documents. Every file lives in exactly one workspace, set at upload time. Workspaces are the top-level partition of your corpus: one per team, customer, or tenant. They’re the natural fit for multi-tenant products, where each customer’s documents must stay isolated from everyone else’s.
“Search only this customer’s documents.” “Answer using just the engineering team’s files.”
Where tags and facets layer labels and metadata across your corpus, workspaces draw hard boundaries through it.
The workspace endpoints are in alpha and may change. Creating and managing workspaces from the API requires the appropriate role; some companies provision workspaces through the console instead. You can always upload into and search existing workspaces by workspace_id.

Workspaces, tags, or facets?

All three organise documents, but at different layers. They compose: a file lives in one workspace, can carry several tags, and can be classified with facets.
WorkspacesTagsFacets
What it isA container; every file lives in exactly oneFlat, reusable labelsTyped, hierarchical metadata with a schema
A file belongs toexactly one workspacemany tags, across workspacesmany content types, across workspaces
Best forIsolating teams, customers, tenantsCross-cutting collections (project, topic)Precise structured queries
Setup costCreate a workspaceCreate a tagDesign a content-type tree
Scope a query withworkspace_idtag_idcontent_type / attribute
Access controlYes: API keys can be scoped to a workspace with a per-key roleNo: not a permission boundaryNo: not a permission boundary
Only workspaces are a permission boundary: you can issue API keys scoped to specific workspaces, which makes them the right tool for segmenting data that needs different permission levels. workspace_id and tag_id can be combined in a search or ask to narrow within a workspace; file_id is mutually exclusive with both. The rest of this tutorial covers workspaces.

Step 1: Create a workspace

A workspace needs a name. The caller is automatically added as its owner.
create_workspace.py
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['LIGHTON_API_KEY']}"}

response = requests.post(
    "https://api.lighton.ai/api/v3/workspaces",
    headers=headers,
    json={
        "name": "Engineering Team",
        "description": "Documents owned by the engineering org",
    },
)
print(response.json())
A 201 returns the new workspace with its id. You’ll pass that ID when uploading files and when scoping queries.
{
  "id": 42,
  "name": "Engineering Team",
  "workspace_type": "shared",
  "document_upload_method": "manual",
  "description": "Documents owned by the engineering org",
  "files_count": 0,
  "user_role": "owner"
}
A 403 means workspace creation is disabled for your company and you’re not an admin: create it from the console instead, or ask an admin.

Step 2: Find a workspace’s ID

List the workspaces you’re a member of to grab an ID. Filter by name, or by workspace_type, user_role, and document_upload_method.
list_workspaces.py
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['LIGHTON_API_KEY']}"}

# Workspaces you're a member of, optionally filtered by name
response = requests.get(
    "https://api.lighton.ai/api/v3/workspaces",
    headers=headers,
    params={"name": "engineering"},
)
print(response.json())
The response is paginated. Each workspace carries a files_count and your user_role (owner, editor, or viewer).
{
  "count": 1,
  "results": [
    {
      "id": 42,
      "name": "Engineering Team",
      "workspace_type": "shared",
      "files_count": 128,
      "user_role": "owner"
    }
  ]
}

Step 3: Put files in a workspace

A file is assigned to its workspace at upload time: pass workspace_id in the upload payload. A file’s workspace is fixed; there’s no “move file” operation. See Uploading & managing files for the full upload flow. To pull back every file in a workspace, filter the file listing:
list_files_in_workspace.py
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['LIGHTON_API_KEY']}"}

# Every file in a workspace
response = requests.get(
    "https://api.lighton.ai/api/v3/files",
    headers=headers,
    params={"workspace_id": "42"},
)
print(response.json())
To populate a workspace automatically from Google Drive, SharePoint, ServiceNow, or a web scraper, convert it to a synced workspace with a datasource payload on PATCH /api/v3/workspaces/{id}. The workspace must be empty first.

Step 4: Scope search and ask to a workspace

Both POST /api/v3/search and POST /api/v3/ask accept a workspace_id array that restricts the query to those workspaces. Pass several IDs to query across a set of them. Search within a workspace:
search_by_workspace.py
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['LIGHTON_API_KEY']}"}

# Search only within these workspaces (pass several IDs to widen the scope)
response = requests.post(
    "https://api.lighton.ai/api/v3/search",
    headers=headers,
    json={
        "query": "deployment runbook",
        "workspace_id": [42],
    },
)
print(response.json())
Ask a grounded question within a workspace:
ask_by_workspace.py
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['LIGHTON_API_KEY']}"}

# Grounded answer over only the documents in these workspaces
response = requests.post(
    "https://api.lighton.ai/api/v3/ask",
    headers=headers,
    json={
        "query": "What is our incident escalation policy?",
        "workspace_id": [42],
    },
)
print(response.json())
Combine workspace_id with tag_id to scope to a tagged collection within a workspace.

Step 5: Rename or delete a workspace

Only custom workspaces can be updated, and only by their owner. Personal and company workspaces are managed by the platform.
rename_workspace.py
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['LIGHTON_API_KEY']}"}

workspace_id = 42  # replace with your workspace ID

# Only CUSTOM workspaces can be updated, and only by their owner
response = requests.patch(
    f"https://api.lighton.ai/api/v3/workspaces/{workspace_id}",
    headers=headers,
    json={"name": "Engineering (EMEA)"},
)
print(response.json())
Deleting a workspace removes it and every document inside it, so use it deliberately.
delete_workspace.py
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['LIGHTON_API_KEY']}"}

workspace_id = 42  # replace with your workspace ID

# Deletes the workspace and every document it contains
response = requests.delete(
    f"https://api.lighton.ai/api/v3/workspaces/{workspace_id}",
    headers=headers,
)
print(response.status_code)
A 204 confirms the workspace and its contents are gone.

Segmenting access with scoped API keys

Workspaces aren’t only an organisational boundary, they’re a permission boundary. You can mint an API key that is scoped to specific workspaces, so the key can only read or write the documents in those workspaces and nothing else. This is what makes workspaces the right tool when different data needs different permission levels. Pass a scopes list to POST /api/v3/keys. Each entry pairs a workspace_id with a role, one of viewer, editor, or owner. The requested role on a workspace is capped at the role you currently hold there, so you can’t hand out more access than you have.
create_scoped_api_key.py
import os
import requests

headers = {"Authorization": f"Bearer {os.environ['LIGHTON_API_KEY']}"}

# Scope the key to a workspace with a per-workspace role (viewer | editor | owner).
# The requested role is capped at the role you hold on that workspace.
response = requests.post(
    "https://api.lighton.ai/api/v3/keys",
    headers=headers,
    json={
        "name": "Acme tenant key (read-only)",
        "expires_at": None,  # or an ISO 8601 datetime to auto-expire
        "scopes": [{"workspace_id": 42, "role": "viewer"}],
    },
)
print(response.json())  # the full `key` value is returned only once
The key value is returned only once, on creation, so store it immediately. A few patterns this unlocks:
  • Multi-tenant isolation: give each customer a key scoped to their own workspace. A request made with that key can never reach another tenant’s documents, even if your application code has a bug.
  • Read-only integrations: issue a viewer-scoped key to a dashboard or analytics job that should search and ask but never upload or delete.
  • Per-environment separation: scope staging and production keys to different workspaces so a misconfigured job can’t touch the wrong corpus.
Because a single key can list several scopes with different roles per workspace, you can grant, say, editor on one workspace and viewer on another with one key. An unscoped key, by contrast, inherits the full permissions of its owner across every workspace, so prefer scoped keys whenever a credential is handed to a narrower-trust consumer.
Tags and facets don’t carry their own permissions: a key that can see a workspace can see every tag and facet on the files inside it. When access control is the goal, segment with workspaces.

Next steps

Uploading & managing files

Upload documents into a workspace and manage file metadata

Organizing documents with tags

Group files into collections that cut across workspaces

Searching documents

Rank passages, then scope the search by workspace

Asking questions

Get grounded answers over a workspace