> ## Documentation Index
> Fetch the complete documentation index at: https://unkey.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Unkey is two separate products. Compute builds, deploys, and runs apps behind a gateway. API Management issues API keys, enforces rate limits, manages identities and permissions, and reports usage. Say which product a page belongs to; a reader can use either without the other.
> Every Unkey API endpoint is an HTTP POST to https://api.unkey.com/v2/{service}.{procedure} with a root key in the Authorization: Bearer header. Root keys are workspace scoped.
> Error codes have the form err:{system}:{category}:{specific} and each has a page at /errors/{system}/{category}/{specific}.
> The word environment means production or preview in Compute. Rate limiting has four meanings on this site; the glossary lists them.

# Roles and permissions

> Define the permissions your API checks and group them into roles.

Create a permission for each action your API checks, and group them into roles for the access levels you offer. Permissions and roles belong to the workspace, so one set covers every keyspace. To attach them to keys, see [Managing key roles and permissions](/docs/api-management/authorization/managing-key-permissions).

<Note>
  You need a root key with the permissions listed on this page. Create one in the dashboard under **Settings > Root Keys**. See [Permission reference](/docs/platform/root-keys/permissions-legacy) for every permission.
</Note>

The endpoints need the matching `rbac.*` permission: `create_permission`, `read_permission`, `delete_permission`, `create_role`, `read_role`, `delete_role`, and `add_permission_to_role` together with `remove_permission_from_role` for `permissions.setRolePermissions`.

## Permissions

<ParamField body="name" type="string" required>
  1 to 512 characters. A readable label shown in the dashboard.
</ParamField>

<ParamField body="slug" type="string" required>
  1 to 128 characters matching `^[a-zA-Z0-9_:\-\.\*]+$`, unique within the workspace. This is the string keys hold and queries check. `documents.read` and `billing:write` are both fine. An asterisk is allowed but is a literal character, not a wildcard. See [Permission queries](/docs/api-management/authorization/permission-queries).
</ParamField>

<ParamField body="description" type="string">
  Up to 512 characters of internal documentation.
</ParamField>

```bash theme={"system"}
curl -X POST https://api.unkey.com/v2/permissions.createPermission \
  -H "Authorization: Bearer $UNKEY_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Read documents", "slug": "documents.read", "description": "List and fetch documents" }'
```

The response has `permissionId` (`perm_...`). A duplicate slug fails with HTTP 409 [`err:unkey:data:permission_already_exists`](/docs/errors/unkey/data/permission_already_exists).

* `permissions.getPermission` takes the ID or slug.
* `permissions.listPermissions` takes `limit` (1 to 100, default 100), `cursor` (up to 1024 characters), and `search` (up to 256 characters, matched against ID, name, slug, or description, ignoring case).
* `permissions.deletePermission` deletes the permission and removes it from every role and key.

## Roles

<ParamField body="name" type="string" required>
  1 to 128 characters, unique within the workspace. Keys refer to roles by name. Spaces are allowed.
</ParamField>

<ParamField body="description" type="string">
  Up to 512 characters.
</ParamField>

<ParamField body="permissions" type="string[]">
  Permission slugs to attach. Slugs that don't exist yet are created if the root key also has `rbac.*.create_permission`. Without it, an unknown slug fails with HTTP 403 `err:unkey:authorization:insufficient_permissions`. Leave it out or send `[]` for an empty role.
</ParamField>

```bash theme={"system"}
curl -X POST https://api.unkey.com/v2/permissions.createRole \
  -H "Authorization: Bearer $UNKEY_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "editor",
    "description": "Read and write documents",
    "permissions": ["documents.read", "documents.write"]
  }'
```

The response has `roleId` (`role_...`). A duplicate name fails with HTTP 409 [`err:unkey:data:role_already_exists`](/docs/errors/unkey/data/role_already_exists). `permissions.getRole` and `permissions.listRoles` return roles with their permissions. `permissions.deleteRole` deletes the role, and keys lose its permissions unless they get them another way.

### Change a role's permissions

`permissions.setRolePermissions` takes `role` (ID or name) and the full list of slugs. Anything not in the list is removed, and `[]` empties the role. (The older `roleId` field still works but is deprecated. Send one or the other.) New slugs are created under the same rule as `createRole`. Every key with the role picks up the change within about 10 seconds, and a few verifications just after that can still see the old permissions. [Verifying keys](/docs/api-management/keys/verifying-keys#how-quickly-changes-take-effect) describes the timing.

```bash theme={"system"}
curl -X POST https://api.unkey.com/v2/permissions.setRolePermissions \
  -H "Authorization: Bearer $UNKEY_ROOT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "role": "editor", "permissions": ["documents.read", "documents.write", "documents.delete"] }'
```

## Designing the set

* **Name permissions after actions**, not customers: `invoices.read`, `invoices.write`, `invoices.void`.
* **Name roles the way you talk to customers**: `viewer`, `editor`, `admin`, or plan names.
* **Attach roles to keys**, and save direct permissions for one-off grants. Then changing what "editor" means is one `setRolePermissions` call, not an update to every key.
* **Use a role for "everything under documents".** An asterisk isn't a wildcard, so list each `documents.*` permission in the role.

## From the dashboard

Open **Authorization** in the sidebar. On the **Permissions** tab, create and edit permissions. On the **Roles** tab, create and edit roles, pick their permissions (or create new ones), and assign the role to keys.

<Frame>
  <img src="https://mintcdn.com/unkey/TjbnJStfcJRkiuek/images/dashboard/api-management--authorization-roles-and-permissions--edit-role.png?fit=max&auto=format&n=TjbnJStfcJRkiuek&q=85&s=fbd8600c1bf8f994d3e3c43edbf0eef1" alt="Edit role dialog showing the keys assigned to the role and its assigned permissions" width="2560" height="1600" data-path="images/dashboard/api-management--authorization-roles-and-permissions--edit-role.png" />
</Frame>
