Levain LabsLevain Labs
Embedded Agents

Workspaces per Customer

Provision, address, and retire an isolated workspace for each end-customer.

Each of your customers gets their own workspace. The boundary is real: agents, credentials, runs, sessions, and usage in one workspace are invisible to every other. Provision one when a customer signs up, act on it over the API, suspend it when they leave — and when they leave for good, delete it with one call.

Provision

curl -X POST https://api.levainlabs.com/api/v1/org/workspaces \
  -H "Authorization: Bearer $LEVAIN_ORG_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Tools", "external_id": "customer_42"}'

The response carries the workspace id — store it against the customer in your own database; it's the value you'll send in X-Workspace-Id from then on. The new workspace starts empty and headless: no members, no sign-in, no agents until you adopt one.

Provisioning requires the Enterprise plan, and an org can hold up to 500 workspaces. Send external_id (e.g. your customer id) to make the call safely retryable: a repeat call whose external_id matches an existing workspace returns that workspace with status 200 instead of creating another. If a create fails or times out, don't guess — recover by calling GET /api/v1/org/workspaces?external_id= with the same value to find out whether the workspace exists.

A replayed create can return a workspace whose provisioning is still in flight. If that provisioning later fails, the workspace is removed — a subsequent lookup for it may then 404.

Address

Send the workspace id with an org key on any workspace-scoped endpoint:

curl https://api.levainlabs.com/api/v1/agents \
  -H "Authorization: Bearer $LEVAIN_ORG_KEY" \
  -H "X-Workspace-Id: $CUSTOMER_WORKSPACE_ID"

The rules are strict on purpose:

  • An org key with X-Workspace-Id acts on that workspace. An unknown id, or one belonging to another org, returns 404.
  • An org key without the header only resolves when the org has exactly one workspace; otherwise the request is refused with 400 and asks you to pick.
  • A workspace-scoped key naming a different workspace in X-Workspace-Id is refused with 403 rather than silently ignored, so a caller never acts somewhere other than where it asked to.

List what you have with GET /api/v1/org/workspaces — each row carries headless (whether anyone can sign in) and lifecycle.

Knowledge base

Every workspace carries a knowledge base — shared context that agents in the workspace read before they act. The knowledge base is provisioned on first access: the first GET /api/v1/wikis/current or the first page write creates it and seeds overview.md, DESIGN.md, and VOICE.md. In a workspace where people sign in, that first access happens when someone opens the knowledge base. In a headless workspace it never does on its own — so if your customer's agents should run with context, provision and seed it during onboarding. Fetching the id below is itself a first access and creates the knowledge base; the write that follows seeds your content into it:

WIKI_ID=$(curl -s https://api.levainlabs.com/api/v1/wikis/current \
  -H "Authorization: Bearer $LEVAIN_ORG_KEY" \
  -H "X-Workspace-Id: $CUSTOMER_WORKSPACE_ID" | jq -r .id)

curl -X PUT "https://api.levainlabs.com/api/v1/wikis/$WIKI_ID/pages/VOICE.md" \
  -H "Authorization: Bearer $LEVAIN_ORG_KEY" \
  -H "X-Workspace-Id: $CUSTOMER_WORKSPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{"body": "# Voice\n\nPlain and direct. Short sentences."}'

The seeded pages are writable like any other page — only deleting them is restricted — and every write through PUT /api/v1/wikis/{wiki_id}/pages/{page_path} is stamped user_edited_at, which tells the maintainer agent to treat your content as append-only rather than rewrite it. Agents only receive the knowledge base once it exists, so write your context before the first run, not after.

Lifecycle

A workspace is active, dormant, or suspended.

Suspend a workspace when its customer offboards:

curl -X POST https://api.levainlabs.com/api/v1/org/workspaces/$WS_ID/lifecycle \
  -H "Authorization: Bearer $LEVAIN_ORG_KEY" \
  -H "Content-Type: application/json" \
  -d '{"state": "suspended"}'

Suspended workspaces refuse new runs until you set them back to active. Data, agents, and configuration are all kept, so re-onboarding a returning customer is the same call in reverse. The org's primary workspace can't be suspended — it carries the org's plan and sign-in.

Dormant is automatic: a workspace with no activity for 30 days is marked dormant, and the next run clears it. You never set it yourself; treat it as a signal that a customer has gone quiet.

Delete

When a customer leaves, the whole of it leaves with them — one call:

curl -X DELETE https://api.levainlabs.com/api/v1/org/workspaces/$WS_ID \
  -H "Authorization: Bearer $LEVAIN_ORG_KEY"

The call returns immediately and is irreversible. From that moment the workspace no longer resolves on any endpoint — its own API keys stop working and it disappears from GET /api/v1/org/workspaces. Everything inside is then permanently removed:

  • agents, their versions and repositories
  • the knowledge base and every uploaded or crawled document
  • agent memory
  • integration credentials, provider keys, and workspace API keys
  • sessions, runs, and their event records
  • members, schedules, triggers, and notifications

Retention. Removal from live systems completes within 7 days of the call; encrypted database backups holding the data expire within 35 days after that. This is the wording to cite when a customer's GDPR erasure request reaches you: their data is deleted from live systems within 7 days and from all backups within 42 days.

What survives. Invoices, the credit ledger, and aggregate usage totals are retained for financial record-keeping. They reference the workspace by identifier and name only — none of its contents.

Deletion is for offboarding for good. If the customer might return, suspend instead: suspension keeps everything and reverses with one call; deletion keeps nothing and doesn't. The org's primary workspace can't be deleted.

On this page