Gateway access is decided on two separate axes: RBAC decides what a person or credential may configure in the console and admin API, and model access controls decide which models a request may call. This page covers both. For the organization → product → workspace model and how teams are managed, see Teams & permissions.

How it works

  • Owner is the only organization role. It manages members, security and who may reach each product, and grants no Gateway access by itself.
  • Product roles are member < editor < admin. A product role applies in every workspace of the product, including ones created later.
  • Workspace roles use the same three names and are effective only while the holder also has Gateway access.

Gateway permissions

Roles are defined in code; each role holds everything the role below it holds.
PermissionMemberEditorAdmin
gateway.requests.execute — call models through /v1✓✓✓
gateway.workspaces.read, gateway.members.read✓✓✓
gateway.providers.read, gateway.models.read✓✓✓
gateway.routing.read, gateway.policies.read, gateway.guardrails.read✓✓✓
gateway.ratelimits.read, gateway.budgets.read✓✓✓
gateway.apikeys.read, gateway.serviceaccounts.read✓✓✓
gateway.analytics.read, gateway.observability.read✓✓✓
gateway.apikeys.manage✓✓
gateway.serviceaccounts.manage — virtual accounts and their tokens✓✓
gateway.models.manage — models and model restriction policies✓✓
gateway.routing.manage — virtual models and routing configs✓✓
gateway.workspaces.manage, gateway.members.manage✓
gateway.providers.manage✓
gateway.policies.manage, gateway.guardrails.manage✓
gateway.ratelimits.manage — rate limits, token limits, access policies✓
gateway.budgets.manage✓
gateway.audit.read✓
gateway.traces.sensitive.read — reveal PII removed from a trace✓
gateway.observability.manage — trace export destinations✓
Permissions are namespaced by product. A gateway.* permission is never satisfied by a Studio or Deployer role, and no product role grants any org.* permission.

Workspace roles and custom roles

Inside a workspace, a member holds exactly one system role plus any number of the workspace’s custom roles and individual extra permissions. Custom roles and extras only add; they are built from the gateway.* permissions above. In the console this lives under Gateway → Access → Roles.
MethodPathBody
GET/api/v1/gateway/workspaces/{id}/roles— lists every permission, the three system roles and custom roles
POST/api/v1/gateway/workspaces/{id}/roles{name, description, permissions}
GET/PATCH/DELETE/api/v1/gateway/workspaces/{id}/roles/{roleID}PATCH: {name?, description?, permissions?}
PUT/DELETE/api/v1/gateway/workspaces/{id}/roles/system/{role}{permissions} — change (PUT) or reset (DELETE) what member or editor grants in this workspace
GET/PUT/api/v1/gateway/workspaces/{id}/members/{userID}/access{role, custom_role_ids, extra_permissions}
A role name is 1–48 characters: letters, digits, spaces, ., _ or -, starting with a letter or digit.
curl -X POST https://app.manylayers.io/api/v1/gateway/workspaces/ws_123/roles \
  -H "Authorization: Bearer ml_pat_..." -H "Content-Type: application/json" \
  -d '{"name": "Routing operator", "description": "Edits virtual models",
       "permissions": ["gateway.routing.manage", "gateway.models.manage"]}'
None of this can escalate. Reading needs gateway.members.read and changing needs gateway.members.manage in that workspace; you can only grant permissions you hold there yourself, cannot hand out a system role above your own, and cannot demote the last manager. The admin role always holds everything and is not editable.

Credentials and service identities

CredentialPrefixActs as
Admin-created API keyml-A key filed under one team, optionally bound to one workspace, with a member, editor or admin role
Personal access tokenml_pat_Its owner, within one workspace; always expires
Virtual account tokenml_vat_A virtual (service) account: the member role plus explicit allowlists, never its creator’s authority
A virtual account must be created with both allowed_models and allowed_providers; an account that names none reaches none. Tokens are issued only from a console session, never from another token, and their plaintext appears only in the response that issued them. In the console, find these under Gateway → Access → Personal Access Tokens and Virtual Accounts. See Credentials for the full API.
curl -X POST https://app.manylayers.io/api/v1/gateway/virtual-accounts \
  -H "Cookie: ml_session=..." -H "Content-Type: application/json" \
  -d '{"name": "billing-bot", "workspace_id": "ws_123", "owner_team_id": "team_9",
       "allowed_models": ["gpt-4o-mini"], "allowed_providers": ["prov_openai"],
       "token": {"name": "prod", "expires_at": "2027-01-01T00:00:00Z"}}'

Restricting model access

Several independent checks run on every /v1 request; a model must pass all of them.
An ml_vat_ token can reach only the models and providers its account lists. Anything else returns 403 model_not_allowed.
A team’s models list (logical names, or *). A team with no list configured is unrestricted. Otherwise a request for an unlisted model returns 403 model_not_allowed. To call a virtual model, the list must include its name. Set it with POST /admin/teams (organization Owner only).
A provider account can be restricted to named users, teams or everyone in the workspace, as user (may call its models) or manager (may also edit it). everyone can only be granted user. An account with no bindings is open to its workspace. A refused caller gets 403 provider_access_denied.
curl -X POST "https://app.manylayers.io/admin/gateway/providers/prov_123/access?workspace_id=ws_123" \
  -H "Authorization: Bearer ml_pat_..." -H "Content-Type: application/json" \
  -d '{"role": "user", "subjects": [{"type": "team", "id": "team_9"}]}'
Subject type is user, team or everyone (no id). List bindings with GET, remove one with DELETE /admin/gateway/providers/{id}/access/{bindingID}. Needs gateway.providers.manage.
PUT /admin/gateway/providers/{id}/scope with {models_scope, model_ids, api_keys_scope, api_key_ids}, each scope all or specific, limits an account to particular models or to traffic from particular API keys. GET returns the current scope.
Allow- and deny-lists at organization, workspace, team, service-account, user or API-key scope; deny wins. Managed in Gateway → Policies → Model restrictions or at /admin/gateway/policies/model-restrictions with gateway.models.manage. See Policies.
Routing configs are checked target by target: a target the caller may not use is skipped, never served. Auto Routing and virtual models cannot route around a deny; if every target is refused the caller gets 403 model_not_allowed.

Next steps

Teams & permissions

Organization, product and workspace rungs.

Credentials

PATs, virtual accounts and rotation.

Policies

Access policies and model restrictions.

Rate limiting

Per-identity request and token ceilings.