---
name: vinkius-multi-tenant-saas
description: 'Teaches the multi-tenant AI SaaS pattern on @vinkius/connect: white-label connectivity for every user inside every customer, addressed by one composite external_id that encodes tenant and user, cross-tenant access impossible by construction, per-plan policies enforced through capability scoping, and enterprise tenants optionally on their own Vinkius application. Explains address grammar, claim-based identity, policy planes, adapter heterogeneity and tenant isolation options. Use when building white-label or per-tenant AI tools with @vinkius/connect. Prerequisite: vinkius-connect-core.'
license: Apache-2.0
metadata:
  author: Vinkius
  package: "@vinkius/connect"
  pattern: "user = customer user (multi-tenant)"
  docs: "https://vinkius.com/learn/connect-sdk/build-multi-tenant-saas"
---

# A multi-tenant AI SaaS on one application key

Applies vinkius-connect-core. The decision this pattern makes: the "user" is a person inside your customer, so the address must carry *both* the tenant and the human. That single grammar is your entire isolation model.

## The address grammar

Compose `external_id` deterministically from the two ids your auth already trusts: a tenant key plus the user key (`cus_<tenant>_u_<user>` style). Rules that hold the model together:
- Build it only from authenticated claims, never from raw request data. If a client can influence the tenant part, they can address another tenant's users, and nothing downstream can save you.
- Keep it stable across renames: derive from immutable database keys, not from display names or emails. Emails and names never leave your database; the opaque id is what the platform sees.
- Never construct a peer's id to "check" existence. A well-formed id that points outside the authenticated tenant resolves to no connection at all, which is the guarantee: cross-tenant access is a 404, by design.

## One shared client, per-tenant policy

One `Vinkius` instance (appId + app key) serves the whole marketplace: isolation lives in the id, not in instances. Tenant policy is layered at the capability query: `include` the connector set that tenant's plan grants, sourced from your own billing table at request time, so a connector the plan forbids is never even queried and never surfaces to the model. Per-plan limits, not per-plan secrets.

## Heterogeneous model runtimes

One code path serves every tenant regardless of which model they use: `toOpenAITools`, `toAnthropicTools`, `toGeminiTools`, or the neutral JSON-Schema bridge for anything else. Convert for the call, then execute against the same `CapabilitySet` you hold; adapters validate tool-name compatibility up front, so a connector slug a given platform rejects never becomes a runtime 400.

## Enterprise tenancy options

For the customer that requires true physical isolation: give them their own Vinkius application (new appId plus app key), provision a dedicated `Vinkius` instance per tenant's credentials, same code path. Composite ids, policy planes and adapters all keep working unchanged. Enterprise isolation is an axis you scale by, never a rewrite.

## Rules that keep this safe

- The `external_id` is security-critical input: validate shape, derive from claims, reject anything that does not belong to the authenticated session's tenant.
- Never pass raw tenant or user data to the platform: the opaque address is the contract, and keeping identities customer-side is what makes the product white-label by construction.
- Keep per-operation `idempotencyKey` so a tenant's retry replays nothing on another tenant's side.
- Server-side only: your browser and mobile talk to your routes, your routes address Vinkius.

## Verify it works before shipping

From tenant A's session, attempt to address a tenant-B id and assert the empty 404 surface; load the same user's capabilities under two different plan policies and assert the second `include` prunes the query; run a cross-provider adapter matrix and assert each platform receives valid tool names.

Docs with the full walkthrough: https://vinkius.com/learn/connect-sdk/build-multi-tenant-saas
