Skip to content

Organizations & Departments

The deployment is implicit. It is created at boot, there is exactly one, and there is no object to manage — its policy lives on the Settings page.

The organization is the first level that discriminates anything. Two organizations can see different provider catalogues, route differently, bill against different credentials, and authenticate against different identity providers. A deployment cannot, because there is only one.

Departments sit inside an organization and narrow it further.

Deployment (implicit — Settings page)
└── Organization
└── Department
└── User

Both levels are renameable. Under Settings → Access, relabel them to match your own terminology — “Teams” and “Projects”, say — and the new words appear throughout the console.

Organizations

The list

ColumnWhat it shows
NameThe name, with the slug beneath it
Policy”Inherits everything”, or a count and a summary of the first few overrides
CreatedRelative time, with the exact timestamp on hover
ActionsEdit, Delete

Name and Created are sortable. Search matches name and slug. Clicking a row opens the edit drawer — there is no separate detail page.

Creating and editing

FieldRequiredNotes
NameYesShown here, in user records and in the navigation
SlugYesLower-case letters, numbers and hyphens, up to 50 characters. Unique across the deployment.
PolicyThe same editor Settings uses, so the fields you set here are visibly the ones you are overriding
Providers and modelsEdit only. See Scope Overrides.
Sign-in and provisioningEdit only. SSO and SCIM, below.

The slug is derived from the name until you edit it yourself, and never auto-changes on an existing record.

The slug is what a user types to sign in with SSO. It is the identifier in GET /api/auth/sso/:slug/initiate, so renaming it changes the sign-in URL for everyone in that organization. It is not used anywhere in admin URLs, which key on the ID.

Creating an organization requires deployment scope — there is no level above an organization for a scoped session to be acting in. Deleting one does too.

Deleting

An organization with departments or users under it cannot be deleted. The console counts both before offering the confirmation and, when either is non-zero, shows a blocker with a link to the departments concerned rather than a confirm button. The API refuses the same case with 409 CONFLICT and the count.

Unlike users and API keys, an organization really is removed.

Policy

Each organization may narrow what it inherits from the deployment — never widen it. The editor shows the inherited value beside each field so an override is legible as an override.

A saved organization sends its whole settings object, because the server replaces it outright: omitting a key is how an override is cleared.

Be aware that most of the policy cascade is stored rather than acted on. Today only maxRequestsPerMinute, cachingEnabled, allowedProviders and allowedModels are read by anything at request time. The console says so rather than implying otherwise.

Endpoints

MethodPathPermissionScope
GET/api/admin/organizationsorganizations:readFiltered to the acting scope
GET/api/admin/organizations/:idorganizations:readassertWithinScope
POST/api/admin/organizationsorganizations:createDeployment scope required
PUT/api/admin/organizations/:idorganizations:updateassertWithinScope
DELETE/api/admin/organizations/:idorganizations:deleteDeployment scope required
PUT/api/admin/organizations/:id/ssoorganizations:updateassertWithinScope
POST/api/admin/organizations/:id/scim-tokenorganizations:updateassertWithinScope
DELETE/api/admin/organizations/:id/scim-tokenorganizations:updateassertWithinScope

GET accepts page, limit (capped at 100), sort (name, slug, createdAt, updatedAt), order and search.

PUT reads only name, slug and settings. Credentials, SSO and SCIM cannot be changed through it — they have their own endpoints, so a rename cannot carry an identity change with it.

A department-scoped session listing organizations receives an empty list, not every organization. The Organizations collection has no organization column to filter on, so an unfiltered query would return all of them; the filter is made deliberately unsatisfiable instead.

Departments

The list

Name, Organization, Policy, Created, Actions. Name and Created are sortable; there is also an organization dropdown filter, whose selection is mirrored into the URL as ?organizationId=… so a link from an organization lands pre-filtered.

If no organizations exist, New department is disabled and says why.

Creating and editing

FieldRequiredNotes
NameYes
SlugYesUnique within its organization, not across the deployment
OrganizationYesCreate only. Fixed afterwards.
PolicyInherits the deployment merged with its organization
Providers and modelsEdit only

A department cannot be moved between organizations. organizationId is required at creation and omitted from the update schema entirely, so there is no request that reassigns one. To move a department, create it under the other organization and reassign its users.

There is no SSO or SCIM section on a department. Identity is configured at the organization.

Endpoints

Departments are guarded by the users resource, not a departments one.

MethodPathPermission
GET/api/admin/departmentsusers:read
GET/api/admin/departments/:idusers:read
POST/api/admin/departmentsusers:create
PUT/api/admin/departments/:idusers:update
DELETE/api/admin/departments/:idusers:delete

