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.
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
- Assign a space when uploading files for each customer
- Scope search and Q&A to that customer's space
- 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.
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.
# 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.
# 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" spacePortal 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.
# 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.
# 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:
- On customer signup -- create their space name (e.g., their org slug)
- On file upload -- pass
space: customerSlugto scope the file - On search/Q&A -- pass
space: customerSlugto scope results - On dashboard render -- issue a portal token for the customer's space and pass it to your frontend
# 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 resultsNext Steps
- Build a Knowledge Base -- upload files and build a searchable knowledge base.
- Search -- deep dive on search modes and parameters.
- API Reference -- full spaces endpoint documentation.