Manage roles
Last updated: Sep-04-2025
Cloudinary roles define what principals (users, groups, and API keys) can access and do across your account. Managing roles via the Permissions API allows you to create, update, and delete custom roles programmatically, so you can scale permissions consistently without assigning individual policies one by one.
On this page, you'll learn how to:
- Retrieve roles and system policies
- Manage custom roles
- Plan roles effectively, with key considerations in mind
How you can help:
- Use Roles and Permissions Management in real projects, prototypes, or tests.
- Share feedback, issues, or ideas with our support team.
Thank you for exploring this early release and helping us shape these tools to best meet your needs.
Base URL and authentication
All Permissions API endpoints on this page use the following base path:
Replace ACCOUNT_ID with your actual account ID.
Find your account ID and credentials in the Account API Keys page of the Console Settings.
Retrieve roles and system policies
Use these endpoints to review available roles and system policies in your account.
Role details
Use these endpoints to list and inspect both system and custom roles, and to review which system policies each role includes. This is useful when planning which roles you want to assign and figuring out whether you need to create additional custom roles.
Endpoint | Use Case |
---|---|
GET /roles |
List all roles. You can filter by management_type=system or management_type=custom . |
GET /roles/{role_id} |
View the policies included in a specific role |
-
GET /roles
sample response: Retrieve a list of roles. You'll need the role'sid
to inspect details or assign the role to a principal.
Field definitions:
Field | Description |
---|---|
id |
The role's unique identifier. Use this when assigning the role programmatically. System roles use the cld::role:: prefix. |
name |
Display name for the role, as shown in the Console. |
description |
Summary of the permission the role grants. |
management_type |
Predefined roles are "system" and roles that you create are "custom" . |
permission_type |
Indicates the level at which the role applies, either "global" or "content" . |
scope_type |
Specifies the scope of the role. Global roles can be "account" or "prodenv" (product environment). Content roles are always "prodenv" . |
created_at , updated_at
|
Timestamps indicating when the role was created and last updated (Unix epoch format). |
-
GET /role
sample response: Retrieves all policies included in a specific role, providing a more detailed view of what that role can do.
For a list of all system roles, see System role reference.
System policy details
You can retrieve a comprehensive list of system policies using GET /policies/system
.
The policy object returned by GET /policies/system
follows the same structure as the policies listed in the policies array returned by GET /roles/{role_id}
. This shared structure makes it easier to reference system policies when creating or reviewing custom roles.
Each policy includes the following fields:
Field | Description |
---|---|
id |
The unique system_policy_id used when referencing this policy in roles. |
name |
The display name of the policy, shown in the Console. |
description |
A summary of what the policy allows, including relevant UI and API capabilities. |
scope_type |
Defines the scope at which the policy applies. Typically "prodenv" for product environments. |
permission_type |
Indicates whether the policy applies globally or in a more granular context ("global" or "content" ). |
policy_statement |
The underlying Cedar policy expression that defines the permission logic. For more information, see Understanding the policy_statement. |
policy_parameters |
Relevant only if the permission_type is content . Specifies whether the policy applies to a folder_id or a collection_id . |
created_at , updated_at
|
Unix timestamps indicating when the policy was created and last updated. |
For a list of all system policies, see System policy reference.
Understanding the policy_statement
Each system policy includes a policy_statement
field, which defines the actual access rule in Cedar, an expressive, logic-based language designed for fine-grained authorization. This statement determines what action the policy allows, and on which resources, and under what conditions.
Structure and purpose
The policy_statement
defines the core logic of a policy. It contains one or more permit
rules, each made up of the following components:
principal: The actor (such as a user, group, or API key) that receives the permission.
action: The operation the policy allows (e.g.,
read
,update_settings
,delete
).resource: The object the action targets, typically a content instance or feature (e.g.,
Cloudinary::Asset
,Cloudinary::Folder
,Cloudinary::Feature::"cld::global::ml::access"
).when clause (relevant for folder and collection roles only): A condition that determines when the permission applies (e.g., the asset exists within a certain folder).
You define both the principal and the folder or collection ID (for the when
clauses) when you assign the role. The assignment implicitly specifies the principal, and you pass the folder or collection through the policy_parameters
field.
Example
Here's a policy_statement
from a policy that allows viewing assets within a specific folder and its subfolders:
This statement means: The principal can read folders or assets, but only if they exist within the specified folder (
<folder_id>
).-
Where it appears:
- When calling
GET /policies/system
, each returned system policy includes apolicy_statement
. - When calling
GET /roles/{role_id}
, each policy listed under the role also includes itspolicy_statement
.
- When calling
This consistency allows you to clearly see and reason about the exact behavior of each policy, whether you're applying it directly or as part of a role.
Manage custom roles
Use these endpoints to manage custom roles for your account or product environments.
Create a custom role
Use POST /roles/custom to define a role and include the system policies it should grant.
You must specify:
-
permission_type
:global
orcontent
-
scope_type
:account
orprodenv
- One or more
system_policy_ids
- (Optional)
id
,name
, anddescription
Global roles apply to all content or account-level features. Content roles apply to specific folders or collections and require policy_parameters
when assigning.
Example 1: Create a global role to manage uploads
Example 2: Create a content role for folder access
Example 3: Create an account-level role for admin tasks
scope_type
is prodenv, you must specify the product environments when assigning the role. You can assign to "all" environments or a specific list of product environment IDs.Update or delete a custom role
-
Update a role: PUT /roles/custom/{role_key}
You can update the role’s name, description, or system policies.
-
Delete a role: DELETE /roles/custom/{role_key}
You can only delete roles that currently assigned.
Considerations for planning roles effectively
Assignment considerations
You can assign roles to groups, users, product environment API keys, and account API keys.
All role types can be assigned to any of these principals. However, some assignments may have no practical effect, depending on scope or usage context:
-
Scope matters: Assigning an account-level role to a product environment API key has no effect.
For example, granting a product environment API key permission to provision users via the Provisioning API won’t work. Those permissions are only relevant at the account level.
-
UI-based permissions: Roles that grant access to UI areas, such as viewing dashboards or reports, don’t apply to API keys, since only users (not API keys) can interact with the Console.
Exception: If you’re using an API key to authenticate an integration that embeds the Media Library Widget, you must assign a role that grants access to the Media Library. For more information, see Integrations.
See the full list of system permission policies for details on which permissions are available by scope and applicable to each entity type.
Integrations
When using Cloudinary integrations, you authenticate them with product environment API keys. These API keys must receive the necessary permissions explicitly, via roles or custom policies.
When setting roles and permissions for API keys used to access integrations:
Avoid giving broad roles like Master Admin to an integration’s API key. It opens more access than what the integration likely needs.
Instead, understand what the integration needs to do. Then assign an appropriate role.
-
For integrations that use the Media Library Widget, the API key needs specific permissions to access content. Consider one of the following options:
-
Global roles
-
System roles: Use a role like Media Library User (
cld::role::prodenv::ml_user
) or Media Library Admin (cld::role::prodenv::ml_admin
), if it matches the required access level. -
Custom roles: Assign a custom global role that includes the Access the Media Library permission (
cld::policy::global::ml::access
) as well as global folder permissions (e.g., view, upload, delete).
-
System roles: Use a role like Media Library User (
-
Content roles
- Assign system or custom folder or collection roles for targeted access to specific instances.NoteWhen assigning content roles, you must also assign a global role that grants the Access the Media Library permission (
cld::policy::global::ml::access
).
- Assign system or custom folder or collection roles for targeted access to specific instances.
-
Global roles
Assigning the right scope and level of access helps integrations function properly without compromising security or best practices.
Actions that require multiple permissions
Some tasks require multiple permissions to enable. If a user doesn't have all the permissions listed for that action, they won't be able to perform it. Make sure the roles you create contain all the listed permissions to perform these actions:
Action | Required System Policies |
---|---|
Use Moderation tab to moderate assets |
cld::policy::global::moderation_queue::access (Access the Moderation page) For UI access:
|
Add assets to (non-dynamic) collections |
cld::policy::global::collections:update (Manage all (non-dynamic) collections) OR cld::policy::content::collection::add_assets (Add assets)
For UI access (collections are only available in the UI): |
Remove assets from (non-dynamic) collections |
cld::policy::global::collections::manage (Manage all (non-dynamic) collections) OR cld::policy::content::collection::remove_assets (Remove assets)
For UI access (collections are only available in the UI): |
Relate one asset to another |
cld::policy::global::asset_relation::create (Relate assets) For UI access : |
Move assets between folders |
cld::policy::content::folder::move_assets (Move assets out of the source folder) For UI access: |
Start creative approval proofs |
cld::policy::global::creative_approval_proofs::create (Start creative approval proofs) For UI access (proofs are only available in the UI):
|
Manage public links for assets and collections |
cld::policy::global::public_links::manage (Manage public links) For UI access: |
Move folders |
cld::policy::content::folder::move (Move folder)
For UI access:
|
- Role-based permissions: An overview of Cloudinary's role-based permissions solution
- Role management in the Console: UI-based role management
- Assign roles: How to assign roles via API
- System role and policy reference: A list of all system roles and system permission polices provided by Cloudinary
- Permissions API reference: Full list of endpoints and schemas
- Define custom policies: Create and apply policies outside of roles