André Lynum
08/03/2026, 10:18 AMMarvin
08/03/2026, 10:18 AMMarvin
08/03/2026, 10:20 AMprefect CLI command like prefect service-account create or prefect role create
- The Cloud CLI surface is focused on login/workspace operations, not identity/RBAC management
So if your question is “can I do this directly with the Prefect CLI?” the answer is generally no.
Possible workaround:
- You may be able to use direct Prefect Cloud API calls instead of a dedicated CLI command, but that would depend on the relevant Cloud API endpoints being available/documented for your account. The API docs are typically here: Prefect Cloud API docs
If you want, I can help with either of these:
1. UI steps to create a service account and assign roles
2. exploring whether the Cloud API exposes endpoints you can script against for this in your environmentAndré Lynum
08/03/2026, 10:22 AMMarvin
08/03/2026, 10:23 AMMarvin
08/03/2026, 10:25 AMprefect.client.cloud.CloudClient does not expose methods to create/manage service accounts
- it also does not expose methods to create/manage roles
- the main orchestration client (PrefectClient) is for flows, deployments, work pools, runs, etc. — not Cloud IAM/RBAC
So the practical answer is:
- Service accounts: create them in the Cloud UI
Service accounts docs
- Roles: manage them in the Cloud UI
Manage roles docs
Cloud app:
- app.prefect.cloud
There is one caveat:
- You might be able to make direct REST calls against Prefect Cloud from Python if there are internal/public endpoints for those resources
- but that is not exposed as a documented Python SDK workflow for service account/role creation
So if you need an officially supported approach today, it’s UI-only for creating those objects.
If helpful, I can also show you:
1. how to use a service account API key from Python once it’s created, or
2. how to probe the Cloud REST API safely to see whether your org exposes endpoints for this automation.André Lynum
08/03/2026, 10:28 AMMarvin
08/03/2026, 10:29 AMMarvin
08/03/2026, 10:31 AMbash
curl -H "Authorization: Bearer $PREFECT_API_KEY" \
<https://app.prefect.cloud/api/docs>
More realistically, open the docs in the browser and search for:
- service account
- role
- member
- workspace
- account
Important caveat:
- If the endpoints are not documented in the Cloud API docs, I would assume they are internal/unsupported and subject to change.
If you want, I can help you:
1. figure out the correct Cloud base URL + auth pattern for REST calls, or
2. draft a small Python/curl script to query the documented Cloud endpoints you find in /api/docs.André Lynum
08/03/2026, 10:43 AMMarvin
08/03/2026, 10:43 AMMarvin
08/03/2026, 10:43 AMAndré Lynum
08/03/2026, 10:45 AMMarvin
08/03/2026, 10:45 AMMarvin
08/03/2026, 10:47 AMPREFECT_API_KEY
- PREFECT_API_URL
For a logged-in CLI user, these are usually stored in the active Prefect profile, commonly in:
- ~/.prefect/profiles.toml
Useful ways to inspect them:
bash
prefect config view --show-secrets --show-sources
That will show the effective config, including where values came from.
You can also inspect the active profile directly:
bash
prefect profile inspect
Or read the raw profile file:
bash
cat ~/.prefect/profiles.toml
What you’re looking for is something like:
toml
PREFECT_API_KEY = "pnu_..."
PREFECT_API_URL = "<https://api.prefect.cloud/api/accounts/<account-id>/workspaces/<workspace-id>>"
Then you can use those directly in REST calls, for example:
bash
curl -H "Authorization: Bearer $PREFECT_API_KEY" \
"$PREFECT_API_URL/flows/filter"
A couple caveats:
- environment variables can override profile values
- .env, prefect.toml, or other config sources may also contribute values
- prefect cloud login usually sets both key and workspace API URL for the active profile
Relevant docs:
- Settings and profiles
- Connect to Prefect Cloud
If you want, I can show you how to convert a logged-in CLI session into a reusable curl or Python requests example.André Lynum
08/03/2026, 11:10 AMMarvin
08/03/2026, 11:10 AMMarvin
08/03/2026, 11:12 AMprod, the scope is the prod workspace
- Their permissions include things like creating/editing deployments, running flows, and managing certain workspace resources
Relevant docs:
- Manage roles
- Service accounts
One subtle point:
- Role is the named bundle
- Permissions are the capabilities inside that bundle
- Scope is the level/resource boundary where that bundle is applied
If you want, I can also break down how this maps specifically for service accounts vs human users in Prefect Cloud.André Lynum
08/03/2026, 11:13 AMMarvin
08/03/2026, 11:13 AMMarvin
08/03/2026, 11:15 AMscopes field is how you set permissions.
So for `POST /api/accounts/{account_id}/workspace_roles/`:
- there is no separate permissions field
- the role’s effective permissions are defined by the values you put in scopes
In other words:
- UI term: permissions
- API field: scopes
That endpoint is using scopes to represent the granular abilities the role grants.
So if you’re creating a custom workspace role, you typically do one of these:
- define a role with an explicit list of scopes
- or inherit from a built-in/base role and add additional scopes if the API supports inheritance fields
Important nuance:
- I could not verify the exact Cloud-only request schema for this endpoint from the open-source repo
- so the authoritative source for the allowed fields and valid scope values is still:
Prefect Cloud API docs
Conceptually though, the mapping is:
- Role = named bundle
- scopes = the bundle contents
- Permissions = what those scopes allow in practice
So if you were expecting a model like:
json
{
"name": "My Role",
"permissions": [...]
}
Prefect appears to instead model it more like:
json
{
"name": "My Role",
"scopes": [...]
}
If you want to confirm exactly what strings are valid, check the schema for that endpoint in the Cloud docs — it may enumerate accepted scope names or reference a schema component.
If you paste the request schema or an example payload from /api/docs, I can help translate it into a working curl or Python example.André Lynum
08/03/2026, 11:27 AMNone, which includes both.\n ",
"required": false
}
],
"schema": {
"properties": {
"limit": {
"type": "integer",
"maximum": 200,
"minimum": 0,
"title": "Limit",
"default": 200
},
"offset": {
"type": "integer",
"minimum": 0,
"title": "Offset",
"default": 0
},
"workspace_roles": {
"anyOf": [
{
"properties": {
"name": {
"anyOf": [
{
"properties": {
"any_": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
],
"title": "Any",
"description": "Only include workspace roles matching these names"
}
},
"additionalProperties": false,
"type": "object",
"title": "WorkspaceRoleFilterName"
},
{
"type": "null"
}
],
"description": "Filter criteria for WorkspaceRole.name"
},
"is_global": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Is Global",
"description": "\n If True, only return global built-in roles. If False,\n only return workspace roles from this account. Defaults to None, which includes both.\n "
}
},
"additionalProperties": false,
"type": "object",
"title": "WorkspaceRoleFilter"
},
{
"type": "null"
}
]
}
},
"type": "object",
"title": "Body_read_workspace_roles_api_accounts__account_id__workspace_roles_filter_post"
}
},
"responses": {
"200": {
"description": "Successful Response",
"type": "arrayobject",
"properties": [
{
"key": "[array items]",
"type": "arrayobject",
"description": "An ORM representation of a WorkspaceRole",
"required": false
},
{
"key": "[array items].id",
"type": "string",
"required": false
},
{
"key": "[array items].created",
"type": "string | null",
"required": false
},
{
"key": "[array items].updated",
"type": "string | null",
"required": false
},
{
"key": "[array items].account_id",
"type": "string | null",
"description": "The account id",
"required": true
},
{
"key": "[array items].name",
"type": "string",
"description": "The workspace role name",
"required": true
},
{
"key": "[array items].description",
"type": "string",
"description": "A short description of the role.",
"required": false
},
{
"key": "[array items].permissions",
"type": "arraystring",
"description": "The workspace role's permissions",
"required": false
},
{
"key": "[array items].scopes",
"type": "arraystring",
"description": "The workspace role's scopes.",
"required": false
},
{
"key": "[array items].inherited_role_id",
"type": "string | null",
"description": "An optional built-in workspace role id from which this workspace role inherits.",
"required": false
}
],
"schema": {
"type": "array",
"title": "Response Read Workspace Roles Api Accounts Account Id Workspace Roles Filter Post",
"items": {
"properties": {
"id": {
"type": "string",
"format": "uuid",
"title": "Id"
},
"created": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"title": "Created"
},
"updated": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"title": "Updated"
},
"account_id": {
"anyOf": [
{
"type": "string",
"format": "uuid"
},
{
"type": "null"
}
],
"title": "Account Id",
"description": "The account id"
},
"name": {
"type": "string",
"title": "Name",
"description": "The workspace role name"
},
"description": {
"type": "string",
"maxLength": 140,
"title": "Description",
"description": "A short description of the role.",
"default": ""
},
"permissions": {
"type": "array",
"title": "Permissions",
"description": "The workspace role's permissions",
"deprecated": true,
"items": {
"type": "string"
}
},
"scopes": {
"type": "array",
"title": "Scopes",
"description": "The workspace role's scopes.",
"items": {
"type": "string"
}
},
"inherited_role_id": {
"anyOf": [
{
"type": "string",
"format": "uuid"
},
{
"type": "null"
}
],
"title": "Inherited Role Id",
"description": "An optional built-in workspace role id from which this workspace role inherits."
}
},
"type": "object",
"required": [
"account_id",
"name"
],
"title": "WorkspaceRole",
"description": "An ORM representation of a WorkspaceRole"
}
}
},Marvin
08/03/2026, 11:27 AMread workspace_role parameters [ { name account_id in path required true type string schema { type string format uuid title Account Id } } ] requestBody { required false type object properties [ { key limit type integer required false } { key offset type integer required false } { key workspace_roles type object | null required false } { key workspace_roles name type object | null description Filter criteria for WorkspaceRole name required false } { key workspace_roles name any_ type array<string> | null description Only include workspace roles matching these names required false } { key workspace_roles is_global type boolean | null description \n If True only return global built-in roles If False \n only return workspace roles from this account Defaults to None which includes both \n required false } ] schema { properties { limit { type integer maximum 200 minimum 0 title Limit default 200 } offset { type integer minimum 0 title Offset default 0 } workspace_roles { anyOf [ { properties { name { anyOf [ { properties { any_ { anyOf [ { type array items { type string } } { type null } ] title Any description Only include workspace roles matching these names } } additionalProperties false type object title WorkspaceRoleFilterName } { type null } ] description Filter criteria for WorkspaceRole name } is_global { anyOf [ { type boolean } { type null } ] title Is Global description \n If True only return global built-in roles If False \n only return workspace roles from this account Defaults to None which includes both \n } } additionalProperties false type object title WorkspaceRoleFilter } { type null } ] } } type object title Body_read_workspace_roles_api_accounts__account_id__workspace_roles_filter_post } } responses { 200 { description Successful Response type array<object> properties [ { key [array items] type array<object> description An ORM representation of a WorkspaceRole required false } { key [array items] id type string required false } { key [array items] created type string | null required false } { key [array items] updated type string | null required false } { key [array items] account_id type string | null description The account id required true } { key [array items] name type string description The workspace role name required true } { key [array items] description type string description A short description of the role required false } { key [array items] permissions type array<string> description The workspace role's permissions required false } { key [array items] scopes type array<string> description The workspace role's scopes required false } { key [array items] inherited_role_id type string | null description An optional built-in workspace role id from which this workspace role inherits required false } ] schema { type array title Response ReadMarvin
08/03/2026, 11:28 AMread workspace_role parameters [ { name account_id in path required true type string schema { type string format uuid title Account Id } } ] requestBody { required false type object properties [ { key limit type integer required false } { key offset type integer required false } { key workspace_roles type object | null required false } { key workspace_roles name type object | null description Filter criteria for WorkspaceRole name required false } { key workspace_roles name any_ type array<string> | null description Only include workspace roles matching these names required false } { key workspace_roles is_global type boolean | null description \n If True only return global built-in roles If False \n only return workspace roles from this account Defaults to None which includes both \n required false } ] schema { properties { limit { type integer maximum 200 minimum 0 title Limit default 200 } offset { type integer minimum 0 title Offset default 0 } workspace_roles { anyOf [ { properties { name { anyOf [ { properties { any_ { anyOf [ { type array items { type string } } { type null } ] title Any description Only include workspace roles matching these names } } additionalProperties false type object title WorkspaceRoleFilterName } { type null } ] description Filter criteria for WorkspaceRole name } is_global { anyOf [ { type boolean } { type null } ] title Is Global description \n If True only return global built-in roles If False \n only return workspace roles from this account Defaults to None which includes both \n } } additionalProperties false type object title WorkspaceRoleFilter } { type null } ] } } type object title Body_read_workspace_roles_api_accounts__account_id__workspace_roles_filter_post } } responses { 200 { description Successful Response type array<object> properties [ { key [array items] type array<object> description An ORM representation of a WorkspaceRole required false } { key [array items] id type string required false } { key [array items] created type string | null required false } { key [array items] updated type string | null required false } { key [array items] account_id type string | null description The account id required true } { key [array items] name type string description The workspace role name required true } { key [array items] description type string description A short description of the role required false } { key [array items] permissions type array<string> description The workspace role's permissions required false } { key [array items] scopes type array<string> description The workspace role's scopes required false } { key [array items] inherited_role_id type string | null description An optional built-in workspace role id from which this workspace role inherits required false } ] schema { type array title Response ReadAndré Lynum
08/03/2026, 11:29 AMread workspace_role parameters [ { name account_id in path required true type string schema { type string format uuid title Account Id } } ] requestBody { required false type object properties [ { key limit type integer required false } { key offset type integer required false } { key workspace_roles type object | null required false } { key workspace_roles name type object | null description Filter criteria for WorkspaceRole name required false } { key workspace_roles name any_ type array<string> | null description Only include workspace roles matching these names required false } { key workspace_roles is_global type boolean | null description \n If True only return global built-in roles If False \n only return workspace roles from this account Defaults to None which includes both \n required false } ] schema { properties { limit { type integer maximum 200 minimum 0 title Limit default 200 } offset { type integer minimum 0 title Offset default 0 } workspace_roles { anyOf [ { properties { name { anyOf [ { properties { any_ { anyOf [ { type array items { type string } } { type null } ] title Any description Only include workspace roles matching these names } } additionalProperties false type object title WorkspaceRoleFilterName } { type null } ] description Filter criteria for WorkspaceRole name } is_global { anyOf [ { type boolean } { type null } ] title Is Global description \n If True only return global built-in roles If False \n only return workspace roles from this account Defaults to None which includes both \n } } additionalProperties false type object title WorkspaceRoleFilter } { type null } ] } } type object title Body_read_workspace_roles_api_accounts__account_id__workspace_roles_filter_post } } responses { 200 { description Successful Response type array<object> properties [ { key [array items] type array<object> description An ORM representation of a WorkspaceRole required false } { key [array items] id type string required false } { key [array items] created type string | null required false } { key [array items] updated type string | null required false } { key [array items] account_id type string | null description The account id required true } { key [array items] name type string description The workspace role name required true } { key [array items] description type string description A short description of the role required false } { key [array items] permissions type array<string> description The workspace role's permissions required false } { key [array items] scopes type array<string> description The workspace role's scopes required false } { key [array items] inherited_role_id type string | null description An optional built-in workspace role id from which this workspace role inherits required false } ] schema { typeMarvin
08/03/2026, 11:29 AMMarvin
08/03/2026, 11:29 AMfilter endpoint with a POST body that filters on workspace_roles.name.any_.
If you want only the role named Viewer, the request body should look like:
json
{
"workspace_roles": {
"name": {
"any_": ["Viewer"]
}
}
}
Example `curl`:
bash
curl -X POST \
"$PREFECT_API_URL/accounts/<account_id>/workspace_roles/filter" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspace_roles": {
"name": {
"any_": ["Viewer"]
}
}
}'
If you are calling the absolute Cloud path exactly as documented:
bash
curl -X POST \
"<https://api.prefect.cloud/api/accounts/<account_id>/workspace_roles/filter>" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspace_roles": {
"name": {
"any_": ["Viewer"]
}
}
}'
A couple notes:
- any_ accepts an array, so even for one role name you pass ["Viewer"]
- if you want only built-in/global roles, add:
json
"is_global": true
- if you want only account-defined custom workspace roles, add:
json
"is_global": false
So for the built-in Viewer role specifically, I’d try:
json
{
"workspace_roles": {
"name": {
"any_": ["Viewer"]
},
"is_global": true
}
}
Example:
bash
curl -X POST \
"<https://api.prefect.cloud/api/accounts/<account_id>/workspace_roles/filter>" \
-H "Authorization: Bearer $PREFECT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspace_roles": {
"name": {
"any_": ["Viewer"]
},
"is_global": true
}
}'
One important thing from the schema you pasted:
- the response includes both permissions and scopes
- so when reading roles, you may see both
- but for creating roles, the API may still expect scopes as input rather than a permissions field
If you want, I can also help build the exact curl using your existing PREFECT_API_URL, because that value usually already includes /accounts/<id>/workspaces/<workspace-id> and may need a small adjustment for account-level endpoints.