How do I give each of my customers their own AI agent?
By Naol Ketema, founder · · Markdown
SHORT ANSWER
Create one agent identity per customer, each with its own mailbox, its own API key and its own webhook, and keep the mapping from customer to agent id in your database. Run each customer's agent with its agent key so it can only reach its own mailbox and events. Use a separate organization per customer only when you need hard isolation of limits, keys and billing.
What per-customer agents need
If your product gives each customer an AI agent, the agents need the same separation the customers have. Customer A's agent must not read customer B's mail, send as customer B, or see customer B's events. Each agent needs its own address so replies go back to the right place, and you need a way to switch one agent off without touching the rest.
In Agent Identity terms, the organization is the tenancy boundary and the agent is the thing that acts. Every row belongs to exactly one organization, and the API derives the organization from the key, never from the request.
Pattern 1: one organization, one agent per customer
This is the default for most SaaS products. Your company owns one organization. Each customer gets an agent inside it, with a handle derived from the customer, its own mailbox, and an agent key that your backend stores against the customer.
- Mail isolation: an agent key reaches only its own agent. Another agent's mailbox reads as 404, and events and webhooks are limited to its own.
- Keys: an agent key cannot create agents, list keys or mint keys. Your provisioning service holds the org key; each customer's runtime holds only its agent key.
- Addresses: handles are unique per organization, and the mailbox address is the handle at your sending domain. With a verified custom domain you can pass domain when creating the agent, for example handle support with domain acme.dev gives support@acme.dev.
- Webhooks: create one endpoint per agent with identityId, so each delivery is already scoped to one customer.
- Off switch: suspend an agent to stop it sending and receiving without losing history, and reinstate it later. Suspensions require the org key and are recorded with a reason.
import { AgentClient } from "@agentidentity/sdk";
const admin = new AgentClient({ baseUrl: "https://api.agent-identity.dev", apiKey: process.env.AID_ORG_KEY! });
export async function provisionCustomerAgent(customer: { id: string; slug: string; name: string; domain?: string }) {
const agent = await admin.identities.create({
handle: `${customer.slug}-assistant`,
displayName: `${customer.name} Assistant`,
...(customer.domain ? { domain: customer.domain } : {}),
});
const { key } = await admin.apiKeys.create({ name: `customer ${customer.id}`, identityId: agent.id });
const hook = await admin.webhooks.create({
url: `https://app.example.com/hooks/aid/${customer.id}`,
identityId: agent.id,
eventTypes: ["mail.received", "mail.bounced", "mail.complained"],
});
await saveCustomerAgent(customer.id, {
identityId: agent.id,
address: agent.mailboxAddress,
apiKey: key, // encrypt at rest; shown once
webhookSecret: hook.secret, // shown once
});
return agent;
}
export async function offboardCustomer(identityId: string) {
await admin.identities.suspend(identityId, "customer offboarded");
}Handles are unique per organization, even across different domains, so two customers cannot both have an agent called assistant in one organization. Prefix handles with something unique to the customer.
What customers share in one organization
One organization is one set of limits. Know which ones your customers share before you scale:
- Request rate: 600 authenticated requests a minute per organization, across all keys. Past it is 429 rate_limit.exceeded with Retry-After.
- Daily sends: email counts against one daily quota per organization, so one busy customer can use up the budget for everyone. Enforce a per-customer budget in your own code.
- Agent count: the plan caps how many agents an organization holds. Creating one past the cap is 403 identity.limit_reached. client.usage() returns the count and the limit.
- Agent2Agent: agents in the same organization can send each other tasks by default. filter_mode does not apply inside an organization, so if customers' agents must not talk to each other, add block rules between them or turn Agent2Agent off for agents that do not need it.
- Org-wide reads: an org key can search every mailbox with searchOrganization. That is useful for your support team and is another reason the org key never leaves your backend.
Pattern 2: one organization per customer
When a customer needs hard isolation, such as their own limits, their own keys that you could hand over, or their own plan, create an organization for them. Organizations share nothing except the deliberately public Agent2Agent surfaces: the agent card and the directory.
The cost is operational. createOrganization is unauthenticated and returns an admin key once, which you must store. Each organization has its own owner, and until that owner verifies the six-digit code sent to them, the organization can only email that owner. Each organization is also its own plan. The docs do not describe parent and child organizations or combined billing, so plan to track the set of organizations yourself.
Choosing between them
- Choose one organization with many agents when you run the agents for your customers, want one place to operate them, and can enforce per-customer budgets in your code.
- Choose one organization per customer when customers manage their own agents, need limits that cannot be affected by other customers, or require that no shared admin key can read their mail.
- Start with the first. Moving a large customer to its own organization later is a provisioning change, not a redesign, as long as your code always looks up the agent id and key per customer.
Pricing
Agent Identity has a free plan for exploring, Builder at $19 a month for developers running agents in production, and Team at $149 a month for teams running agent fleets. Email, a public URL and agent-to-agent messaging are on every plan. Limits such as agents per organization and emails a day depend on the plan; read them from client.usage() rather than hard-coding them.
FAQ
Can one customer's agent read another customer's email?
Not with its own agent key. An agent key reaches only its own agent, and another agent's mailbox reads as 404. Only an org key can read across agents in an organization.
Can each customer's agent send from the customer's own domain?
Yes. Verify the domain in your organization with a TXT record, have the customer publish the SPF, DKIM and DMARC records, then pass domain when creating that customer's agent. Handles stay unique across the whole organization.
How do I stop one customer's agent without affecting others?
Suspend it with the org key. It stops sending and receiving, keeps its history, and can be reinstated. Revoke its API key as well if the key may have leaked.
Can I delete a customer's agent?
There is no delete for agents. Suspension is the supported way to take one out of service, and mail and threads can be deleted separately if you need to remove data.
Related guides
Give your agent its own identity in a couple of minutes. Get started free → · Docs · All guides