- ›
Building AI agents into a multi-tenant SaaS means every customer gets their own isolated, governed agent— not one shared agent with a big system prompt. - ›The hard part isn't the model; it's the surrounding infrastructure: per-user identity, permissions, secrets, spend control, and revocable access.
- ›Six building blocks make it work: identity, permissions (Account Kits), secrets (vault), spend (cards + approvals), delegated sessions, and runtime.
- ›Naïve's model is Operator → Account Kit → tenant user → resources, with `naive.forUser(customerId)` scoping every call to one customer.
- ›Governance is enforced server-side: sensitive actions gate on approval, secrets never reach the model, and sessions are short-lived and revocable.
- ›
Start by creating a tenant user and assigning an Account Kit— then add primitives one at a time.
If you're adding AI agents to a SaaS product, the interesting question isn't "which model?" It's "what happens when a thousand different customers each have an agent acting on their behalf?" Building multi-tenant AI agents means giving every customer their own isolated, governed agent — one that can act in the real world without ever touching another customer's data, money, or credentials.
That surrounding infrastructure — identity, permissions, secrets, spend, and revocation — is the actual work. This playbook walks through the building blocks, the pitfalls teams hit when they roll their own, and how Naïve's developer platform turns each block into a primitive you configure instead of build.
What does it mean to build AI agents into a multi-tenant SaaS?
A multi-tenant AI agent is an agent that exists per customer, not per app. Each of your users gets an agent with its own identity, its own permissions, its own secrets, and its own spending authority — all isolated from every other tenant.
The tempting shortcut is one shared agent with a big system prompt that says "only act for customer X." That works in a demo and fails in production: a single prompt-injection, a logging mistake, or a mixed-up variable can leak one tenant's data or spend into another's. Isolation has to be structural, enforced below the model, not requested in natural language.
Why is per-user isolation the hard part?
The model is the easy part. The hard part is everything an agent needs to act: an identity to act as, a boundary on what it may do, somewhere to hold secrets, a way to pay, and a way to pull its access back. Each of those is a small distributed-systems problem, and you have to solve all of them before the first agent touches a real customer.
Teams that build this in-house usually end up assembling a payments integration, a secrets manager, an OAuth broker, an approvals queue, an audit log, and a session service — then maintaining the seams between them. It's months of undifferentiated work that has nothing to do with your actual product.
What are the building blocks?
Six concerns show up in every multi-tenant agent product. Here's the DIY version versus the primitive that replaces it.
| Concern | The DIY stack | The Naïve primitive |
|---|---|---|
| Identity | Per-tenant user records + custom scoping everywhere | Tenant user + naive.forUser(customerId) |
| Permissions | Hand-rolled policy checks per request | Account Kit (policy template, enforced server-side) |
| Secrets | Secrets manager + careful redaction | Per-tenant KMS-encrypted vault the model never reads |
| Spend | Card issuing integration + limit logic | Per-user virtual cards with fixed limits |
| Approvals & audit | Approvals queue + append-only log service | Approval gates + per-user audit log, built in |
| Delegated access | Token service + rotation | Short-lived, revocable MCP sessions |
The rest of this playbook takes them one at a time.
How do you give each customer their own agent identity?
Start with a tenant user per customer. On Naïve, the model is Operator → Account Kit → tenant user → resources: you're the operator, you create a user for each customer, and you address that customer's agent with naive.forUser(customerId). Every call made through that scoped client is isolated to that tenant.
This is the difference between "the agent promises to stay in its lane" and "the platform enforces the lane." Isolation lives in the scoped client, so a bug in your prompt or your app code cannot cross tenants through forUser.
How do you control what an agent is allowed to do?
Give the tenant user an Account Kit — a policy template that defines which primitives the agent may call and the limits that apply. You define the kit once and assign it; the platform enforces it on every request, server-side, at execution time.
That's the key property: permissions are configuration, not per-request code you write and re-audit. If a kit doesn't grant the cards primitive, no prompt can talk the agent into spending. Naïve's governance primitive covers this enforcement layer — permissions, approvals, and audit together.
How do you keep customer secrets out of the model?
Put them in a vault the agent can use but never see. Naïve's vault is KMS envelope-encrypted per tenant, and the raw secret is consumed server-side to complete an action — it never re-enters the model's context or the client.
This closes the exfiltration path that makes DIY secret-handling risky: if a credential never enters the prompt, a prompt-injection attack has nothing to steal. The agent logs into a service or calls an API on the customer's behalf without the secret ever passing through the LLM. (See the vault docs for the mechanism.)
How do you let an agent spend money safely?
Give it a per-user virtual card with a hard limit, and gate the sensitive steps on a human. Naïve cards come in two types — a prepaid card with a $150 maximum and no cardholder required, and a managed virtual card with cardholder controls and no fixed cap — with limits set in cents (per published docs).
Spending authority is per tenant, so one customer's agent can never draw on another's card. And because issuing or funding a card can freeze as pending until a human approves, the risky moments stay under human control while the routine work stays autonomous. (Details in the cards docs.)
How do you hand out access without leaking your master key?
Never give a runtime your long-lived API key. Instead, mint a short-lived, scoped session. A Naïve MCP session (sessions.create) has a default TTL of 15 minutes and a maximum of 24 hours, is scoped to one tenant user, and is instantly revocable (per published docs).
That combination is what makes delegated access safe: the credential expires on its own, it can only act as one customer, and if anything looks wrong you revoke it immediately — without rotating the key your whole platform depends on. It's the "short-lived, scoped, revocable delegated token" pattern as a single call. (See the sessions docs.)
How does it all fit together?
Put the blocks in order and the architecture is small:
- Create a tenant user for the customer.
- Assign an Account Kit that defines their agent's permissions and limits.
- Scope every call with
naive.forUser(customerId)so identity, vault, cards, and connections are isolated to that tenant. - Hand the agent a session, not your key, when a runtime needs to act.
- Let approvals and audit catch the sensitive moments and record everything per user.
In code, the first three steps are a few lines:
import { Naive } from "@usenaive-sdk/server";
const naive = new Naive({ apiKey: process.env.NAIVE_API_KEY! });
// 1. one identity per customer
const user = await naive.users.create({ email: "customer@acme.com" });
// 2. scope every call to that tenant — cards, vault, connections all isolated
const agent = naive.forUser(user.id);
// 3. hand a runtime a short-lived, revocable session, not your long-lived key
const session = await agent.sessions.create({ ttlMs: 900000 });The result is an agent that can genuinely act in the world — sign up for services, hold credentials, spend within limits, operate as the customer — while staying inside a boundary you defined and can revoke. The same model runs one agent or a hundred thousand.
What are the common pitfalls?
A few mistakes show up again and again when teams first add agents to a multi-tenant product:
- Isolation by prompt, not by platform. "Only act for customer X" in a system prompt is a suggestion, not a boundary. Scope with a tenant identity so crossing tenants is blocked by the platform, not merely discouraged.
- Secrets in the context window. The moment a raw API key or password enters the prompt, a prompt-injection attack can exfiltrate it. Keep secrets in the vault and let them be used server-side only.
- One long-lived key everywhere. Handing your master key to every runtime means one leak compromises every tenant. Issue scoped, short-lived sessions instead.
- No human gate on money and identity. Fully autonomous card issuance or company formation is where costs and liability escape. Keep the sensitive steps approval-gated and let the rest run.
Where to start
Pick one customer flow and make it multi-tenant end to end: create a tenant user, assign an Account Kit, and have the agent do one real thing through forUser — read a connected inbox, make a small card purchase behind an approval, or use a vaulted credential. Once one primitive works cleanly per tenant, the rest follow the same shape.
The multi-tenancy docs are the source of truth for the model, and the Naïve SDK gets you to the first forUser call in a few minutes. Build the agent product; let the platform be the payments, secrets, and governance company for you.
How do I build multi-tenant AI agents into my SaaS?+
How do I give each user their own AI agent identity?+
How do I keep API keys and secrets out of the LLM?+
How do I put spending limits on an AI agent?+
What is an Account Kit?+
How do I give an AI agent delegated, revocable access?+
Do I have to build all of this myself?+
Building the agent-native backend.
The Naïve Developer Platform turns every Naïve primitive into a multi-tenant building block for your own products. 38 primitives across 8 groups, four surfaces (SDK, CLI, MCP, REST), per-customer isolation, governance, and metered billing — so you can give every AI agent a real existence.
Human-in-the-loop approvals that freeze sensitive actions until you say yes, a per-user audit trail of everything an agent did, short-lived scoped MCP sessions, and unified async job tracking — the controls that make an autonomous fleet safe to run.
An autonomous company is a real legal entity run by AI employees instead of humans. Here's what one looks like, what it can actually do today, and how a non-technical founder can start one.
The new @usenaive-sdk/server is a single, Stripe-style TypeScript client for every Naïve primitive — email, cards, apps, LLM, vault, and more — with first-class multi-tenancy and a drop-in agent toolset. A getting-started guide.