---
title: Multi-tenancy
path: core-concepts/multi-tenancy
status: published
---

ScaiDrive is multi-tenant. Every resource — user, group, share, file, folder, ACL, quota, audit event — belongs to a tenant, and tenants cannot see each other. This page covers the tenancy model, how it shows up in the API, and what happens at the edges.

## The three levels

```mermaid
flowchart TD
  P["Partner (prt_…)<br/><i>managed service provider, optional</i>"]
  T["Tenant (tnt_…)<br/><i>organization / customer</i>"]
  U["Users (usr_…)"]
  G["Groups (grp_…)"]
  S["Shares (shr_…)"]
  F["Files (fil_…)"]
  D["Folders (fld_…)"]

  P --> T
  T --> U
  T --> G
  T --> S
  S --> F
  S --> D
```

- **Partner** — an optional outer layer. A consulting firm that runs ScaiDrive for five customers is a Partner; each customer is a Tenant. If you're running ScaiDrive for a single organization, there's still a Partner record, but you'll rarely interact with it.
- **Tenant** — an organization. The practical boundary for data isolation, administration, and billing.
- **User** — a person or service account inside a tenant. Identified by `usr_...`. Users have roles, quotas, and group memberships.
- **Group** — a collection of users inside a tenant. Can be share members and ACL principals.
- **Share** — a collaboration namespace inside a tenant. The container for files and folders.

Resource IDs are globally unique strings, but they resolve within their tenant. There's no "cross-tenant file" — accessing a file always implies "this tenant's file with this ID."

## How tenancy is enforced

Tenancy is checked in three places:

1. **Token.** The JWT's `tenant_id` claim pins every request to one tenant. You cannot present a token for Tenant A and access Tenant B's data.
2. **Query layer.** Every database query filters by `tenant_id`. The service layer takes `current_user.tenant_id` as a hard requirement; it's not possible to ask "give me this file regardless of tenant."
3. **ACL layer.** ACEs grant rights to principals (users, groups) that belong to the same tenant as the resource. Cross-tenant principals are rejected at write time.

Result: a request authenticated as a Tenant A user cannot access Tenant B resources, even if they know the IDs.

## Resolving a user's tenant

Clients rarely need to think about tenants — the JWT pins it automatically. To verify:

```bash
curl -H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
     $SCAIDRIVE_URL/api/v1/users/me
```

```python
resp = httpx.get(
    f"{url}/api/v1/users/me",
    headers={"Authorization": f"Bearer {token}"},
)
user = resp.json()
print(user["tenant_id"], user["partner_id"])
```

```typescript
const resp = await fetch(`${url}/api/v1/users/me`, {
  headers: { Authorization: `Bearer ${token}` },
});
const user = await resp.json();
console.log(user.tenant_id, user.partner_id);
```

## Users in multiple tenants

A human can have multiple ScaiKey accounts, one per tenant. They log in to each separately and get a different JWT for each. From the server's perspective, these are entirely separate principals — there's no cross-tenant linking.

If you're building a UI that lets a user switch tenants, the switch is a re-login against ScaiKey with a different tenant context, not an in-app operation.

## Partner and super admin operations

Most tenant-level operations are scoped to the tenant in the JWT. A few are cross-tenant:

**Partner admin** (`partner:admin` scope) can view and manage quotas for every tenant under their partner — see [Quotas](/docs/scaidrive/reference/quotas). They cannot view content, only quotas and metadata.

**Super admin** (`*` or `platform:admin` scope) can do anything on any tenant. Reserved for platform operators. Super-admin actions are recorded in the audit log of every affected tenant.

Neither role bypasses ACLs on file contents — you cannot read a file you don't have `READ` permission on, even as super admin, unless you first grant yourself that permission (which is auditable).

## Quotas across the hierarchy

Quotas apply at every level:

- **Partner quota** — total storage for all tenants under a partner.
- **Tenant quota** — total storage for one tenant.
- **User quota** — per-user allocation within a tenant.
- **Group quota** — aggregate allocation for a group.
- **Share quota** — per-share cap.

Any request that would push usage above any applicable quota fails with `507 QUOTA_EXCEEDED`. The error identifies *which* quota was exceeded.

See [Quotas](/docs/scaidrive/reference/quotas) for configuration.

## Tenant isolation at the audit level

Every audit event is tagged with its tenant. The audit log of Tenant A does not contain events from Tenant B, even if a partner admin performed them. Partner-admin cross-tenant actions appear in both the tenant's log (as "performed by [partner admin]") and a separate cross-tenant log available only to partner and super admins.

## What's next

- [Shares and Ownership](/docs/scaidrive/core-concepts/shares-and-ownership) — the collaboration unit within a tenant.
- [Permissions and ACLs](/docs/scaidrive/core-concepts/permissions-and-acls) — how access is resolved.
- [Quotas Reference](/docs/scaidrive/reference/quotas) — quota endpoints.