GenuineAIGenuineAI
For usersFor developers
  • Overview
  • Guides
  • How-to
  • API reference
Documentation
  • Quickstart
  • Authentication
  • Errors
  • Rate limits
  • API reference
Platform
  • Platform overview
  • Solutions
  • Pricing
  • Sign in
Company
  • Status
  • Trust Center
  • Contact
  • Terms of Service
  • Privacy Policy

© 2026 GenuineAI Ventures LLC

support@genuinehq.com
Start here
QuickstartAuthentication
Working with the API
Objects and fieldsErrorsPaginationRate limitsMaintenance windowsVersioning and deprecation
Security
Security and tenancyRoles and permissionsPermission referenceSharing and access
Your plan
Plans and modules
Guides

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
what the user's roles grant ∩ what the workspace's plan entitles ∩ what the key was scoped to = what this request may do

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
{ "key_permissions": ["media:view", "media:download", "album:view"] }

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:

CodeMeaningWhat fixes it
forbiddenThe permission is missing from the session.A role change, or widening key_permissions.
license_requiredThe plan does not include the module.A plan change. Adding permissions will not help.
insufficient_creditsThe 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
knowledge-base:record:view └────────────┘ └────┘ └──┘ | | └─ verb | └─ sub-resource, where one exists └─ resource, named as the API path names it

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:

VerbCovers
viewReading: one record and the list of them. There is no separate list permission.
createMaking a new one.
editChanging an existing one.
deleteRemoving 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:

  • view includes content. A knowledge base's documents are the knowledge, so knowledge-base:view opens them. The media library is the exception: media:view browses and previews, and media:download retrieves 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 by knowledge-base:*, a conversation's attachment by the conversation. A key scoped to media:view and media:download therefore 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.

RoleFor
AdministratorFull workspace access, including users, roles, and every setting.
Billing AdministratorThe subscription, plan changes, and credit top-ups, and nothing else.
Album AdminCreating and organizing albums and their contents.
Media EditorThe media library end to end: files, versions, albums.
Media ViewerBrowsing media, albums, and saved searches. Read-only.
Media UploaderAdding files to the library and to albums.
Knowledge AdminKnowledge bases, their schemas, wildcards, and the content behind them.
Knowledge ContributorWriting knowledge content and records, without changing configuration.
Knowledge ViewerReading knowledge bases and their records.
DesignerBuilding designs, publishing templates, and defining their editable fields.
Design ContributorFilling approved templates without changing their layout.
Chat UserChat, threads, and AI features.
Power UserChat 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:

TerminalCode
curl https://api.genuineai.app/api/v1/admin/roles \ -H "X-Api-Key: gai_…" \ -H "X-Tenant-Id: <workspace-id>"

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.

Last modified on October 8, 2026
Security and tenancyPermission reference
On this page
  • The intersection
    • 1. Roles grant
    • 2. The plan entitles
    • 3. The key narrows
  • Read a 403
  • Every operation names its permission
  • Permission naming
  • The built-in roles
  • Manage roles through the API
  • What this does not cover
JSON