# Multi-Tenancy Patterns

Highflame supports multi-tenant deployments through account and project scoping. This page covers how to structure clients, isolate tenant traffic, and apply per-tenant policies.

### Account and Project Scope

Every Highflame API request is scoped to an account and a project. The SDK reads these from the API key by default, but you can override them explicitly to support multi-tenant applications.

```python
# Python — explicit account and project scoping
from highflame import Highflame

client = Highflame(
    api_key="hf_sk_...",
    account_id="acc_tenant_a",
    project_id="proj_prod",
)
```

```typescript
// TypeScript — explicit account and project scoping
import { Highflame } from "@highflame/sdk";

const client = new Highflame({
  apiKey: "hf_sk_...",
  accountId: "acc_tenant_a",
  projectId: "proj_prod",
});
```

When `account_id` and `project_id` are set, all requests from that client instance are evaluated against the policies and quotas for that specific project.

### Per-Tenant Client Instances

The most common pattern for SaaS platforms is to create a client instance per tenant:

```python
from functools import lru_cache
from highflame import Highflame

@lru_cache(maxsize=128)
def get_client_for_tenant(account_id: str, project_id: str) -> Highflame:
    return Highflame(
        api_key="hf_sk_...",
        account_id=account_id,
        project_id=project_id,
    )

# In your request handler
def handle_request(tenant: Tenant, user_input: str):
    client = get_client_for_tenant(tenant.account_id, tenant.project_id)
    resp = client.guard.evaluate_prompt(user_input)
    ...
```

The client is lightweight — caching instances per tenant avoids repeated initialization overhead while keeping token caches warm per project.

### Per-Tenant Session Tracking

Session IDs should be scoped to both the tenant and the user to prevent cross-tenant session pollution:

```python
def make_session_id(tenant_id: str, user_id: str, conversation_id: str) -> str:
    return f"{tenant_id}_{user_id}_{conversation_id}"

resp = client.guard.evaluate(GuardRequest(
    content=user_input,
    content_type="prompt",
    action="process_prompt",
    session_id=make_session_id(tenant.id, user.id, conversation.id),
))
```

### Per-Tenant ZeroID Configuration

For platforms issuing ZeroID tokens on behalf of tenants, use a ZeroIDClient scoped to each tenant's account and project:

```python
from highflame.zeroid import ZeroIDClient

def get_zeroid_client(account_id: str, project_id: str) -> ZeroIDClient:
    return ZeroIDClient(
        base_url="https://auth.zeroid.dev",
        account_id=account_id,
        project_id=project_id,
    )
```

Tokens issued through a tenant-scoped client carry the tenant's `account_id` and `project_id` in the token claims, enabling tenant-specific policies in Shield.

### Per-Project Policy Isolation

Policies in Highflame are project-scoped. Assign different projects to different tenant tiers to apply different enforcement levels:

| Tenant tier  | Project           | Policy set            |
| ------------ | ----------------- | --------------------- |
| Free         | `proj_free`       | Conservative defaults |
| Professional | `proj_pro`        | Standard enforcement  |
| Enterprise   | `proj_enterprise` | Custom Cedar policies |

### Custom Headers for Tenant Routing

For advanced deployments where Shield sits behind a routing layer, use `default_headers` to pass tenant metadata:

```python
client = Highflame(
    api_key="hf_sk_...",
    default_headers={
        "X-Tenant-ID": tenant.id,
        "X-Tenant-Tier": tenant.tier,
    },
)
```

### Passing Tenant Identity Context to Cedar

Pass tenant attributes as `metadata` in `GuardRequest` to make them available in Cedar policies:

```python
resp = client.guard.evaluate(GuardRequest(
    content=user_input,
    content_type="prompt",
    action="process_prompt",
    metadata={
        "tenant_id": tenant.id,
        "tenant_tier": tenant.tier,
        "user_role": user.role,
    },
))
```

Cedar policies can then reference these values:

```cedar
permit (
  principal,
  action == Action::"call_tool",
  resource
)
when {
  context.tenant_tier == "enterprise" ||
  context.user_role == "admin"
};
```

### Single-Client Multi-Tenant Pattern

If you have a small number of tenants and want to avoid per-tenant client instances, pass `account_id` and `project_id` at the request level using the low-level client API and custom headers. The recommended approach for most platforms is still per-tenant clients.

### Isolation Guarantees

* **Policy isolation**: each project has its own Cedar policy set. Policies in `proj_tenant_a` do not affect requests in `proj_tenant_b`.
* **Session isolation**: sessions are namespaced by project. A `session_id` in one project does not collide with the same string in another project.
* **Quota isolation**: rate limits and quotas are tracked per account and project.
* **Audit isolation**: the Highflame observatory shows events per project. Tenant A cannot see Tenant B's request traces.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.highflame.ai/guides/multi-tenancy-patterns.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