GET additionally accepts organizationId as a narrowing filter. It narrows within the acting scope and cannot escape it.

That permission mapping has a consequence worth planning around: the built-in org-admin role holds users: [create, read, update] but not users:delete, so an organization administrator can create and rename departments and cannot delete one. dept-admin holds users: [read] only.

A department with users in it cannot be deleted; the API returns 409 CONFLICT with the count.

Per-organization SSO

Each organization can authenticate against its own identity provider. Users reach it at /api/auth/sso/<organization-slug>/initiate; the deployment’s own provider uses the reserved slug system.

There is no fallback. If an organization has no enabled SSO configuration, its sign-in is refused rather than quietly borrowing the deployment’s provider — an organization borrowing the system provider would be authenticated by an authority entitled to system scope. The refusal message is deliberately the same whether the organization has no SSO or does not exist, so the endpoint cannot be used to enumerate organizations.

Configure it under Sign-in and provisioning on the organization, or with PUT /api/admin/organizations/:id/sso:

{
"enabled": true,
"provider": "oidc",
"config": {
"issuerUrl": "https://your-org.okta.com",
"clientId": "...",
"clientSecret": "...",
"scopes": "openid email profile"
},
"claimedDomains": ["example.com"],
"groupRoleMappings": { "Engineering": "org-admin" }
}

provider is oidc or saml. A SAML config takes entryPoint, issuer and cert instead.

Four behaviours worth knowing:

  • Secrets are write-only and merge-on-write. The incoming config is merged over the stored one, so an edit that is not a secret rotation may leave clientSecret out and keep the existing value. Reads report clientSecretSet and certSet rather than the values. Switching protocol replaces the config wholesale instead of merging, because a SAML certificate has no meaning under OIDC.
  • Claimed domains are enforced at login. For an organization-initiated sign in, the email’s domain must be one the organization has claimed, or the login is refused. Claiming a domain requires deployment scope — an organization administrator cannot claim one for itself. Domains are unique across the deployment, and a clash is refused with 409 naming the organization that holds it.
  • Group mappings write memberships. groupRoleMappings maps an IdP group name to a role slug, and roles are re-synced on every login. Only the membership belonging to that issuer is replaced, so an SSO login cannot erase a locally assigned one, or one from another organization’s IdP.
  • Licensing. sso-oidc or sso-saml is checked when SSO is being enabled. Turning it off always works, whatever the licence says.

SCIM provisioning

POST /api/admin/organizations/:id/scim-token issues a bearer token for that organization and returns it once, alongside the base URL to give your IdP:

{
"data": {
"token": "...",
"prefix": "aigw_scim_...",
"scimBaseUrl": "https://gateway.example.com/scim/v2"
}
}

Only a hash and the prefix are stored. If the token is lost, issue a new one.

DELETE .../scim-token disables SCIM for the organization and clears the stored hash. It is deliberately not licence-gated: a licence that has lapsed must not leave a provisioning token you cannot revoke.

Issuing a token requires the scim licence feature.

Placement, and the gotcha it hides

A user’s organizationId and departmentId are a default scope hint, not authority. Authority comes from the per-scope memberships described in Users & Roles. But the two are linked: when you edit a user through the admin, its locally-managed membership is recomputed from its placement, and the scope is the narrowest level named.

  • Department set → membership at department scope.
  • Organization set, no department → membership at organization scope.
  • Neither set → membership at deployment scope.

So a deployment-scoped role does not take effect on an account pinned to a department. It reads wide and acts narrow, because containment comes from the scope the session is acting in — the scope recorded on a role is descriptive and no enforcement path reads it. An account that needs deployment-wide authority must have no organization and no department.

Clearing them is possible, with one asymmetry and one side effect:

  • On update, organizationId and departmentId accept null, and null clears the field. Omitting the key means “leave unchanged”.
  • On create, they accept a string or nothing. null is a validation error — omit the field instead.
  • Clearing both promotes the account’s locally-managed membership to deployment scope, silently, because that is what “neither level named” infers. That is usually what you wanted if you were clearing them deliberately, and a surprise if you were not.

The promotion cannot be used to escalate: role assignment is bounded separately, and an administrator cannot attach a role they do not themselves hold. An organization-scoped administrator is refused the clearing operation outright, because a target with no organization is not within their scope.

  • Scope Overrides — what a scope changes about providers and models
  • Users & Roles — memberships, the scope switcher and role assignment
  • Budgets — spending limits at each level
  • Settings — the deployment policy these inherit from