Skip to content

Multi-Tenant Spaces

Spaces let you scope files per customer in a B2B SaaS application. Each space is an isolated namespace -- files, search results, and Q&A answers are all scoped to a space. Combine spaces with portal tokens to give each customer their own searchable document workspace.

Note

If you're not building a multi-tenant application, you can skip this page. All files default to the "default" space.

The Pattern

Your Customer A --> Space "acme"    --> Files, Search, Q&A scoped to Acme
Your Customer B --> Space "globex"  --> Files, Search, Q&A scoped to Globex
  1. Assign a space when uploading files for each customer
  2. Scope search and Q&A to that customer's space
  3. Issue portal tokens for each customer's space to power embeddable UIs

Upload Files to a Space

Pass the space parameter when uploading to scope files to a customer.

python
import os
from roset import Client
 
client = Client(api_key=os.getenv("ROSET_API_KEY"))
 
# Upload a file scoped to the "acme" customer space
file = client.files.upload(
    filename="acme-contract.pdf",
    content_type="application/pdf",
    size_bytes=85000,
    space="acme",
)
print(f"File {file['id']} uploaded to space: {file['space']}")
 
# Upload a file scoped to the "globex" customer space
file2 = client.files.upload(
    filename="globex-invoice.pdf",
    content_type="application/pdf",
    size_bytes=42000,
    space="globex",
)

Search Within a Space

Scope search to a specific customer's files by passing the space parameter.

python
# Search only within the "acme" space
results = client.search.query(
    query="payment terms",
    space="acme",
)
print(f"Found {results['total']} results in acme's space")

Q&A Within a Space

Q&A answers are also scoped to the space -- your customers only see answers from their own documents.

python
# Ask a question scoped to Acme's documents
answer = client.qa.ask(
    question="What are the payment terms?",
    space="acme",
)
print(answer["answer"])
# Sources will only include files from the "acme" space

Portal Tokens

Portal tokens grant temporary, scoped access to a space. Use them to power embedded UIs where your customers can browse, search, and ask questions about their documents.

python
# Issue a portal token for a customer's space (valid for 1 hour)
token = client.portal.create_token(
    space="acme",
    ttl=3600,
)
print(f"Portal token: {token['token']}")
print(f"Expires: {token['expires_at']}")
 
# Your frontend uses this token to authenticate portal API calls:
# Authorization: PortalToken ptk_abc123...

List Spaces

View all spaces with file counts and statistics.

python
# List all spaces
result = client.spaces.list()
for s in result["spaces"]:
    print(f"  {s['space']}: {s['file_count']} files")

B2B SaaS Integration Pattern

A typical integration looks like this:

  1. On customer signup -- create their space name (e.g., their org slug)
  2. On file upload -- pass space: customerSlug to scope the file
  3. On search/Q&A -- pass space: customerSlug to scope results
  4. On dashboard render -- issue a portal token for the customer's space and pass it to your frontend
python
# In your backend route handler
def handle_upload(request):
    customer_space = request.user.org_slug  # e.g., "acme"
 
    file = client.files.upload(
        filename=request.file.name,
        content_type=request.file.content_type,
        size_bytes=request.file.size,
        space=customer_space,
    )
    return {"file_id": file["id"]}
 
def handle_search(request):
    customer_space = request.user.org_slug
    results = client.search.query(
        query=request.query,
        space=customer_space,
    )
    return results
Build this with AI
Roset (roset.dev) is a developer API that transforms unstructured files into structured data. It has a 'spaces' feature for multi-tenant isolation -- each space is a namespace that scopes files, search, and Q&A to one customer. Python SDK: `pip install roset`. Init: `from roset import Client; client = Client(api_key='rsk_...')`. Create space: `client.spaces.create(name='customer-123')`. Upload to space: `client.files.upload(filename, content_type, size_bytes, space='customer-123')`. Scoped search: `client.search.query(query='...', space='customer-123')`. Scoped Q&A: `client.qa.ask(question='...', space='customer-123')`. Write me a Python backend integration (FastAPI or Flask) that creates a space per customer on signup, uploads files to their space, and runs scoped search/Q&A.

Next Steps