Core concepts¶
Read this once. Every other page assumes you know what a scope is, what your role can do, the two kinds of keys, and that everything is recorded as an event.
Organizations, teams, and projects¶
Agent Access Manager is multi-tenant. The unit of tenancy is the organization (org). Inside an org you can carve out teams and projects:
flowchart TD
O["Organization<br/>(the tenant: one base currency, its own catalog, its own data)"]
T1["Team: Platform"]
T2["Team: Data Science"]
P1["Project: chatbot"]
P2["Project: batch-jobs"]
P3["Project: research"]
O --> T1
O --> T2
T1 --> P1
T1 --> P2
T2 --> P3
- An org is the hard tenant boundary. Its catalog, budgets, guardrails, keys, audit trail, and spend are its own and are never shared with another org. Each org has one base currency (default USD) that all its pricing, budgets, and spend are denominated in, so totals add up with no currency conversion.
- A team groups people and work inside an org. Teams can have a lead, who gets a delegated slice of authority (for example, setting a project budget within their own team) without being an org admin.
- A project is the finest grouping, used to attribute keys, spend, and limits to a piece of work.
- A person has one account in one org (the one-account-one-org rule). A brand-new user with no org is sent to a short onboarding screen to create or join one.
Who manages the org vs the appliance
Membership roles (below) let people run their own org. Separately, the platform admin is the person who operates the appliance itself (the break-glass admin login or an SSO user with the platform-admin role). The platform admin can act across every org and picks which org to act on per screen; an org member is always locked to their own org.
Scopes and the scope chain¶
Almost every control in the product (a virtual key, a budget, a rate limit, a guardrail policy) attaches to a scope. There are four scope levels, from broadest to narrowest:
| Scope level | What it means | Example |
|---|---|---|
ORG |
The whole organization | "Acme can spend $5,000/month total" |
TEAM |
One team in the org | "Data Science is capped at 2M tokens/day" |
PROJECT |
One project in a team | "The research project gets 60 requests/min" |
KEY |
A single virtual key | "This one key may not exceed $50/day" |
When a request arrives, Agent Access Manager looks at the calling key and builds its scope chain: the key itself, plus whichever of project, team, and org it belongs to. A key always belongs to an org; team and project are optional and set when the key is issued.
flowchart LR
K["KEY<br/>sk-… (this request)"] --> P["PROJECT<br/>(if the key has one)"]
P --> T["TEAM<br/>(if the key has one)"]
T --> ORG["ORG<br/>(always)"]
classDef present fill:#E9F1FF,stroke:#2F7CFF,color:#0B0F1A;
class K,P,T,ORG present;
The single most important rule:
How scopes apply
Budgets and rate limits are enforced at every level of the chain at once. A call charged to a key also counts against that key's project, team, and org. The request is allowed only if it passes at all present levels. So an org-wide monthly cap, a team's daily cap, and a single key's hourly cap can all be in force on the same request, and the tightest one wins.
Guardrail policies resolve most-specific-first. The narrowest scope that has a policy for a given content category decides the action, so a team can tighten (or loosen, if allowed) what the org sets.
This is why you can hand a team lead a key and trust that it cannot blow the org budget: the org cap still applies on top of anything set lower down. It is also why cost-aware failover works (see routing): when a per-deployment budget at any level is exhausted, the request fails over to a cheaper backend instead of being denied.
Roles and capabilities¶
What you can do is decided by your org role. Roles are strictly nested (each higher role includes everything below it) and grant capabilities. The dashboard hides or disables what your capabilities do not cover, but the server is always the real gate, so hiding a button is a convenience, not the security boundary.
| Capability | Guest | User | Operator | Admin | Owner | What it unlocks |
|---|---|---|---|---|---|---|
VIEW |
✅ | ✅ | ✅ | ✅ | ✅ | Read the dashboards |
ISSUE_KEYS |
✅ | ✅ | ✅ | ✅ | Issue / manage virtual keys in your scope | |
VIEW_BUDGETS |
✅ | ✅ | ✅ | ✅ | See budgets and spend | |
MANAGE_GATEWAY |
✅ | ✅ | ✅ | Guardrails, rate limits, SOAR rules, notifications | ||
MANAGE_DEPLOYMENTS |
✅ | ✅ | ✅ | Catalog deployments (model alias, pricing) | ||
MANAGE_TEAMS |
✅ | ✅ | ✅ | Create / manage teams | ||
MANAGE_MEMBERS |
✅ | ✅ | ✅ | Invite / manage users and guests | ||
VIEW_SECURITY |
✅ | ✅ | ✅ | SIEM, UEBA, SOAR, sign-in activity | ||
VIEW_REPORTS |
✅ | ✅ | ✅ | View reports | ||
MANAGE_REPORTS |
✅ | ✅ | ✅ | Author / schedule / run reports | ||
MANAGE_PROVIDERS |
✅ | ✅ | Catalog providers + master vendor credentials | |||
MANAGE_BUDGETS |
✅ | ✅ | Set budgets and cost caps (the money domain) | |||
MANAGE_ORG |
✅ | Org settings, archive, manage admins |
A few deliberate splits worth understanding:
- The operator owns the rules of engagement, not the money. An operator configures guardrails, rate limits, routing (deployments), and SOAR, but cannot set budgets. Setting budgets is
MANAGE_BUDGETS, which is admin and owner only. - The catalog is split by sensitivity. Connecting a vendor and storing its master key is
MANAGE_PROVIDERS(admin-grade, because it holds a credential). Defining a model alias and its pricing isMANAGE_DEPLOYMENTS(operator and up, because routing is the operator's job). Everyone can read the catalog. - The team lead is a delegated grant outside the role table. A team lead (
is_leadon their team membership) can curate their team's roster and set a project budget inside their team, without being an org admin. They cannot raise their team's own cap. - Anti-escalation. You can only assign or manage roles strictly below your own. An unknown stored role fails closed to
GUEST.
Two kinds of credentials¶
There are two completely separate front doors, and they never mix.
| Virtual keys (the data plane) | The admin plane | |
|---|---|---|
| Who uses it | Your applications | Humans (and scripts) administering the product |
| Where | POST /v1/chat/completions, /v1/messages, … |
/admin/** and the dashboard |
| Credential | A sk-… virtual key (Bearer) |
A browser session via SSO, the break-glass Basic admin, or an OIDC Bearer token |
| Stored as | SHA-256 hash (the secret is shown once at issue) | No password store here; the human session lives at your IdP |
Virtual keys are what you give to applications. They are 256-bit sk--prefixed tokens, hashed at rest, and they carry their scope (org, optional team, optional project) so the whole governance chain is known the instant a request arrives. You issue, revoke, and cap them on the Virtual keys page.
The admin plane is the dashboard and its API. It is SSO-first: if your deployment configures Keycloak (or any OIDC provider), people sign in there and Agent Access Manager only validates the resulting token. The local username/password form is a break-glass path, on by default until SSO is configured and then off. See Settings ▸ Authentication and the deep dive in authentication.
One endpoint, many vendors¶
Your applications always speak the OpenAI chat shape to Agent Access Manager, regardless of which vendor ultimately serves the request. Inbound surfaces (/v1/chat/completions, /v1/responses, /v1/messages, /v1/embeddings) are mapped to one canonical format; outbound adapters translate that to whatever the chosen vendor speaks (OpenAI-compatible passthrough, or translating adapters for Anthropic, Gemini, and Vertex).
The practical consequences for you:
- You can switch a model alias from, say, OpenAI to a local Ollama or to Anthropic without changing a line in your application. Only the Catalog changes.
- A model alias (what your app asks for, like
gpt-4o-miniorfast-cheap) is decoupled from the upstream model a vendor actually runs. Budgets and reports key on the alias, so they stay stable even as you re-point it.
Everything is an event¶
Every proxied call publishes a durable event in the same transaction as the work. That one event stream is the backbone of all governance:
flowchart LR
GW["A proxied call"] -->|publishes| OB[("durable outbox")]
OB --> AUD["Audit trail<br/>(Audit & usage)"]
OB --> SPEND["Spend metering<br/>(Budgets)"]
OB --> ALERT["Alerts<br/>(Notifications)"]
OB -. "Pro" .-> SIEM["SIEM / UEBA / SOAR"]
AUD --> RPT["Reports"]
Because the event is written transactionally (a durable outbox), a call's audit record can never be lost, and consumers run off the hot path: a slow analytics query or an OpenSearch outage adds zero latency to the call your application made. This is why the same data shows up consistently in Audit & usage, Budgets, Reports, and (on Pro) SIEM: they are all reading the one event stream, each for their own purpose.
The events worth knowing by name:
| Event | Emitted when | Feeds |
|---|---|---|
LlmCallCompleted |
Any completion attempt finishes | Audit trail, spend, SIEM/SOAR |
GuardrailTriggered |
A guardrail flags / redacts / blocks | Guardrail trail, alerts, SIEM/SOAR |
SecurityActionTaken |
SOAR contains something (quarantine / throttle) | Audit, SIEM |
ScopeDeleted |
An org or team is hard-deleted | Tenant purge: budgets, keys, rules, audit are erased |
ConfigChanged |
An admin changes config | The admin-action audit trail |
Next: Operate → for the day-to-day screens, or jump to any section from the I want to… table.