Documentation

Multi-tenancy

Hard isolation at the database layer. Built in from day one.

Multi-tenancy

Nimblesite is multi-tenant from the first line of code. Every config, conversation, message, and log row has a tenant_id. Every query is filtered by it. Tenants cannot see each other's data, conversations, or configs.

If you're building a SaaS product on top of Nimblesite, your customers map one-to-one to tenants.

The model

Tenant
  ├─ API Key (hashed)
  ├─ Agent Configs
  │    └─ Conversations
  │         └─ Messages
  └─ Logs

A tenant is the unit of isolation. One tenant = one customer (or one environment, or one project — however you want to model it).

Creating tenants

Tenants are created by admin calls (typically from your own backend, not from customer-facing code):

curl -X POST https://api.nimblesite.dev/api/v1/admin/tenants \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Corp"}'

The response includes an api_key. Show it once, store it securely. We hash it at rest and never return it again.

The API key

Every chat call requires an X-API-Key header:

curl -X POST https://api.nimblesite.dev/api/v1/chat/$CONFIG_ID \
  -H "X-API-Key: $TENANT_KEY" \
  -d '{"message": "Hello"}'

The key identifies the tenant. We resolve it to a tenant_id, then every subsequent query is scoped:

WHERE tenant_id = :tenant_id

No tenant_id in the path, no way to query across tenants, no way to leak one tenant's data into another's response.

Per-tenant configs

Each tenant has its own set of agent configs. Tenant A's configs endpoint will never return Tenant B's configs:

curl https://api.nimblesite.dev/api/v1/configs \
  -H "X-API-Key: $TENANT_A_KEY"

This means you can ship one product with per-customer agent variants — different system prompts, different tool lists, different models — without building that scaffolding yourself.

Per-tenant prompts

Prompts support template variables, so one config can serve many tenants with tenant-specific personalisation:

{
  "system_prompt": "You are the assistant for {tenant_name}. Today is {date}. Be helpful."
}

{tenant_name} is resolved from the tenant that owns the chat call. Your customers get a per-tenant assistant without duplicating configs.

Isolation guarantees

  • Configs are scoped by tenant_id. Cross-tenant reads are impossible.
  • Conversations and messages are scoped by tenant_id. You cannot load another tenant's conversation history.
  • API keys are hashed with SHA-256 + per-key salt at rest.
  • Logs are scoped by tenant_id. Your dashboard only shows your own activity.

What you still own

Multi-tenancy is solved at the Nimblesite layer. Things you still own:

  • User-to-tenant mapping. If one tenant has 500 users, you decide how to scope conversations and rate limits within that tenant.
  • Tool execution trust boundary. Your tools run in your app. If tenant A's tool accidentally touches tenant B's data, that's a bug in your app, not ours.
  • Provider API keys. If you bring your own provider keys, you decide whether to share one key across tenants or issue one per tenant.

Multi-tenancy you get for free, in one line of code

curl -H "X-API-Key: $KEY" https://api.nimblesite.dev/api/v1/chat/$CONFIG_ID -d ...

That's the whole thing. You ship your product, point each customer's backend at a different API key, and Nimblesite keeps them apart.