Roles and permissions
Authorization answers one question on every request: may this caller do this thing, in this workspace? Three independent things have to agree before the answer is yes.
The intersection
Code
Each narrows. None can widen another. A role that grants workflow:deploy has no effect
if the plan does not include the workflow module, and a plan that entitles everything has
no effect for a user whose roles grant nothing.
The set is computed when the session is built rather than consulted per query, so all three are resolved before your request reaches a handler.
1. Roles grant
A user holds one or more roles in a workspace, and a role is a named list of permissions. Holding two roles grants the union of their permissions: roles add to each other and never subtract.
A workspace can also grant a permission to one person directly, without creating a role for it. That grant is unioned in the same way.
2. The plan entitles
Many permissions belong to a module, and a workspace only holds the modules its plan includes. This is a second, separate gate. See plans and modules for how the two differ and which failure you are looking at, and the permission reference for which permissions need one at all.
The practical effect: a permission your plan does not entitle is dropped from your session even if a role grants it. No error is raised at login. You simply do not hold it, and the endpoint answers 403.
3. The key narrows
An API key acts as the user who created it, so it starts from that user's resolved
permissions. key_permissions then filters that set down:
Code
An empty array means no narrowing: the key carries everything its owner has, which is almost never appropriate for an integration. See authentication.
Read a 403
A refusal reports which of the three gates stopped you in its code:
| Code | Meaning | What fixes it |
|---|---|---|
forbidden | The permission is missing from the session. | A role change, or widening key_permissions. |
license_required | The plan does not include the module. | A plan change. Adding permissions will not help. |
insufficient_credits | The workspace is out of credits. | A top-up. Retrying will not help. |
Branching on code rather than on the status is what lets you tell someone "ask your
administrator for access" instead of "your plan does not include this". They are two
different conversations, and only one is about permissions. See errors.
Every operation names its permission
The permission an endpoint requires is not documentation maintained alongside the code. It is read out of the middleware that enforces it when the spec is generated, so what the reference shows on an operation is the gate that runs.
Most operations name exactly one permission. A few name several, and the spec records
which reading applies in x-permission-mode: all means every permission is required,
and any means one is enough. File operations use any, because which permission applies
depends on where the file lives, and the operation lists every surface that could satisfy
it.
The service also refuses to start if any route declares neither a permission nor an explicit decision to be public. There is no allowlist and no warning-only mode. This matters most for keys, because key scoping works by narrowing a permission set: a route that reads no permission would ignore the narrowing entirely, and a read-only key would call it exactly as an owner's key does.
Permission naming
Code
The resource is the noun from the endpoint: /knowledge-bases is knowledge-base:*,
/share-links is share-link:*, and /workflow-instances is workflow:instance:*.
Reading a permission is usually enough to know what it does.
The verbs are a closed set:
| Verb | Covers |
|---|---|
view | Reading: one record and the list of them. There is no separate list permission. |
create | Making a new one. |
edit | Changing an existing one. |
delete | Removing one. Whether that is recoverable is a property of the resource, noted in the permission reference. |
Anything else is a named action, granted separately because it is separately worth
deciding: upload, download, analyze, search, curate, write, import,
export, crawl, fill, contribute, generate, deploy, execute, publish,
send, run, review, revoke, migration and deduplicate. The permission
reference lists every one of them against the resource it
applies to.
Two consequences are worth knowing up front:
viewincludes content. A knowledge base's documents are the knowledge, soknowledge-base:viewopens them. The media library is the exception:media:viewbrowses and previews, andmedia:downloadretrieves the original. It is the only download permission in the catalog.- Files have no permissions of their own. A file is governed by whatever it belongs
to: a media asset by
media:*, a knowledge document byknowledge-base:*, a conversation's attachment by the conversation. A key scoped tomedia:viewandmedia:downloadtherefore reads the library and provably nothing else.
One prefix is worth noting: admin: covers workspace administration (users, roles,
settings, audit, billing) and the workspace-wide configuration behind a feature, such as
the media tag structure (admin:media-tag:edit) or the social accounts the whole
workspace posts under (admin:social:edit). The rule is who the change affects:
using a feature carries the feature's own prefix, while configuring it for everyone
carries admin:. It is not cross-workspace; that surface is not part of this API.
The built-in roles
A new workspace is seeded with thirteen roles. They are ordinary records that a workspace can edit, delete or add to, but most customers keep them, so an integration can usually assume they exist.
| Role | For |
|---|---|
| Administrator | Full workspace access, including users, roles, and every setting. |
| Billing Administrator | The subscription, plan changes, and credit top-ups, and nothing else. |
| Album Admin | Creating and organizing albums and their contents. |
| Media Editor | The media library end to end: files, versions, albums. |
| Media Viewer | Browsing media, albums, and saved searches. Read-only. |
| Media Uploader | Adding files to the library and to albums. |
| Knowledge Admin | Knowledge bases, their schemas, wildcards, and the content behind them. |
| Knowledge Contributor | Writing knowledge content and records, without changing configuration. |
| Knowledge Viewer | Reading knowledge bases and their records. |
| Designer | Building designs, publishing templates, and defining their editable fields. |
| Design Contributor | Filling approved templates without changing their layout. |
| Chat User | Chat, threads, and AI features. |
| Power User | Chat User, plus building agents, prompts, and the inline AI helpers. |
The tiers are the useful part: Viewer / Contributor / Admin means the same thing in media, knowledge and design, so "what can this person do" is a question you answer once.
Manage roles through the API
Roles and memberships are ordinary resources under /api/v1/admin, each gated on the one
admin:role:* or admin:user:* permission it needs:
Code
Use this to provision people from your own directory rather than by hand. Every change
lands in the audit history (GET /api/v1/admin/history) with the before and after of the
record.
What this does not cover
Permissions decide whether you may call an operation. They do not decide which rows you get back: that is row-level security for the workspace boundary, and row ACLs for sharing inside it. See security and tenancy and sharing and access.
The product guide covers the same subject from the app's side: what a role opens in the app, and how to tell which of the three gates stopped someone.
