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

# Define custom policies

This guide describes the Roles and Permissions system. For details on all roles available in the legacy system, see [Role-based permissions](user_provisioning#role_based_permissions).

> **INFO**:
>
> :title=Which permissions system do you have?
> Use the rollout schedule to find out:

> * **Enterprise accounts**: Broad Enterprise migration hasn't started yet. If your team hasn't already been moved with Cloudinary's help, you're still on the legacy system.

> * **Existing free and paid accounts**: Migration starts May 12, 2026.

> * **New free accounts (created since February 2026)**: You may already have the new system.
> You can confirm which permissions system you have. Open **Console Settings** and look for **Role Management**. If it's listed, your account is on Roles and Permissions. If it isn't listed, you're still on the legacy permissions model. 
> ![Global role management](https://cloudinary-res.cloudinary.com/image/upload/f_auto/q_auto/bo_1px_solid_grey/roles_interface.png "thumb: w_800,dpr_2, width:800, with_code:false, with_url:false, popup:true")
> The Roles and Permissions system provides more granular, flexible access control than the legacy system. 

> * For a quick comparison, see [Roles and Permissions vs. legacy](dam_admin_users_groups#roles_and_permissions_vs_legacy). 

> * If your account is being migrated, see [Migrating to Roles and Permissions](permissions_migration) to understand what changes.

## Overview

Cloudinary custom policies let you define fine-grained API-level permissions using Cedar-based policy statements. These policies allow precise control over what API keys can do, including folder-level access, asset operations, metadata updates, upload configurations, collections, user and group management, video players, streaming profiles, and more.

Use custom policies to grant secure, automated access to developers building AI workflows, integrating with CI/CD pipelines, or working in specialized product environments. Cloudinary provides a comprehensive Cedar schema and a Permissions API to help you enforce policy as code at scale.
> **NOTE**: :title=For Free plan customers:

The Permissions API isn't available on the Free plan. You can [manage roles and permissions](dam_admin_permissions) via the [Console](https://console.cloudinary.com/app/settings/role-management) only and assign folder roles to API keys and other principals programmatically via the [Admin API](permissions_assign_roles_api#assign_folder_roles_via_the_admin_api).

This guide contains the following sections: 

* [Custom policies overview](#custom_policies_overview): Explains how to create and manage API key permissions using custom policies.
* [Policy statement overview](#policy_statement_overview): Describes the components of a policy statement and includes the Cloudinary-defined [Cedar schema](#cedar_schema), which details the valid resources, actions, and principals you can use in your policy statements.
* [Notes and considerations](#notes_and_considerations): Covers important details and considerations when implementing custom policies.
* [Use cases and examples](#use_cases_and_examples): Presents various scenarios and examples to demonstrate practical applications of custom policies and how they can be effectively utilized. It includes sample [Admin](admin_api) and [Upload](image_upload_api_reference) API calls and responses to illustrate the impact of custom policies.

## Custom policies

By default, all actions on all resources are forbidden for all principals. Consider which developers within your organization have common permission needs, and create corresponding API keys from the [API Keys](https://console.cloudinary.com/settings/api-keys) page of the Console Settings. 

After creating your API keys, use the [Create custom policies](permissions_api#tag/custom-policies/GET/policies/custom) endpoint to grant specific actions to each API key and assign them to the appropriate developers. Any actions *not* specified in your policies will remain prohibited.

> **NOTE**: You can create a policy that permits all resources and actions for all API keys and then explicitly prohibit actions for individual keys. However, this method is not recommended.

Custom policies include the following attributes:

* `scope_type`: Specifies the level that the permissions apply to. Currently, the only available option is `prodenv` (product environment). 
* `scope_id`: Specifies the ID of the product environment that you want the permission to apply to. You can find the product IDs for all your product environments on the [Product Environments](https://console.cloudinary.com/settings/product-environments) page of the Console Settings. Make sure you're copying the ID for the correct product environment and that it corresponds with the API keys you're trying to set permissions for.
* `policy_statement`: The Cedar statement that specifies the permissions. You can use any valid combination of actions, principals, and resources as defined in the [Cedar schema](#cedar_schema) to grant permissions for API keys relevant to your organization.

If your custom policy applies to a specific folder or asset, you'll need to specify the folder's external ID within the `policy_statement`. Find the folder's external ID using the [Get root folders](admin_api#get_root_folders) or [Get subfolders](admin_api#get_subfolders) method.

## Policy statement overview

The `policy_statement`, written in Cedar language, is required when creating and updating custom policies using the Permissions API. This statement defines who can or cannot perform specific actions on designated entities.

Here's an example of a `policy_statement` that allows the API key `1234` to `read` all assets in the `Clothing` folder:

```json
permit
    (principal == Cloudinary::APIKey::\"1234\",
    action==Cloudinary::Action::\"read\",
    resource is Cloudinary::Folder 
    ) when {
        resource.ancestor_ids.contains(\"Clothing\")} ;
```

Not specifying a particular principal, action or resource will result in automatically allowing permissions to all instances of the unspecified entity. For example, `permit(principal, action, resource)` allows all actions on all resources for all principals.

```json
    {
        "policy_statement": "permit(principal, action, resource)",
        "enabled": true,
        "scope_type": "prodenv",
        "scope_id": "123789sjklwyufj38nlaz8",
        "name": "Everything is permitted"
    }
```

Here are some examples of common actions with their applicable principals and resource types. For the complete list of all actions, principal types, and resource types, refer to the [Cedar schema](#cedar_schema) below.

> **NOTE**:
>
> `ProvisioningKey` and `AccountAPIKey` in the Cedar schema both refer to the API keys that authenticate the Permissions and Provisioning APIs. You'll see those keys referred to as **Account Management Keys** in the Console UI, and `provisioningKey` is the parameter value in the Permissions API.

`action` | `resourceTypes`| `principalTypes`
--- | --- | ---
read | Folder, Asset, MetadataField, UploadPreset, Collection, User, Group, Role, and [more](#cedar_schema) | APIKey, User, Group, ProvisioningKey/AccountAPIKey
create | Folder, Asset, MetadataField, UploadPreset, Collection, User, Group, Role, and [more](#cedar_schema) | APIKey, User, Group, ProvisioningKey/AccountAPIKey
update | Folder, Asset, MetadataField, UploadPreset, Collection, User, Group, Role, and [more](#cedar_schema) | APIKey, User, Group, ProvisioningKey/AccountAPIKey
delete | Folder, Asset, MetadataField, UploadPreset, Collection, User, Group, Role, and [more](#cedar_schema) | APIKey, User, Group, ProvisioningKey/AccountAPIKey
rename | Asset, Folder | APIKey, User, Group
move | Asset, Folder | APIKey, User, Group
download | Collection, DynamicCollection, Folder, Asset | APIKey, User, Group
moderate | Asset | APIKey, User, Group

Here are some examples of common entity types and the filters (`when` statement in the `policy_statement`) that can be applied to them. For complete entity type definitions including all available attributes, refer to the `entityTypes` section in the [Cedar schema](#cedar_schema) below.

`entityType` | Example `when` Filters
--- | ---
Folder | `resource.ancestor_ids.contains(\"<ancestor_folder_id>\")`, `resource.path == \"<folder_path>\"`
Asset | `resource.ancestor_ids.contains(\"<ancestor_folder_id>\")`, `resource.resource_type == \"<type>\"`, `resource.type == \"<delivery_type>\"`
Collection | `resource.owner == Cloudinary::User::\"<user_id>\"`, `resource.name.contains(\"<collection_name>\")`
UploadPreset | `resource.name.contains(\"<upload_preset_name>\")`
MetadataField | `resource.allow_dynamic_list_values == <true|false>`

### Cedar schema

The Cedar schema is predefined and provided by Cloudinary, detailing the valid parameters within the `policy_statement`. The Cedar schema corresponds to the elements of the `policy_statement`:

Policy Statement | Cedar Schema | Description
--- | --- | ---
`principal` | `principalTypes` | The actor for whom the action is being permitted or forbidden. Valid principals include `APIKey`, `User`, `Group`, and `ProvisioningKey/AccountAPIKey` depending on the action and resource.
`action` | `actions` | The type of operation being permitted or forbidden. Each action in the schema defines which `principalTypes` and `resourceTypes` it applies to.
`resource` | `resourceTypes` / `entityTypes` | The entity on which the action is permitted or forbidden.  - `resourceTypes` are listed within each action's `appliesTo` section and specify which entities the action can be performed on. - `entityTypes` define the structure and available attributes for each entity type, used when defining filters in `when` clauses.

The Cedar schema below includes three main namespaces:

- **Cloudinary**: The primary namespace containing general product environment actions and entities
- **CreativeApproval**: Actions and entities related to proofs and approval workflows (available for Enterprise customers by request for additional cost)
- **MediaFlows**: Actions and entities related to EasyFlow and PowerFlow automation

Here's the Cedar schema:

```json
{
    "schema": {
        "Cloudinary": {
            "actions": {
                "add_asset": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Collection",
                            "TempCollection"
                        ]
                    }
                },
                "bulk_delete_assets": {
                    "appliesTo": {
                        "principalTypes": [
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "ProductEnvironment"
                        ]
                    }
                },
                "challenge": {
                    "appliesTo": {
                        "principalTypes": [
                            "User",
                            "ProvisioningKey",
                            "AccountAPIKey"
                        ],
                        "resourceTypes": [
                            "AccountReview"
                        ]
                    }
                },
                "create": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group",
                            "ProvisioningKey",
                            "AccountAPIKey"
                        ],
                        "resourceTypes": [
                            "Folder",
                            "Asset",
                            "Portal",
                            "Collection",
                            "DynamicCollection",
                            "TempCollection",
                            "APIKey",
                            "ProvisioningKey",
                            "AccountAPIKey",
                            "User",
                            "Group",
                            "Role",
                            "AssetRelation",
                            "DerivedAsset",
                            "MetadataRule",
                            "MetadataField",
                            "VideoPlayerConfig",
                            "VideoPlayerProfile",
                            "LiveStream",
                            "UploadMapping",
                            "UploadPreset",
                            "Trigger",
                            "Tag",
                            "Report",
                            "StreamingProfile",
                            "Transformation",
                            "ProductEnvironment",
                            "PublicLink",
                            "SavedSearch"
                        ]
                    }
                },
                "delete": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group",
                            "ProvisioningKey",
                            "AccountAPIKey"
                        ],
                        "resourceTypes": [
                            "Folder",
                            "Asset",
                            "Portal",
                            "Collection",
                            "DynamicCollection",
                            "TempCollection",
                            "APIKey",
                            "ProvisioningKey",
                            "AccountAPIKey",
                            "User",
                            "Group",
                            "Role",
                            "AssetRelation",
                            "DerivedAsset",
                            "MetadataRule",
                            "MetadataField",
                            "VideoPlayerConfig",
                            "VideoPlayerProfile",
                            "LiveStream",
                            "UploadMapping",
                            "UploadPreset",
                            "Trigger",
                            "Tag",
                            "Report",
                            "StreamingProfile",
                            "Transformation",
                            "ProductEnvironment",
                            "Account",
                            "PublicLink",
                            "SavedSearch"
                        ]
                    }
                },
                "download": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Collection",
                            "DynamicCollection",
                            "Folder",
                            "Asset"
                        ]
                    }
                },
                "initiate_backup": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "ProductEnvironment"
                        ]
                    }
                },
                "invite": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Collection",
                            "DynamicCollection",
                            "Folder",
                            "SavedSearch"
                        ]
                    }
                },
                "list": {
                    "appliesTo": {
                        "principalTypes": [
                            "User",
                            "ProvisioningKey",
                            "AccountAPIKey"
                        ],
                        "resourceTypes": [
                            "ProductEnvironment"
                        ]
                    }
                },
                "minimal_read": {
                    "appliesTo": {
                        "principalTypes": [
                            "User",
                            "ProvisioningKey",
                            "AccountAPIKey",
                            "APIKey"
                        ],
                        "resourceTypes": [
                            "User",
                            "Group",
                            "APIKey"
                        ]
                    }
                },
                "moderate": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Asset"
                        ]
                    }
                },
                "move": {
                    "appliesTo": {
                        "context": {
                            "attributes": {
                                "direction": {
                                    "required": false,
                                    "type": "String"
                                }
                            },
                            "type": "Record"
                        },
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Asset",
                            "Folder"
                        ]
                    }
                },
                "read": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group",
                            "ProvisioningKey",
                            "AccountAPIKey"
                        ],
                        "resourceTypes": [
                            "Folder",
                            "Asset",
                            "Portal",
                            "Collection",
                            "DynamicCollection",
                            "TempCollection",
                            "APIKey",
                            "ProvisioningKey",
                            "AccountAPIKey",
                            "Feature",
                            "User",
                            "Group",
                            "Role",
                            "DerivedAsset",
                            "MetadataRule",
                            "MetadataField",
                            "VideoAnalyticsView",
                            "VideoPlayerConfig",
                            "VideoPlayerProfile",
                            "LiveStream",
                            "UploadMapping",
                            "UploadPreset",
                            "Trigger",
                            "Tag",
                            "Report",
                            "StreamingProfile",
                            "Transformation",
                            "ProductEnvironment",
                            "Account",
                            "DamApp",
                            "PublicLink",
                            "SavedSearch",
                            "Person"
                        ]
                    }
                },
                "remove_asset": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Collection",
                            "TempCollection"
                        ]
                    }
                },
                "rename": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Asset",
                            "Folder"
                        ]
                    }
                },
                "restore": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Asset"
                        ]
                    }
                },
                "subscribe": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "DamApp"
                        ]
                    }
                },
                "unsubscribe": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "DamApp"
                        ]
                    }
                },
                "update": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group",
                            "ProvisioningKey",
                            "AccountAPIKey"
                        ],
                        "resourceTypes": [
                            "Folder",
                            "Asset",
                            "Portal",
                            "Collection",
                            "DynamicCollection",
                            "TempCollection",
                            "APIKey",
                            "ProvisioningKey",
                            "AccountAPIKey",
                            "User",
                            "Group",
                            "Role",
                            "DerivedAsset",
                            "MetadataRule",
                            "MetadataField",
                            "VideoPlayerConfig",
                            "VideoPlayerProfile",
                            "LiveStream",
                            "UploadMapping",
                            "UploadPreset",
                            "Trigger",
                            "Tag",
                            "Report",
                            "StreamingProfile",
                            "Transformation",
                            "ProductEnvironment",
                            "Account",
                            "PublicLink",
                            "SavedSearch",
                            "Person"
                        ]
                    }
                },
                "update_access_control": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group"
                        ],
                        "resourceTypes": [
                            "Asset"
                        ]
                    }
                },
                "update_settings": {
                    "appliesTo": {
                        "principalTypes": [
                            "APIKey",
                            "User",
                            "Group",
                            "ProvisioningKey",
                            "AccountAPIKey"
                        ],
                        "resourceTypes": [
                            "ProductEnvironment"
                        ]
                    }
                }
            },
            "entityTypes": {
                "APIKey": {
                    "shape": {
                        "attributes": {
                            "kind": {
                                "required": false,
                                "type": "String"
                            },
                            "root": {
                                "required": false,
                                "type": "Boolean"
                            }
                        },
                        "type": "Record"
                    }
                },
                "Account": {},
                "AccountAPIKey": {
                    "shape": {
                        "attributes": {
                            "root": {
                                "required": false,
                                "type": "Boolean"
                            }
                        },
                        "type": "Record"
                    }
                },
                "AccountReview": {},
                "Asset": {
                    "shape": {
                        "attributes": {
                            "ancestor_ids": {
                                "element": {
                                    "type": "String"
                                },
                                "required": true,
                                "type": "Set"
                            },
                            "collection_ids": {
                                "element": {
                                    "type": "String"
                                },
                                "required": false,
                                "type": "Set"
                            },
                            "has_access_control": {
                                "required": true,
                                "type": "Boolean"
                            },
                            "moderation_status": {
                                "required": false,
                                "type": "String"
                            },
                            "resource_type": {
                                "required": true,
                                "type": "String"
                            },
                            "type": {
                                "required": true,
                                "type": "String"
                            }
                        },
                        "type": "Record"
                    }
                },
                "AssetRelation": {},
                "Collection": {
                    "shape": {
                        "attributes": {
                            "name": {
                                "required": true,
                                "type": "String"
                            },
                            "owner": {
                                "name": "User",
                                "required": true,
                                "type": "Entity"
                            }
                        },
                        "type": "Record"
                    }
                },
                "DamApp": {
                    "shape": {
                        "attributes": {
                            "subscribed": {
                                "required": false,
                                "type": "Boolean"
                            }
                        },
                        "type": "Record"
                    }
                },
                "DerivedAsset": {},
                "DynamicCollection": {
                    "shape": {
                        "attributes": {
                            "name": {
                                "required": true,
                                "type": "String"
                            },
                            "owner": {
                                "name": "User",
                                "required": true,
                                "type": "Entity"
                            }
                        },
                        "type": "Record"
                    }
                },
                "Feature": {},
                "Folder": {
                    "shape": {
                        "attributes": {
                            "ancestor_ids": {
                                "element": {
                                    "type": "String"
                                },
                                "required": true,
                                "type": "Set"
                            },
                            "name": {
                                "required": true,
                                "type": "String"
                            },
                            "path": {
                                "required": true,
                                "type": "String"
                            }
                        },
                        "type": "Record"
                    }
                },
                "Group": {},
                "LiveStream": {},
                "MetadataField": {
                    "shape": {
                        "attributes": {
                            "allow_dynamic_list_values": {
                                "required": false,
                                "type": "Boolean"
                            }
                        },
                        "type": "Record"
                    }
                },
                "MetadataRule": {},
                "Person": {},
                "Portal": {},
                "ProductEnvironment": {},
                "ProvisioningKey": {
                    "shape": {
                        "attributes": {
                            "root": {
                                "required": false,
                                "type": "Boolean"
                            }
                        },
                        "type": "Record"
                    }
                },
                "PublicLink": {
                    "shape": {
                        "attributes": {
                            "subject_ancestor_ids": {
                                "element": {
                                    "type": "String"
                                },
                                "type": "Set"
                            },
                            "subject_collection_ids": {
                                "element": {
                                    "type": "String"
                                },
                                "type": "Set"
                            },
                            "subject_id": {
                                "required": true,
                                "type": "String"
                            },
                            "subject_type": {
                                "required": true,
                                "type": "String"
                            }
                        },
                        "type": "Record"
                    }
                },
                "Report": {
                    "shape": {
                        "attributes": {
                            "type": {
                                "required": true,
                                "type": "String"
                            }
                        },
                        "type": "Record"
                    }
                },
                "Role": {},
                "SavedSearch": {
                    "shape": {
                        "attributes": {
                            "owner": {
                                "name": "User",
                                "required": true,
                                "type": "Entity"
                            }
                        },
                        "type": "Record"
                    }
                },
                "StreamingProfile": {},
                "Tag": {},
                "TempCollection": {
                    "shape": {
                        "attributes": {
                            "name": {
                                "required": true,
                                "type": "String"
                            },
                            "owner": {
                                "name": "User",
                                "required": true,
                                "type": "Entity"
                            }
                        },
                        "type": "Record"
                    }
                },
                "Transformation": {
                    "shape": {
                        "attributes": {
                            "allowed_for_strict": {
                                "required": true,
                                "type": "Boolean"
                            },
                            "name": {
                                "required": false,
                                "type": "String"
                            },
                            "named": {
                                "required": true,
                                "type": "Boolean"
                            },
                            "transformation": {
                                "required": true,
                                "type": "String"
                            }
                        },
                        "type": "Record"
                    }
                },
                "Trigger": {
                    "shape": {
                        "attributes": {
                            "id": {
                                "required": true,
                                "type": "String"
                            },
                            "uri": {
                                "required": true,
                                "type": "String"
                            },
                            "uri_type": {
                                "required": true,
                                "type": "String"
                            }
                        },
                        "type": "Record"
                    }
                },
                "UploadMapping": {
                    "shape": {
                        "attributes": {
                            "folder_name": {
                                "required": true,
                                "type": "String"
                            }
                        },
                        "type": "Record"
                    }
                },
                "UploadPreset": {
                    "shape": {
                        "attributes": {
                            "name": {
                                "required": true,
                                "type": "String"
                            }
                        },
                        "type": "Record"
                    }
                },
                "User": {
                    "shape": {
                        "attributes": {
                            "cld_support": {
                                "required": false,
                                "type": "Boolean"
                            },
                            "root": {
                                "required": false,
                                "type": "Boolean"
                            }
                        },
                        "type": "Record"
                    }
                },
                "VideoAnalyticsView": {},
                "VideoPlayerConfig": {},
                "VideoPlayerProfile": {}
            }
        },
        "CreativeApproval": {
            "actions": {
                "create": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User"
                        ],
                        "resourceTypes": [
                            "Proofs",
                            "ApprovalFlow"
                        ]
                    }
                },
                "delete": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User"
                        ],
                        "resourceTypes": [
                            "Proofs",
                            "ApprovalFlow"
                        ]
                    }
                },
                "list": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User"
                        ],
                        "resourceTypes": [
                            "Proofs",
                            "ApprovalFlow",
                            "Reviewer"
                        ]
                    }
                },
                "read": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User"
                        ],
                        "resourceTypes": [
                            "Proofs",
                            "ApprovalFlow",
                            "Reviewer"
                        ]
                    }
                },
                "update": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User"
                        ],
                        "resourceTypes": [
                            "Proofs",
                            "ApprovalFlow"
                        ]
                    }
                }
            },
            "entityTypes": {
                "ApprovalFlow": {},
                "Proofs": {},
                "Reviewer": {}
            }
        },
        "MediaFlows": {
            "actions": {
                "create": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User",
                            "Cloudinary::Group"
                        ],
                        "resourceTypes": [
                            "EasyFlow",
                            "PowerFlow"
                        ]
                    }
                },
                "delete": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User",
                            "Cloudinary::Group"
                        ],
                        "resourceTypes": [
                            "EasyFlow",
                            "PowerFlow"
                        ]
                    }
                },
                "read": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User",
                            "Cloudinary::Group"
                        ],
                        "resourceTypes": [
                            "EasyFlow",
                            "PowerFlow",
                            "LogEntry",
                            "Plan",
                            "Usage"
                        ]
                    }
                },
                "read_details": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User",
                            "Cloudinary::Group"
                        ],
                        "resourceTypes": [
                            "LogEntry"
                        ]
                    }
                },
                "update": {
                    "appliesTo": {
                        "principalTypes": [
                            "Cloudinary::APIKey",
                            "Cloudinary::User",
                            "Cloudinary::Group"
                        ],
                        "resourceTypes": [
                            "EasyFlow",
                            "PowerFlow",
                            "Plan"
                        ]
                    }
                }
            },
            "entityTypes": {
                "EasyFlow": {},
                "LogEntry": {},
                "Plan": {},
                "PowerFlow": {},
                "Usage": {}
            }
        }
    }
}
```

### Understanding the Cedar schema

The Cedar schema above provides the complete specification for all valid policy statements. Here's how to use it:

**Finding valid action combinations:**

1. Locate the action you want to use (e.g., `read`, `create`, `update`) in the `actions` section of the relevant namespace
2. Check the `appliesTo` object to see which `principalTypes` (who can perform the action) and `resourceTypes` (what the action can be performed on) are valid for that action

**Using entity attributes in `when` clauses:**

1. Find the entity type you want to filter in the `entityTypes` section (e.g., `Folder`, `Asset`, `Collection`)
2. Review the `attributes` listed under `shape` to see what properties are available for filtering
3. Use these attributes in your `when` clauses to create conditional policies (e.g., `resource.ancestor_ids.contains("folder_id")`)

**Example:** To allow an API key to read assets, look at the `read` action in the `Cloudinary` namespace. You'll see that `APIKey` is a valid `principalType` and `Asset` is a valid `resourceType`. Then check the `Asset` entity type to see available attributes like `ancestor_ids`, `resource_type`, `collection_ids`, etc. that you can use for filtering.

## Notes and considerations

Review the following sections for key information on managing your custom policies.

### Permit and forbid policy statements

A Cedar policy statement allows you to either permit or forbid a certain action. Forbid statements always take precedence over permit statements. For example, if an action on a particular folder is forbidden for a principal, you can't permit that action on an asset or subfolder within that folder for the same principal.

It's important to review your custom policies to verify the permissions granted to each API key and ensure there are no policy conflicts. Use the [Get custom policies](permissions_api#tag/custom-policies/GET/policies/custom) endpoint to retrieve all `enabled` policies for a specific `scope_id`.

### Permissions API scope and limitations

The Permissions API is currently enabled for specific product environments only. You can't create policies for product environments where the API isn't enabled. 

You can set permissions either programmatically via the Permissions API, or through the [Role Management](https://console.cloudinary.com/settings/role-management) page of the Console Settings. Many permission configurations are fully supported with the roles and permissions available through the Console. We recommend using the Console options wherever your needs are supported, as creating custom policies programmatically can have unexpected results. 

> **INFO**: Keep in mind that users assigned the Master admin, Admin or Technical admin user roles have access to all API keys. For more information, see [Role-based permissions](user_provisioning#role_based_permissions).

### Critical default policy

Cloudinary provides the `permission prodenv allow DAM` custom policy to allow full use of the Console. Ensure this policy isn't deleted, as its removal will block Console access for all users.

### API permissions setup method

By default, all API actions on all resources are forbidden for all principals. To set up API permissions, explicitly grant specific actions to individual API keys. Any actions not specified in your policies will remain prohibited. Consider which developers within your organization have common permission needs, and create corresponding API keys from the [API Keys](https://console.cloudinary.com/settings/api-keys) page of the Console Settings. 

For more details about administering permissions, see [Permissions API requests](#permissions_api_requests).

### Behavior of forbidden actions in API calls

Behavior for informing the user that an attempted action was forbidden may vary in different API calls.Some calls will return a 403 error, while others—especially those involving a mix of permitted and forbidden actions—will return a 200 status with detailed responses. Here are some examples:

#### Example 1: Update metadata 

When attempting to add metadata to several assets using the [metadata](image_upload_api_reference#metadata) endpoint of the Upload API, the response may return a `200` status and include an object specifying which assets were successfully updated and which were `unauthorized`:

```json
{
    "public_ids": [
        "sample1",
        "sample2"
    ],
    "unauthorized": [
        "sample3"
    ]
}
```

#### Example 2: Get subfolders

For the [Get subfolders](admin_api#get_subfolders) endpoint, if the request is forbidden, the response will indicate this:

```json
{
    "error": {
        "message": "customer <api_key> is unauthorized to read one or more of the requested folders"
    }
}
```

#### Example 4: Get root folders

For the [Get root folders](admin_api#get_root_folders) endpoint, forbidden folders won't appear in the response, while the total_count will reflect the total number of folders in the product environment:

```json
{
    "folders": [],
    "next_cursor": null,
    "total_count": 2
}
```

## Use cases and examples

Below are example configurations for different scenarios and use cases:

### Setup for product detail page (PDP) developers

Suppose the developers working on your e-commerce website's product detail pages (PDP) need full access to product-related assets only. Use the [Create custom policy](permissions_api#tag/custom-policies/POST/policies/custom) endpoint to set up the following permissions for the API key you'll give those developers:

* Forbid access to non-product assets in the dedicated **Non-product** folder. (Access is prohibited by default, so no additional permissions need to be set.)

* Allow full management of the **Product** folder, including permission to retrieve information about it, `create` (upload assets to it), `update`, and `delete` it, as well as `move` assets and subfolders from the **Product** folder.

* Allow `read` access to structured metadata, meaning, the ability to retrieve information about all structured metadata fields and their attributes.

#### Allow full management access over the Product folder

```curl
\
  -H "Content-Type: application/json" \
  -d '{ 
    "policy_statement": "permit(principal == Cloudinary::APIKey::\"898989784927662\", action, resource is Cloudinary::Folder) when {resource.ancestor_ids.contains(\"c88e51b3480116696uubb39ce27a0dd703\")};",
    "description": "Allow API key `898989784927662` to manage the `Product` folder.",
    "scope_type": "prodenv",
    "scope_id": "123789sjklwyufj38nlaz8",
    "name": "898989784927662: Manage Product folder",
    "enabled": true
    }' \
  -X POST \
  https://<PROVISIONING_KEY>:<PROVISIONING_SECRET>@api.cloudinary.com/v2/accounts/<ACCOUNT_ID>/permissions/custom_policies
```

> **NOTES**:
>
> * For moving an asset to a different folder to succeed, the API key must also have `update` access to the destination folder.

> * When no `action` is specified, all actions are included.

**Sample response:**

```json
{
    "data": {
        "id": "d4acc018-bce9-40db-b3fa-48309758de8f",
        "policy_statement": "permit(principal == Cloudinary::APIKey::\"898989784927662\", action, resource is Cloudinary::Folder) when {resource.ancestor_ids.contains(\"c88e51b3480116696uubb39ce27a0dd703\")}",
        "scope_type": "prodenv",
        "scope_id": "123789sjklwyufj38nlaz8",
        "name": "898989784927662: Manage Product folder",
        "enabled": true,
        "created_at": 1722766987,
        "updated_at": 1722766987
    }
}
```

#### Allow `read` access to structured metadata

```curl
\
  -H "Content-Type: application/json" \
  -d '{ 
    "policy_statement": "permit(principal == Cloudinary::APIKey::\"898989784927662\", action== Cloudinary::Action::\"read\",resource is Cloudinary::MetadataField);",
    "description": "Allow API key `898989784927662` to read structured metadata fields",
    "scope_type": "prodenv",
    "scope_id": "123789sjklwyufj38nlaz8",
    "name": "898989784927662: Read metadata",
    "enabled": true
    }' \
  -X POST \
  https://<PROVISIONING_KEY>:<PROVISIONING_SECRET>@api.cloudinary.com/v2/accounts/<ACCOUNT_ID>/permissions/custom_policies
```

**Sample response:**

```json
{
    "data": {
        "id": "7b365752-2591-45cc-863b-e694dea0c390",
        "policy_statement": "permit(principal == Cloudinary::APIKey::\"893515392262445\", action== Cloudinary::Action::\"read\",resource is Cloudinary::MetadataField);",
        "scope_type": "prodenv",
        "scope_id": "123789sjklwyufj38nlaz8",
        "name": "898989784927662: Read metadata",
        "enabled": true,
        "created_at": 1722767347,
        "updated_at": 1722767347
    }
}
```

#### Sample responses for permitted and forbidden API calls 

Get root folders - read access to some folders

A response for the [Get root folders](admin_api#get_root_folders) endpoint when read access is forbidden to the **Non-Product** folder and permitted to the **Product** folder:

```json
{
    "folders": [
        {
            "name": "Product",
            "path": "Product",
            "external_id": "c88e51b3480116696uubb39ce27a0dd703"
        }
    ],
    "next_cursor": null,
    "total_count": 2
}
```

> **INFO**: The response only includes information about folders the API key is permitted to `read`. The `total_count` field indicates the total number of folders, including those the API key does not have permission to access.

Get subfolders - permitted action

A response for the [Get subfolders](admin_api#get_subfolders) endpoint for the **Product** folder when read access is permitted:

```json
{
    "folders": [
        {
            "name": "Accessories",
            "path": "Product/Accessories",
            "external_id": "c88e51edad8124e31673014b6abb14d9b7"
        },
        {
            "name": "Clothing",
            "path": "Product/Clothing",
            "external_id": "c88e51e2f10153b06cfb84ef0614737a41"
        }
    ],
    "next_cursor": null,
    "total_count": 2
}
```

> **INFO**: The response returns information only about the folders that the API key has permission to `read`. `total_count` indicates the total number of folders, including those that the API key doesn't have permission to `read`.

Get subfolders - forbidden action

A response for the [Get subfolders](admin_api#get_subfolders) endpoint for the **Non-product** folder when read access is forbidden:

```json
{
    "error": {
        "message": "customer 5f37647b75c5a6aecc821f3041ebb6 is unauthorized to read one or more of the requested folders"
    }
}
```

Get metadata fields - read access permitted

A response for the [Get metadata fields](admin_api#get_metadata_fields) endpoint when read access is permitted:

```json
{
    "metadata_fields": [
        {
            "type": "set",
            "external_id": "location",
            "label": "Location",
            "mandatory": false,
            "default_value": null,
            "validation": null,
            "default_disabled": false,
            "restrictions": {
                "readonly_ui": false
            },
            "datasource": {
                "values": [
                    {
                        "external_id": "us",
                        "value": "US",
                        "state": "active"
                    },
                    {
                        "external_id": "europe",
                        "value": "Europe",
                        "state": "active"
                    },
                    {
                        "external_id": "asia",
                        "value": "Asia",
                        "state": "active"
                    },
                    {
                        "external_id": "middle_east",
                        "value": "Middle East",
                        "state": "active"
                    }
                ]
            },
            "dynamic_list_values": "enabled"
        },
        {
            "type": "enum",
            "external_id": "active_status",
            "label": "Active Status",
            "mandatory": true,
            "default_value": "inactive",
            "validation": null,
            "default_disabled": false,
            "restrictions": {
                "readonly_ui": false
            },
            "datasource": {
                "values": [
                    {
                        "external_id": "active",
                        "value": "Active",
                        "state": "active"
                    },
                    {
                        "external_id": "inactive",
                        "value": "Inactive",
                        "state": "active"
                    }
                ]
            },
            "dynamic_list_values": "disabled"
        },
        {
            "type": "string",
            "external_id": "barcode",
            "label": "Barcode",
            "mandatory": true,
            "default_value": null,
            "validation": null,
            "default_disabled": false,
            "restrictions": {
                "readonly_ui": false
            }
        },
        {
            "type": "string",
            "external_id": "product_id",
            "label": "Product ID",
            "mandatory": false,
            "default_value": null,
            "validation": null,
            "default_disabled": false,
            "restrictions": {
                "readonly_ui": false
            }
        }
    ]
}
```

Create metadata field - read access only

A response for the [Create a metadata field](admin_api#create_a_metadata_field) endpoint when *only* read is permitted:

```json
{
    "error": {
        "message": "customer 5f37647b75c5a6aecc821f3041ebb6 is unauthorized to create the metadata field"
    }
}
```

### Setup for configuration administrators

Suppose some developers are in charge of system configuration, such as metadata and upload presets. Use the [Create custom policy](permissions_api#tag/custom-policies/POST/policies/custom) endpoint to set up the following permissions for the API key you'll give those developers:

* Forbid access to all assets and folders. (Access is prohibited by default, so no additional permissions need to be set.)

* Allow full management of structured metadata fields, including permission to `read` (retrieve information about them), `create`, `update`, and `delete` them.

#### Allow full management of structured metadata fields

```curl
\
  -H "Content-Type: application/json" \
  -d '{ 
    "policy_statement" : "permit(principal == Cloudinary::APIKey::\"721588181775364\", action, resource is Cloudinary::MetadataField);",
    "description": "Allow API key `721588181775364` to manage structured metadata fields", 
    "scope_type": "prodenv",
    "scope_id": "123789sjklwyufj38nlaz8",
    "name": "721588181775364: Manage metadata",
    "enabled": true
    }' \
  -X POST \
  https://<PROVISIONING_KEY>:<PROVISIONING_SECRET>@api.cloudinary.com/v2/accounts/<ACCOUNT_ID>/permissions/custom_policies

```

> **NOTE**: When no `action` is specified, all actions are included.

**Sample response:**

```json
{
    "data": {
        "id": "14a50f71-d9c3-41ec-a881-6fbece29a0c7",
        "policy_statement": "permit(principal == Cloudinary::APIKey::\"721588181775364\", action, resource is Cloudinary::MetadataField);",
        "scope_type": "prodenv",
        "scope_id": "123789sjklwyufj38nlaz8",
        "name": "721588181775364: Manage metadata",
        "enabled": true,
        "created_at": 1722772408,
        "updated_at": 1722772408
    }
}
```

#### Sample responses for permitted and forbidden API calls 

Get root folders - read access forbidden

A response for the [Get root folders](admin_api#get_root_folders) endpoint when read access to all folders is forbidden:

```json
{
    "folders": [],
    "next_cursor": null,
    "total_count": 2
}
```

> **INFO**: The response contains no `folders`, indicating that the API key doesn't have `read` permissions for any root folders. However, `total_count` still shows the total number of folders.

Create a metadata field - permitted action

A response for the [Create a metadata field](admin_api#create_a_metadata_field) endpoint when create access to metadata fields is permitted:

```json
{
    "type": "set",
    "external_id": "my_metadata",
    "label": "My Metadata",
    "mandatory": true,
    "default_value": [
        "value1",
        "value2"
    ],
    "validation": null,
    "default_disabled": false,
    "restrictions": {
        "readonly_ui": false
    },
    "datasource": {
        "values": [
            {
                "external_id": "value1",
                "value": "value1",
                "state": "active"
            },
            {
                "external_id": "value2",
                "value": "value2",
                "state": "active"
            }
        ]
    },
    "dynamic_list_values": "disabled"
}
```

Get a metadata field by external ID - permitted action

A response for the [Get a metadata field by external ID](admin_api#get_a_metadata_field_by_external_id) endpoint when read access to all metadata fields is permitted:

```json
{
    "type": "set",
    "external_id": "my_metadata",
    "label": "My Metadata",
    "mandatory": true,
    "default_value": [
        "value1",
        "value2"
    ],
    "validation": null,
    "default_disabled": false,
    "restrictions": {
        "readonly_ui": false
    },
    "datasource": {
        "values": [
            {
                "external_id": "value1",
                "value": "value1",
                "state": "active"
            },
            {
                "external_id": "value2",
                "value": "value2",
                "state": "active"
            }
        ]
    },
    "dynamic_list_values": "disabled"
}
```

> **See also**:
>
> * [Role-based permissions](permissions_overview): An overview of Cloudinary's role-based permissions solution

> * [Role management in the Console](permissions_manage_roles_ui): UI-based role management

> * [Manage roles](permissions_manage_roles_api): How to manage roles via API

> * [Assign roles](permissions_assign_roles_api): How to assign roles via API

> * [System role and policy reference](permissions_system_roles_policies): A list of all system roles and system permission polices provided by Cloudinary

> * [Permissions API reference](permissions_api): Full list of endpoints and schemas