---
title: Roles and Permissions
path: core-concepts/roles-and-permissions
status: published
---

# Roles and Permissions

ScaiGrid authorization is permission-based. Roles are bundles of permissions. Users get roles; endpoints check permissions.

## Built-in roles

Six roles ship out of the box, covering the common hierarchy:

| Role | Scope | Typical use |
|------|-------|-------------|
| `super_admin` | Platform | Platform operators — full access |
| `partner_admin` | Partner | Reseller administrators |
| `partner_viewer` | Partner | Partner-level read-only / accounting |
| `tenant_admin` | Tenant | Customer admin — manages their own tenant |
| `tenant_user` | Tenant | Regular user — uses models, manages own keys |
| `tenant_viewer` | Tenant | Read-only user — can list models, view own usage |

Permission bundles (from lowest to highest):

**`tenant_viewer`** — `models:list`, `accounting:view_own`.

**`tenant_user`** — tenant_viewer permissions plus `models:use`, `api_keys:manage`, `modules:use`.

**`tenant_admin`** — tenant_user permissions plus `routing:view`, `accounting:view_tenant`, `accounting:manage_budgets`, `users:manage`, `webhooks:manage`, `modules:manage`, `admin:access`.

**`partner_viewer`** — `models:list`, `accounting:view_own`, `accounting:view_tenant`, `accounting:view_partner`.

**`partner_admin`** — partner_viewer permissions plus `accounting:manage_budgets`, `users:manage`, `admin:access`.

**`super_admin`** — every permission, all the time, platform-wide.

## Core permissions

The 15 core permissions ScaiGrid uses internally:

| Permission | What it grants |
|------------|----------------|
| `models:list` | See which models are available |
| `models:use` | Call inference endpoints |
| `models:manage` | Create, update, delete models and backends |
| `routing:view` | See routing policies |
| `routing:manage` | Edit routing policies and model/backend mappings |
| `accounting:view_own` | View your own usage |
| `accounting:view_tenant` | View full tenant usage |
| `accounting:view_partner` | View partner-level usage across tenants |
| `accounting:manage_budgets` | Create, update, enforce budgets |
| `users:manage` | Create, update, delete users in tenant |
| `api_keys:manage` | Create and revoke your own API keys |
| `webhooks:manage` | Configure outbound webhooks |
| `modules:use` | Call module endpoints |
| `modules:manage` | Enable, disable, configure modules |
| `admin:access` | Access the admin UI |

## Module permissions

Modules register their own permissions. They follow the convention `{module_id}:{action}` and are stored on the user as a separate set from core IAM permissions. A few representative examples:

- `scaibot:manage` — manage chatbot configurations
- `scaimatrix:ingest` — add documents to a knowledge collection
- `scaibunker:execute` — run commands inside a sandbox
- `scaibunker:admin:tenant` — manage tenant-scoped quota profiles + assignments
- `scaiqueue:publish` — send messages to a queue

ScaiBunker has the most granular permission set in the platform — covering bunker creation, lifecycle modes, network profiles, image management, and tiered admin levels (`scaibunker:admin`, `scaibunker:admin:tenant`, `scaibunker:admin:platform`). See [ScaiBunker → Permissions](/docs/scaigrid/scaibunker#permissions) for the full table.

**Implicit grants on tenant / partner admin roles.** Tenant admins and partner admins receive every module permission by default through a short-circuit in `has_module_permission`. This means a `tenant_admin` automatically has `scaibunker:admin:tenant` (the intent), and also nominally has `scaibunker:admin:platform` (which is route-gated separately to platform-only operations like cross-tenant availability-group management). Module routes that need platform-scope authorization check the user's role rather than the module-permission flag.

See each module's page in the [Modules section](/docs/scaigrid/) for its full permission list.

## How permissions resolve

A user's effective permissions come from three sources, combined:

1. **Role-based permissions.** Each role the user has contributes its permission set. A `tenant_user` contributes `models:use`, `api_keys:manage`, etc. A user can have multiple roles (unusual but supported) and their effective permissions are the union.
2. **Group mappings.** ScaiKey groups can map to ScaiGrid roles via the `role_mappings` table. If you're in a ScaiKey group mapped to `tenant_admin`, you get that role whenever you authenticate. Configure via `/v1/role-mappings`.
3. **Module permissions.** Users can have per-module permissions granted directly (not through a role). These are additive — a user who's a `tenant_user` plus has `scaibot:manage` granted can use models and manage bots, but not other admin functions. Configure via `/v1/users/{user_id}/module-permissions`.

Effective permission set = (role permissions) ∪ (group-mapped permissions) ∪ (direct module permissions).

### Per-resource ACLs (some modules)

Some modules layer a per-resource ACL on top of the role/permission system. The role/permission system gates *whether you can use the module's API*; the ACL gates *which specific resources within the module you can touch*.

[ScaiMatrix](/docs/scaigrid/scaimatrix#permissions) is the most prominent example — collections and individual documents each carry an NTFS-style ACL with allow/deny entries, parent inheritance, and an owner concept. A user with `scaimatrix:search` can call the search endpoint, but the ACL decides which collections and documents the search results actually contain.

When both a module permission and an ACL apply, the user needs both. Group memberships are expanded transitively where the module supports it, including nested groups.

## Custom roles

If the six built-in roles don't match your access pattern, create a custom role. Custom roles are tenant-scoped, composed from any mix of core permissions and module permissions.

```bash
curl -X POST https://scaigrid.scailabs.ai/v1/custom-roles \
  -H "Authorization: Bearer $TENANT_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Analytics Team",
    "slug": "analytics",
    "description": "Can view all tenant usage and export reports, no admin access",
    "core_permissions": ["accounting:view_tenant", "models:list"],
    "module_permissions": []
  }'
```

Assign to a user:

```bash
curl -X PUT https://scaigrid.scailabs.ai/v1/users/{user_id}/roles \
  -H "Authorization: Bearer $TENANT_ADMIN_TOKEN" \
  -d '{"roles": ["tenant_user"], "custom_role_ids": ["role_abc"]}'
```

Custom roles can include any module permission the tenant has enabled. See [Custom Roles](../07-advanced/04-custom-roles.md).

## Checking permissions programmatically

The current user's permissions are available at `/v1/me`:

```bash
curl -H "Authorization: Bearer $TOKEN" https://scaigrid.scailabs.ai/v1/me
```

```json
{
  "status": "ok",
  "data": {
    "user_id": "...",
    "email": "alice@acme.example",
    "tenant_id": "...",
    "roles": ["tenant_admin"],
    "permissions": ["models:use", "users:manage", ...],
    "module_permissions": ["scaibot:manage", "scaimatrix:search", ...]
  }
}
```

Useful for building permission-aware UI — show the "Manage users" button only to callers with `users:manage`.

## What happens on a permission denial

Requests without sufficient permissions return `403 AUTHZ_PERMISSION_DENIED`:

```json
{
  "status": "error",
  "error": {
    "code": "AUTHZ_PERMISSION_DENIED",
    "message": "User lacks required permission"
  }
}
```

No indication of which specific permission is missing — to avoid leaking the permission taxonomy to unauthenticated callers. Authenticated admins can inspect a user's permissions directly.

## What's next

- [Custom Roles](../07-advanced/04-custom-roles.md) — design patterns for tenant-specific access control.
- [Authentication](../02-getting-started/02-authentication.md) — how tokens and API keys are issued.
- [Users and Access Reference](../06-reference/02-users-and-access.md) — full endpoint list.
