diff --git a/fusion_docs/guide/snapshots/gcp.md b/fusion_docs/guide/snapshots/gcp.md
index 320999c90..6d7221c0e 100644
--- a/fusion_docs/guide/snapshots/gcp.md
+++ b/fusion_docs/guide/snapshots/gcp.md
@@ -31,6 +31,17 @@ Fusion Snapshots work with sensible defaults (5 automatic retry attempts). For c
[Incremental snapshots](./index.md#incremental-snapshots) are enabled by default on x86_64 instances and capture only changed memory pages between checkpoints. This is particularly beneficial for Google Batch's shorter reclamation window. Use x86_64 instances to enable incremental snapshots.
+## Machine type guidance
+
+Fusion Snapshots on Google Batch work best when the underlying compute environment uses machine types that provide local SSD support and enough memory bandwidth to complete checkpoints within the preemption window.
+
+- If you don't specify a machine type, Seqera Platform selects a VM from Google Cloud families that support local SSDs.
+- Any machine type you specify for Fusion Snapshots must support local SSDs.
+- For production workloads, start with an `n2-highmem-16-lssd` VM or larger, then validate checkpoint duration with your workload profile.
+- If your workload has larger memory footprints, increase the machine size conservatively and re-test snapshot and restore times before widening usage.
+
+See [Google Cloud Batch compute environment configuration](../../platform-cloud/docs/compute-envs/google-cloud-batch.md#use-fusion-v2) for the underlying Fusion v2 compute recommendations that also apply to Fusion Snapshots on Google Batch.
+
## Resource limits
A single job can request more resources than are available on a single instance. To prevent this, set resource limits using the `process.resourceLimits` directive in your Nextflow configuration. See [Resource limits](./configuration.md#resource-limits) for more information.
diff --git a/platform-api-docs/docs/check-permission.ParamsDetails.json b/platform-api-docs/docs/check-permission.ParamsDetails.json
new file mode 100644
index 000000000..22c89b9c2
--- /dev/null
+++ b/platform-api-docs/docs/check-permission.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"orgId","in":"query","description":"Organization numeric identifier.","schema":{"type":"integer","format":"int64"}},{"name":"workspaceId","in":"query","description":"Workspace numeric identifier.","schema":{"type":"integer","format":"int64"}},{"name":"operationId","in":"query","description":"Operation identifier to check in the selected context.","required":true,"schema":{"type":"string"}}]}
diff --git a/platform-api-docs/docs/check-permission.RequestSchema.json b/platform-api-docs/docs/check-permission.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/check-permission.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/check-permission.StatusCodes.json b/platform-api-docs/docs/check-permission.StatusCodes.json
new file mode 100644
index 000000000..0d57dccdb
--- /dev/null
+++ b/platform-api-docs/docs/check-permission.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","description":"Result of checking whether the authenticated user can perform a given operation in the selected context.","properties":{"authorized":{"type":"boolean","description":"Whether the authenticated user is authorized to perform the requested operation."}},"title":"CheckPermissionResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"}}}
diff --git a/platform-api-docs/docs/check-permission.api.mdx b/platform-api-docs/docs/check-permission.api.mdx
new file mode 100644
index 000000000..2f1846f38
--- /dev/null
+++ b/platform-api-docs/docs/check-permission.api.mdx
@@ -0,0 +1,66 @@
+---
+id: check-permission
+title: "Check permission"
+description: "Checks whether the authenticated user is allowed to perform the given operation in the specified user, organization, or workspace context."
+sidebar_label: "Check permission"
+hide_title: true
+hide_table_of_contents: true
+api: eJzNVU1v20YQ/SuLOTUAIdlp2oNOcYI0MHqo4aTowdBhvRyRa5O769mhXYXgfy9m+SHKUqwkyKEnidzhzHtv3s60wLqIsLqBgFTbGK13EdYZ5BgN2cDWO1jB+xLNfVRPJXKJpLhEpRsu0bE1mjFXTURSNipdVf4Jc8VeBaSNpzoFF/YRnfIBSUtGZV16HQMau7HD95nyVGhnv6QYeVJPnu5j0AaV8Y7xX15ABlOay3yEdjWBhwyCJl0jIwmvFpyuEVbgqbjMIQMrfB4apC08Z/nXrLxyTY1kjbK5sNxYJKkdTYm1hlULvA2S1jrGAgkyELKa+1e/v4Guy6baE41TCP6Z+P7M8nPBXhZg16CprLTSiMZT07BCIz2ftYTwobGEOayYGjyCMzJZV0DXrSU4Bu8iRjl/fXYmP89w/AkZpPSO5VSHUInRrHfLuygh7WEJf3uHhg84XWNsKlZ+07OwrjhlY6PdZF79VeseUSGQhLHtmUlmT/aLqDKBvPW+Qu0OG3/6Zk3pnl8uER+jxE4oF9J/YMsVHl6R60F/6DqJenOsA+90Pub9nlbsfHADNcaoC5Rh8rxD+0KNgUfcsuPwgcjTAfJfj3hn6pTzPM6jlCqiacjyNk2Fd6gJ6aLhElY3a7FljVx6mSgFJoxajmA5m4vL5CC5hkiP43hpqIIVlMwhrpZLHezCVL7JFxEfkPTC+oNef0on6qrSnHr4XuLVxdUlCIwR5ScRtRdojnXSSCqOEyE5KwVBNvz5YxwHd0+c2Fu38enzQdABhZQ9BVDoWoNxCBY3aJPcsE9+Thlrbas0jTb+7e6gy0CU6+ucL87Pf1ucycvgI9c6uWkYWsm0KswH+x7KdufK/9d6Gvojj8tQaeuEXxKqHUy1v2wz6G21zqD0keW4bW91xL+p6jp53Q9rMVtuo76t5H5tdBXxBUm+YZcdBXqP29myfNRVIzEg2+Tbi59aYy9U3l+VP1j/l+thDr1SP7zSXlJnb5/uMK7lgayATEMlgxJ1jpRa1396YQwGnn11ME/3RtHHD58hS5tkvkP2b3rKPhxpt53lbts+4rO/R9d1MOJneYZu3XXdf3bGgLk=
+sidebar_class_name: "get api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Checks whether the authenticated user is allowed to perform the given operation in the specified user, organization, or workspace context.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/create-role.ParamsDetails.json b/platform-api-docs/docs/create-role.ParamsDetails.json
new file mode 100644
index 000000000..dd9160da2
--- /dev/null
+++ b/platform-api-docs/docs/create-role.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"orgId","in":"query","description":"Organization numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}}]}
diff --git a/platform-api-docs/docs/create-role.RequestSchema.json b/platform-api-docs/docs/create-role.RequestSchema.json
new file mode 100644
index 000000000..2aae28379
--- /dev/null
+++ b/platform-api-docs/docs/create-role.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body","body":{"description":"Role create request","content":{"application/json":{"schema":{"type":"object","description":"Request payload for creating a custom role in an organization.","properties":{"name":{"type":"string","description":"Role name."},"description":{"type":"string","description":"Role description."},"permissions":{"type":"array","items":{"type":"string"},"description":"List of permission names assigned to the role."}},"title":"CreateRoleRequest"}}},"required":true}}
diff --git a/platform-api-docs/docs/create-role.StatusCodes.json b/platform-api-docs/docs/create-role.StatusCodes.json
new file mode 100644
index 000000000..484fb0ed5
--- /dev/null
+++ b/platform-api-docs/docs/create-role.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","description":"Created role details.","properties":{"name":{"type":"string","description":"Role name."},"description":{"type":"string","description":"Role description."},"permissions":{"type":"array","items":{"type":"string"},"description":"List of permission names assigned to the role."}},"title":"CreateRoleResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"},"409":{"description":"Duplicate role name","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}}}}
diff --git a/platform-api-docs/docs/create-role.api.mdx b/platform-api-docs/docs/create-role.api.mdx
new file mode 100644
index 000000000..a2f4280cd
--- /dev/null
+++ b/platform-api-docs/docs/create-role.api.mdx
@@ -0,0 +1,66 @@
+---
+id: create-role
+title: "Create role"
+description: "Creates a custom role in the organization identified by `orgId`."
+sidebar_label: "Create role"
+hide_title: true
+hide_table_of_contents: true
+api: eJztVktv4zYQ/ivEnFpAtZN2W6A+NUm3QIACCZL0ZBjYiTS2maVIhRwl6wr878WQki1b+0Kxhx56k8h5fDPfPNgB4ybAYgneGQqwKqCiUHrdsHYWFnDlCZmCQlW2gV2tRE5pq3hLyvkNWv03iqzSFVnWa02Vetypd85vrqt3MyjANeSTyHW1N3jnDEEBDXqsickLhA4s1gQLSKpQgBYAzy35HZzCuhl7tm1NXpcHBF7cenputacKFuxbKiCUW6oRFh3wrhE32jJtyEMBa+dr5Hz0yxuIcZXVKfClq3aic+xe4KsyRaJ6QSigdJbJsohj0xhdJnjzpyA63RSAe3yikiex3WWDqsGdcViptfPZl7abKQ9oj2iQyBsvKWdNQZzlpO6dBvbabqZOxZyIziCe3H2V6ugoWWjI1zoE7WwYWUDvUcjUTHWYWj71DH/qwMqt1cFawhgUhqA3lirFLlWiZGMGMRbAmg0d1VmfT4hyfVwV6SA0zoacqx/PzqdkZ0vVtyO4N5gprIhRm/A/bx/hLTMjxMUC3pydTbm5xOrfNOChCpZQUwi4IRl9p7QdEzIITsMfwX/rvfMT5D9Nkd8MU1FZxwqNca9UQZL+dSr9e5vDyRlLyfyvxhsLCFS2XvMuDfVLQk/+ouUtLJYrGa018dbJLmhcoq1BuYN5XkGi7l+GldB6AwvYMjdhMZ9jo2elcW01C/RMHmfaTcr6Pt2oW4Msc11diby6uL0G8T1Au5fc5DjHAPehikfol4b8PyYhKPqPP4aN8fTKKR+S87vDynj7AevG0KGPP9WE++OjxlsO56soa3DtErI+5X2AEtGXYpdM6pJCLyz1gmWql+O8jrNJNWqTduHa/Xa4iAUIKdnP+ez8/OfZWRoYLnCNdhTpVb8X84o/GUn7kv0WL4ueK6YPPG8MaiuAUmRdX1Sjd81Wim2xhK57xEB/eROjHOf3hZRapQM+GmmSNZpAn4H+3V3fT9+rr3iIfBTle9qNXjovaFqRSSX6gl4LkNQuBWwJK/IJYVa6yjh+eBC7B93JBIjFoHFRltTwZ2XHbXl7c/8gld4/fWpXiY7HV3lV4avglFcdD0sinXVg0G7aNDAg25S+wOO2OmmjFNWwY+xuhLDrssSDe082RhgyxvIPcRVj/AcSGbud
+sidebar_class_name: "post api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Creates a custom role in the organization identified by `orgId`.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/delete-role.ParamsDetails.json b/platform-api-docs/docs/delete-role.ParamsDetails.json
new file mode 100644
index 000000000..178f18516
--- /dev/null
+++ b/platform-api-docs/docs/delete-role.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"roleName","in":"path","description":"Role name.","required":true,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}}]}
diff --git a/platform-api-docs/docs/delete-role.RequestSchema.json b/platform-api-docs/docs/delete-role.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/delete-role.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/delete-role.StatusCodes.json b/platform-api-docs/docs/delete-role.StatusCodes.json
new file mode 100644
index 000000000..990d6f9b3
--- /dev/null
+++ b/platform-api-docs/docs/delete-role.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"204":{"description":"OK - No content"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"},"404":{"description":"Role not found","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}}}}
diff --git a/platform-api-docs/docs/delete-role.api.mdx b/platform-api-docs/docs/delete-role.api.mdx
new file mode 100644
index 000000000..a786738fa
--- /dev/null
+++ b/platform-api-docs/docs/delete-role.api.mdx
@@ -0,0 +1,66 @@
+---
+id: delete-role
+title: "Delete role"
+description: "Deletes the custom role identified by `roleName` in the organization identified by `orgId`. Predefined roles cannot be deleted."
+sidebar_label: "Delete role"
+hide_title: true
+hide_table_of_contents: true
+api: eJzNVF1vEzEQ/CvWPoFkkhQKD/dES4NUgUrVlqcqUp27TeLWZ1/tvZZw8n9H67vLt6BCQuIpOXvsmVnPbgOk5gGyW/DOYICJhAJD7nVF2lnI4AwNEgZBCxQMEbpAS3qmsRDTpbjjtQtV4p3QNoGcnyurfyo+vwt2fn5e3A1AgqvQJ8h5sSK5cgZBQqW8KpHQs6wGrCoRMuh5QIJmXZWiBeyK5RsEH2AKj4+19lhARr5GCSFfYKkga4CWFV8ZyGs7hxjliiUJ7Ckea/TLPY5vm/5sXaLX+dqnfxGztoRz9CBh5nypqF36cAwxTvh4qJwNGPjE29Ex/+xo+CLeiAsncmcJLUGUcDwa7eNOVSFYDAYCCT06a0BVldF58jC8D4xtNlSu9d9CiSGoOXIwOvFueo8531d5fkXSrdAeeKi+QJoML429d/6q8wcxxqT83QGHfT6EdSSUMe4Zi9bngXq07+5IzFxti//VapQQMK+9pmVK9ikqj/6kpgVktxN++RJp4bghitQQqRl4F4apO4dN3wUR+C7/1DdJ7Q1ksCCqQjYcqkoPcuPqYhDwEb0aaLcX4+u0Iy6NIs6g+MR4cXJ5Diyk13nNhWpNb6pd+WZG6ALO39MEAtn9+dyn+/6ZUnG0nbl0vCtSp4Jp/ySQ7eocQwfmF1Z5euFt85uWsVTapOaauY/rjSiBK9fyHA2Ojt4PRrxYuUClSgnp5kE7mNLg2xXYrEP2r4ZkV2TCHzSsjNKWRSa3TReMfmxLyFYDciJh4QLxZtNMVcDv3sTIy+1A47wUOqip4djPlAn4G2uvrroOeS1eMPkOKn7A5cZofVKmZkzK2ZPymoX8vaitkX+QvltUdrnJ3stalS1OooQFqgJ9UtNun+Q5VrRxcG+cbPXt2fjr+GYMEtR2n+z0RSI4qKtpWsSNe0Ab40om8TdrjPEXrVGkrw==
+sidebar_class_name: "delete api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Deletes the custom role identified by `roleName` in the organization identified by `orgId`. Predefined roles cannot be deleted.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/describe-role.ParamsDetails.json b/platform-api-docs/docs/describe-role.ParamsDetails.json
new file mode 100644
index 000000000..178f18516
--- /dev/null
+++ b/platform-api-docs/docs/describe-role.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"roleName","in":"path","description":"Role name.","required":true,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}}]}
diff --git a/platform-api-docs/docs/describe-role.RequestSchema.json b/platform-api-docs/docs/describe-role.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/describe-role.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/describe-role.StatusCodes.json b/platform-api-docs/docs/describe-role.StatusCodes.json
new file mode 100644
index 000000000..4ed7c04c7
--- /dev/null
+++ b/platform-api-docs/docs/describe-role.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","description":"Role description response.","properties":{"role":{"type":"object","description":"Role details with assigned permissions.","properties":{"name":{"type":"string","description":"Role name."},"description":{"type":"string","description":"Role description."},"isPredefined":{"type":"boolean","description":"Whether the role is predefined by the system."},"permissions":{"type":"array","items":{"type":"string"},"description":"List of permission names assigned to the role."}},"title":"RoleDto"}},"title":"DescribeRoleResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"},"404":{"description":"Role not found","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}}}}
diff --git a/platform-api-docs/docs/describe-role.api.mdx b/platform-api-docs/docs/describe-role.api.mdx
new file mode 100644
index 000000000..17dd2885f
--- /dev/null
+++ b/platform-api-docs/docs/describe-role.api.mdx
@@ -0,0 +1,66 @@
+---
+id: describe-role
+title: "Describe role"
+description: "Retrieves the details of the role identified by `roleName` in the organization identified by `orgId`."
+sidebar_label: "Describe role"
+hide_title: true
+hide_table_of_contents: true
+api: eJzNVktv20YQ/iuLOTUAIdmN2wNPcR4tjBSt4aTIwRDgFTkS1yF36Z2hXZXY/17M8iFKFBInh6AnSTuzM988vm/VAustQXoL3pVIsEogR8q8qdk4CyncIHuDj0iKC1Q5sjYlKbeJP+WOMjlaNhuDuVrv1J2c/akrvFPGRifnt9qaf7UEPHZ2fnuV3y0gAVejjy5XOaTwNmJY440rERKotdcVMnpB2oLVFUIKQyZIwAjUWnMBM/wCUS5IEo8PjfGYQ8q+wQQoK7DSkLbAu1pCEntjtxBCMmaJEIcUDw363SzHX9MKbVOhN9m+Uv+szMYybtFDAhvnK83d0a8XEMJKrlPtLCHJjZ/PzuTjCMN7SCBzltGyWHVdlyaLkJb3JC7tPKlb32PGp3s2OVJDeqmk9jIqNh0WmcGzA3a782S4UJrIbC3mqkZfGSLjLM2jdyM4ns4XRhyObM+6OjmKEQxde8xxY6zMawyxdq5EbWcxPhXIBfoJIUjVYwBZc7HQjhirGH9S8iS89l7LahnGik6s5HHaPwyx8HAfLfaA9q1lN2JayEoDG5Zpxarfsjs4mzLuph83hCAuF6f27bXOlSw1En/L4u15cAsVEuktiuYcr8/hGgyOp3g6FvDOe+dnyF+eYMqgNMo6Vros3RPmEL0v5t7dcjlWG9fY/P9aakiAMGu84V1UyNeoPfrLhgtIb1eiIBVy4URatxizilamsIyqv2wHKQ0ggfzjoLSNLyGFgrmmdLnUtVlkpWvyBeEDer0wbsaGD9GirkvNImTqjfiry+srEBQDyA/Spa7iKdSxaMkIvUpG7kUnSPovvw0Sef/EsTPGbly83neoRyFpvwZQyjUZUu8s49VZHO9h8dOSsdKmjAq9ca/2hpCAdK7Lc744P/9lcRYJ74grbfeKNrItkvMYYrvfsR/2/PZ9Z/yHl3WpjRXcsQFtvyvDP4QE0vHhXSVQOGIxtu1aE/7tyxDkuHsoZYVyQ3pdCg02uiT8Qq0/3fSMeaGe8aKeRPwZd5Mn+1GXjfjE1XvU3giQ7wd18FfiZPpByu1umn2ANbYtrEICBeocfUTTmS+zDGueXJzJywGPf3/3ERLQh7w54kmMfhJU23YeH91ntCGMGFl+C8AQ/gPQ14A9
+sidebar_class_name: "get api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Retrieves the details of the role identified by `roleName` in the organization identified by `orgId`.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/info/parameter-tables/orgs/parameters.yml b/platform-api-docs/docs/info/parameter-tables/orgs/parameters.yml
index f9c63961c..ca4a68923 100644
--- a/platform-api-docs/docs/info/parameter-tables/orgs/parameters.yml
+++ b/platform-api-docs/docs/info/parameter-tables/orgs/parameters.yml
@@ -39,3 +39,8 @@
Req/Opt: Optional
Description: Optional array of specific quota names to include in the response.
Omit to retrieve all quotas.
+- Name: "`userId`"
+ Type: integer
+ Location: path
+ Req/Opt: Required
+ Description: User numeric identifier.
diff --git a/platform-api-docs/docs/info/parameter-tables/permissions/parameters.yml b/platform-api-docs/docs/info/parameter-tables/permissions/parameters.yml
new file mode 100644
index 000000000..fb2519b61
--- /dev/null
+++ b/platform-api-docs/docs/info/parameter-tables/permissions/parameters.yml
@@ -0,0 +1,15 @@
+- Name: "`orgId`"
+ Type: integer
+ Location: query
+ Req/Opt: Optional
+ Description: Organization numeric identifier.
+- Name: "`workspaceId`"
+ Type: integer
+ Location: query
+ Req/Opt: Optional
+ Description: Workspace numeric identifier.
+- Name: "`operationId`"
+ Type: string
+ Location: query
+ Req/Opt: Required
+ Description: Operation identifier to check in the selected context.
diff --git a/platform-api-docs/docs/info/parameter-tables/roles/parameters.yml b/platform-api-docs/docs/info/parameter-tables/roles/parameters.yml
new file mode 100644
index 000000000..9931605d5
--- /dev/null
+++ b/platform-api-docs/docs/info/parameter-tables/roles/parameters.yml
@@ -0,0 +1,30 @@
+- Name: "`orgId`"
+ Type: integer
+ Location: query
+ Req/Opt: Required
+ Description: Organization numeric identifier.
+- Name: "`max`"
+ Type: integer
+ Location: query
+ Req/Opt: Optional
+ Description: "Maximum number of results to return. Default: `50`. Maximum: `100`."
+- Name: "`offset`"
+ Type: integer
+ Location: query
+ Req/Opt: Optional
+ Description: "Number of results to skip for pagination. Default: `0`."
+- Name: "`name`"
+ Type: string
+ Location: query
+ Req/Opt: Optional
+ Description: Role name search filter.
+- Name: "`type`"
+ Type: string
+ Location: query
+ Req/Opt: Optional
+ Description: Role type filter.
+- Name: "`roleName`"
+ Type: string
+ Location: path
+ Req/Opt: Required
+ Description: Role name.
diff --git a/platform-api-docs/docs/info/parameter-tables/roles/request-bodies.yml b/platform-api-docs/docs/info/parameter-tables/roles/request-bodies.yml
new file mode 100644
index 000000000..8ac1cbe51
--- /dev/null
+++ b/platform-api-docs/docs/info/parameter-tables/roles/request-bodies.yml
@@ -0,0 +1,32 @@
+- Name: "**CreateRole**"
+ Type: ""
+ Req/Opt: ""
+ Description: Create role
+- Name: name
+ Type: string
+ Req/Opt: Optional
+ Description: Role name.
+- Name: description
+ Type: string
+ Req/Opt: Optional
+ Description: Role description.
+- Name: permissions
+ Type: array
+ Req/Opt: Optional
+ Description: List of permission names assigned to the role.
+- Name: "**UpdateRole**"
+ Type: ""
+ Req/Opt: ""
+ Description: Update role
+- Name: name
+ Type: string
+ Req/Opt: Optional
+ Description: Role name.
+- Name: description
+ Type: string
+ Req/Opt: Optional
+ Description: Role description.
+- Name: permissions
+ Type: array
+ Req/Opt: Optional
+ Description: List of permission names assigned to the role.
diff --git a/platform-api-docs/docs/info/permissions.info.api.mdx b/platform-api-docs/docs/info/permissions.info.api.mdx
new file mode 100644
index 000000000..acb0b116c
--- /dev/null
+++ b/platform-api-docs/docs/info/permissions.info.api.mdx
@@ -0,0 +1,24 @@
+---
+id: permissions-info
+title: "Permissions"
+description: "API operations for frontend-visible permissions in Seqera Platform"
+sidebar_label: Permissions
+hide_title: false
+custom_edit_url: null
+---
+
+import ApiLogo from "@theme/ApiLogo";
+import Heading from "@theme/Heading";
+import SchemaTabs from "@theme/SchemaTabs";
+import TabItem from "@theme/TabItem";
+import Export from "@theme/ApiExplorer/Export";
+import MDXComponents from "@theme-original/MDXComponents";
+
+
+Use these endpoints to inspect the authenticated user's effective roles and allowed operations in a personal workspace context or an organization workspace context.
+
+The `Check permission` endpoint accepts an `operationId` query parameter using the operation identifier returned by `Retrieve permissions`.
+
+### Path and query parameters
+
+::table{file=parameter-tables/permissions/parameters.yml}
diff --git a/platform-api-docs/docs/info/roles.info.api.mdx b/platform-api-docs/docs/info/roles.info.api.mdx
new file mode 100644
index 000000000..509afe140
--- /dev/null
+++ b/platform-api-docs/docs/info/roles.info.api.mdx
@@ -0,0 +1,28 @@
+---
+id: roles-info
+title: "Roles"
+description: "API operations for predefined and custom organization roles in Seqera Platform"
+sidebar_label: Roles
+hide_title: false
+custom_edit_url: null
+---
+
+import ApiLogo from "@theme/ApiLogo";
+import Heading from "@theme/Heading";
+import SchemaTabs from "@theme/SchemaTabs";
+import TabItem from "@theme/TabItem";
+import Export from "@theme/ApiExplorer/Export";
+import MDXComponents from "@theme-original/MDXComponents";
+
+
+Use these endpoints to list predefined and custom roles, discover assignable permissions, and create, update, validate, or delete custom roles in an organization context.
+
+Use `List role permissions` as the discovery endpoint for the permission names accepted by `Create role` and `Update role`.
+
+### Path and query parameters
+
+::table{file=parameter-tables/roles/parameters.yml}
+
+### Request body parameters
+
+::table{file=parameter-tables/roles/request-bodies.yml}
diff --git a/platform-api-docs/docs/list-available-features.ParamsDetails.json b/platform-api-docs/docs/list-available-features.ParamsDetails.json
new file mode 100644
index 000000000..4661c0329
--- /dev/null
+++ b/platform-api-docs/docs/list-available-features.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"orgId","in":"query","description":"Organization numeric identifier.","schema":{"type":"integer","format":"int64"}},{"name":"workspaceId","in":"query","description":"Workspace numeric identifier.","schema":{"type":"integer","format":"int64"}}]}
diff --git a/platform-api-docs/docs/list-available-features.RequestSchema.json b/platform-api-docs/docs/list-available-features.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/list-available-features.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/list-available-features.StatusCodes.json b/platform-api-docs/docs/list-available-features.StatusCodes.json
new file mode 100644
index 000000000..16ed3d47c
--- /dev/null
+++ b/platform-api-docs/docs/list-available-features.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","description":"Features enabled in the selected context.","properties":{"features":{"type":"array","items":{"type":"string","description":"Feature flag identifier.","enum":["DATA_EXPLORER","DATA_STUDIO","MANAGED_IDENTITY","SEQERA_COMPUTE","DYNAMIC_RESOURCE_LABELS","CONTAINERS","METERING","SEQERA_COMPUTE_ENABLE_CE_TYPE_CHOICE","PIPELINE_VERSIONING","STUDIO_METRICS","DATA_STUDIO_CONNECT_IFRAME","DATA_STUDIO_SSH_ENABLED","SSH_KEYS_MANAGEMENT","SEQERA_AI_DEBUG_BUTTON","CUSTOM_ROLES","CE_FORMS_V2","AUDIT_LOG_V2"],"title":"FeatureId"},"description":"Feature identifiers enabled in the selected context."}},"title":"ListFeaturesResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"}}}
diff --git a/platform-api-docs/docs/list-available-features.api.mdx b/platform-api-docs/docs/list-available-features.api.mdx
new file mode 100644
index 000000000..2872343cf
--- /dev/null
+++ b/platform-api-docs/docs/list-available-features.api.mdx
@@ -0,0 +1,66 @@
+---
+id: list-available-features
+title: "List available features"
+description: "Lists the feature flags enabled for the authenticated user in the specified organization or workspace context."
+sidebar_label: "List available features"
+hide_title: true
+hide_table_of_contents: true
+api: eJy9Vt9v4zYM/lcMPhtJe7vtIU9zErU1LrEz27mtOASGajOJWttyJbm9LvD/PlCJm1+9a4cBe2plUeT3kR/JbMDwlYbBN6hRlUJrISsNCxdy1JkStRGyggFMhDbaMWt0lshNo9BZFnylHaz4XYG5s5TK3vLGrLEyIuMGc6fRqBxR2RtdYyaWAnNHqhWvxN+cXDtSOc9SPeiaZ+hksjL43fTABVmjshZ+vgvvPXFRULSrLQINLtRc8RINKmKwgYqXCAOQauXn4IIg5I8Nqhc45RMeYqiaEpXIHJET9KVARQh0tsaSw2AD5qUmt6IyuEIFLiylKrnZfvrtM7St+xr7lcx7CP58Zf3fwy9cUKhrWWnU9OLTxQX9OaH8BVywGa4M3fK6LqhOQlb9e00mm/Og8u4eM3MGvivBa/27ImOBGVX+oJK1oloasYW27Iq3j8GV4pQfYbA8/K6NEtXqR7GtAE9yhlVTkpTHXuKl7K/ZJIxYBO72HCfzsR+CC1Mv8K7ZOPXHLEj85BZciNkfLPLSUTidzRNGL24Db+qP0ojF4TwasXTiDdkkBhdGYZB4fsAiOkxZwiI/uD5zkbLAG05YOmJpcjtj6egm9EfkeObP2MQPWPqVRbEfBrvHFls6ZUnkj+JjxOkoDAI2SlL/KvKm7OQyjm92scbkJ75Jv7DbON1ynLIg2UPz/HTMhvPrdDhPkjAgLvM4CadpFE6YpcbSqzCaxunXT+CCNx/7SToJr+m4cMEIU+A+/34O7Y9Ks6/KBxTStnvf1OedtqKdoqFtyeTzW5oe8txR+NigNv9G3PREKMxJKyVqzVdoGZ5o/li5neGZQA8JMKWkOkP+yxvd2M03p5LG4UUhnzG3rjRmjRLmxU60IXKFymvMGgbfFtToJZq1pJm4QouR0xX0D6Z3f7kfkBrVUzcdG1XAANbG1HrQ7/Na9LJCNnlP4yMq3hPyrNVie+PMCm5o5jgjsne8mQ+EpAMaU163OTqE+5omitgNNDrfWSNwd/9cddPs/tnYBIhqKe3zXU53KCjsewCJrshQ74xJEDyzgjgmf0gZSy4KO0yX8vf9ResCZW4b57J3eflr74I+1lKbkltB7UY+idbh3XZyDrJ/BHaz1+f/v053paBjvy64qIiKzclmJ6HjHwDuflAvXFhLbchis7njGueqaFv6vF1sJK1caAscBkteaPwJ8w8s3jexPuDLwWZ/4kVDNkCb9+PB39u5P4l8vNf38Rd0UIIA2A51YY08R2XTsn3qZRnW5uDV2XA66utrRjObH/fQSc9Y7936rF4OfG82W4tEPmDVttDhN3SGdtG27T/bxV/I
+sidebar_class_name: "get api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Lists the feature flags enabled for the authenticated user in the specified organization or workspace context.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/list-role-permissions.ParamsDetails.json b/platform-api-docs/docs/list-role-permissions.ParamsDetails.json
new file mode 100644
index 000000000..8f1cfcce8
--- /dev/null
+++ b/platform-api-docs/docs/list-role-permissions.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"orgId","in":"query","description":"Organization numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"name","in":"query","description":"Permission name search filter.","schema":{"type":"string"}}]}
diff --git a/platform-api-docs/docs/list-role-permissions.RequestSchema.json b/platform-api-docs/docs/list-role-permissions.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/list-role-permissions.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/list-role-permissions.StatusCodes.json b/platform-api-docs/docs/list-role-permissions.StatusCodes.json
new file mode 100644
index 000000000..fa7344777
--- /dev/null
+++ b/platform-api-docs/docs/list-role-permissions.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","description":"Available role permissions.","properties":{"permissions":{"type":"array","items":{"type":"object","description":"Metadata for a role permission.","properties":{"name":{"type":"string","description":"Permission name."},"category":{"type":"string","description":"Permission category."}},"title":"RolePermissionResponseDto"},"description":"Permission definitions available for assignment to roles."}},"title":"ListRolePermissionsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"},"404":{"description":"Not found","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}}}}
diff --git a/platform-api-docs/docs/list-role-permissions.api.mdx b/platform-api-docs/docs/list-role-permissions.api.mdx
new file mode 100644
index 000000000..beffbb7ef
--- /dev/null
+++ b/platform-api-docs/docs/list-role-permissions.api.mdx
@@ -0,0 +1,66 @@
+---
+id: list-role-permissions
+title: "List role permissions"
+description: "Lists the role permissions available for assignment in the organization identified by `orgId`."
+sidebar_label: "List role permissions"
+hide_title: true
+hide_table_of_contents: true
+api: eJzNVUtv3EYM/isDnlpA2LUTtwed6qRJYPRlOOnJWCBcidKOI83IHMrpVtB/DziSvA9t7ORQoCc9yJnv4+tjB4JlgPQW2FcUYJVATiFj24j1DlL43QYJRjZk1ME0xLUNwXoXDD6grXBdkSk8GwzBlq4mJ8a6eMBzic7+i3qTsTk5sYWl3Ky35qPn8ir/uIAEfEMcXa7yEe7GV3S9w4EEGmSsSYiVaQcOa4IU4h2QgFWe9y3xFo7Z/7VPwbU1sc12VFjxme5by5RDKtxSAiHbUI2QdiDbRmGsEyqJIYHCc40y/Pr5Avo+eeQSH09S2UVk1NkEQs42prCVDERmwEHYuhL6fqUsQ+NdoKD2F2dn+jgK9TdIIPNOyIlasWkqm8XIl3dBXbo5hF/fUSYzrpePlT0uuhJtWGsmdiCzZ9y7GJlRc2CF6vA84B8kmKPg0EnHqHPQIevHmXom5QvoE8hQqPS8/a7T06GF1hzESqXnDvv0ZqzQr+IV56t35VRYZ+XpCRIfcxAOAU8Mx4QKfa+eF6c64xXmRrucgnxPi+wG4xZqCgFLUnk4LuRhYSbHE128i+MNs+cZ85cnenrSBuO8GKwq/5lyiN4Xc+8/vZjCty7/v0bZJxAoa9nKNurYK0ImvmxlA+ntSse8Jtl41cGSIiqqCZaxF5bNgSYG4odJEFuuIIWNSBPS5RIbu8gq3+aLQPfEuLB+1tzvo8VcVyiqaua1+pvL6ytQGhPL95qmIeR9ro9RK+KkXPq9jk6QjC9vJ728+ywxNdYVPh4fUzSyUNjnCGq4NqMwOmt9MYv1PQx+P2Sq0VZRrgv/y87QJ6CZG3DOF+fnPy3O9Gfjg9TodvoSB24mgcdUu12z/ffbcky80D+ybCq0TonHDHRjt0ybPDlQ5lUCGx9EzV23xkB/c9X3+nvYVtpFuQ3KL4e0wCrQE2H+cDNOzY/mGzbsSc6faLu3wh+watUHdKV+O49nd+oT0OPG3iGv9IOtQsdxTGBDmBPH3AxnLrOMGtk7NdOWgyF+9+YDJICHM3M0I/H2aWm67d7dXTd4fPCfyPU9TMRFv6Ff9X3/Ba+eZxw=
+sidebar_class_name: "get api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Lists the role permissions available for assignment in the organization identified by `orgId`.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/list-roles.ParamsDetails.json b/platform-api-docs/docs/list-roles.ParamsDetails.json
new file mode 100644
index 000000000..c96c2c57a
--- /dev/null
+++ b/platform-api-docs/docs/list-roles.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"orgId","in":"query","description":"Organization numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"max","in":"query","description":"Maximum number of results to return. Default: `50`. Maximum: `100`.","schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip for pagination. Default: `0`.","schema":{"type":"integer","format":"int32"}},{"name":"name","in":"query","description":"Role name search filter.","schema":{"type":"string"}},{"name":"type","in":"query","description":"Role type filter.","schema":{"type":"string","enum":["predefined","custom"]}}]}
diff --git a/platform-api-docs/docs/list-roles.RequestSchema.json b/platform-api-docs/docs/list-roles.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/list-roles.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/list-roles.StatusCodes.json b/platform-api-docs/docs/list-roles.StatusCodes.json
new file mode 100644
index 000000000..ba5453116
--- /dev/null
+++ b/platform-api-docs/docs/list-roles.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","description":"Paginated role list response.","properties":{"roles":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Role name."},"description":{"type":"string","description":"Role description."},"isPredefined":{"type":"boolean","description":"Whether the role is predefined by the system."}},"title":"ListRolesResponse.RoleInfo"},"description":"Roles matching the query."},"totalSize":{"type":"integer","format":"int32","description":"Total number of matching roles."}},"title":"ListRolesResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"}}}
diff --git a/platform-api-docs/docs/list-roles.api.mdx b/platform-api-docs/docs/list-roles.api.mdx
new file mode 100644
index 000000000..153cbb243
--- /dev/null
+++ b/platform-api-docs/docs/list-roles.api.mdx
@@ -0,0 +1,66 @@
+---
+id: list-roles
+title: "List roles"
+description: "Lists predefined and custom roles available in the organization identified by `orgId`."
+sidebar_label: "List roles"
+hide_title: true
+hide_table_of_contents: true
+api: eJy1Vttu4zYQ/RVinlpAcJy99EFPzbbbIugt2KToQ2AgtDSymFCkMhxl4zX078VQki1f6rjZ9skWOZfDwzPDWQHrRYD0FshbDDBLIMeQkanZeAcp/GoCB1UT5lgYh7nSLldZE9hXKroo/aSN1XOLyjjFJSpPC+3MFy0RlMnRsSkM5mq+VHeeFpf53QQS8DVSNLnM+zSfIoIEak26QkYSXCtwukJIIXpCAkZQPTZIS9jF+sc4sWsqJJNtAJBkJXxsDGEOKVODCYSsxEpDugJe1pLGOMYFEiRQeKo0d0vfvYO2TdZYKv18HMlv+tlUTSUg5kjKF4owNJaDYq8IuSE3UT9ioRvLqbp7P72bqN4nVXfn02mk6ERwb99sgfNFEZCP4/v9EK7wYGpVeFK1XhgXWRyD/BpM8ecoIrl8JWYqoKasVIWx3N3ZXsrAZNxiK0HceTmBmJ0QOQF0TSVVsRE+JNDJHmZtOxMlhdq7gEHc30yn8rMjx1/ExztGx7Kr69qaLPJ6dh/EZLWPwM/vMeM99FfdlWAei05ZE1gNCOQkNUk9sengdLW8CaqJtDBiGKtwKNm2e8fpPin/cGMTaHf2TnIdLcUIJlxtyN6EmHtvUbu9GH+VyCVS7DiRE7PVpubLuBOWgbGaiFaADVsc95pPA4HydekKv3eQiDSoSnNWGreIIaO8ImL2rO21+YKnlMNu5BtxHjWIdY54eS8ghraV/XeHZPdB50raHAb+N/rbdMZbqDAEvUB5DY4rZTA8VJtr9B+JPO0hf3ugYIYnQTnPSlvrP2MeQwXMGjK8jA/CB9SEdNFwCentTGqxQi69PCOL2PhqLVtwRv2DEpCehtekIQsplMx1SM/OdG0mmfVNPgn4iKQnxu9d1HXcUVdWs1yp+kHs1cXVJUjqAdm1ENmRMsa35kUyDh0nyjoaQdL/+WkQy/1njic2Ikdx70nsUUjalwDKcU2GoTcWBegsKmD78OMjY6WNjVot/PebjTYBYa7Lcz45P38/mcpi7QNX2m2aRZSoGgjfaQZrDf5/00TPMuMzn9VWGyco43FXvRxGE07pA8vCajXXAf8k27ay3L0bIpLcBIGQQ1poG/DIgb751JfNt+qE6eMgygdcjsabJ20bsQF53E7H8d8MHEfwdSPPK9G9ftw4xtgw57wS1JGJ40jWfpL5mpw7Q8iRZP1Us0k2kw8yki32vgRK1DlSVG3nc5FlWI9p2Wv7Wx3z5483kIDeblY7zSlGH0YJtxzFXq06ixv/gK5tYQ1cvqGdtW37N9xtQTc=
+sidebar_class_name: "get api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Lists predefined and custom roles available in the organization identified by `orgId`.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/list-user-roles-in-organization.ParamsDetails.json b/platform-api-docs/docs/list-user-roles-in-organization.ParamsDetails.json
new file mode 100644
index 000000000..8b8d6d3ae
--- /dev/null
+++ b/platform-api-docs/docs/list-user-roles-in-organization.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"orgId","in":"path","description":"Organization numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"userId","in":"path","description":"User numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}}]}
diff --git a/platform-api-docs/docs/list-user-roles-in-organization.RequestSchema.json b/platform-api-docs/docs/list-user-roles-in-organization.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/list-user-roles-in-organization.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/list-user-roles-in-organization.StatusCodes.json b/platform-api-docs/docs/list-user-roles-in-organization.StatusCodes.json
new file mode 100644
index 000000000..0e442b2ef
--- /dev/null
+++ b/platform-api-docs/docs/list-user-roles-in-organization.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","description":"A user's organization membership details and workspace-level roles and permissions.","properties":{"user":{"type":"object","properties":{"memberId":{"type":"integer","format":"int64","description":"Member numeric identifier."},"userId":{"type":"integer","format":"int64"},"userName":{"type":"string","description":"Username of the organization member."},"email":{"type":"string","description":"Email address of the organization member."},"firstName":{"type":"string","description":"First name of the organization member."},"lastName":{"type":"string","description":"Last name of the organization member."},"avatar":{"type":"string","description":"Avatar image URL for the organization member."},"role":{"type":"string","enum":["owner","member","collaborator"],"x-enum-varnames":["owner","member","collaborator"],"title":"OrgRole"}},"title":"MemberDbDto"},"userWorkspaces":{"type":"array","items":{"type":"object","description":"Workspace-specific roles and permissions for a user.","properties":{"workspaceId":{"type":"integer","format":"int64","description":"Workspace numeric identifier."},"workspaceName":{"type":"string","description":"Workspace name."},"roles":{"type":"array","items":{"type":"object","description":"A role assigned to the user in a workspace and the source of that assignment.","properties":{"role":{"type":"string","description":"Workspace role name."},"roleSourceType":{"type":"string","description":"Source of a workspace role assignment.","enum":["individual","team"],"title":"WspRoleSourceType"},"sourceTeamId":{"type":"integer","format":"int64","nullable":true,"description":"Source team numeric identifier when the role is inherited from a team."},"sourceTeamName":{"type":"string","nullable":true,"description":"Source team name when the role is inherited from a team."},"sourceTeamType":{"nullable":true,"type":"string","description":"Team type.","enum":["regular","system_owners"],"title":"TeamType"}},"title":"UserWorkspaceRoleDto"},"description":"Roles held by the user in this workspace."},"permissions":{"type":"array","items":{"type":"object","description":"A permission granted to the user in a workspace and the roles that grant it.","properties":{"permission":{"type":"string","description":"Permission name."},"roles":{"type":"array","items":{"type":"string"},"description":"Roles that grant the permission."}},"title":"UserWorkspacePermissionDto"},"description":"Effective permissions granted in this workspace."}},"title":"UserWorkspaceRolesDto"},"description":"Workspace access details for the user within the organization."}},"title":"ListUserRolesResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"}}}
diff --git a/platform-api-docs/docs/list-user-roles-in-organization.api.mdx b/platform-api-docs/docs/list-user-roles-in-organization.api.mdx
new file mode 100644
index 000000000..55cd34142
--- /dev/null
+++ b/platform-api-docs/docs/list-user-roles-in-organization.api.mdx
@@ -0,0 +1,66 @@
+---
+id: list-user-roles-in-organization
+title: "List user roles in organization"
+description: "Lists an organization member or collaborator's workspace roles and effective permissions across the organization identified by `orgId`."
+sidebar_label: "List user roles in organization"
+hide_title: true
+hide_table_of_contents: true
+api: eJzNWN1v20YM/1cO99INUOx26/bgp6VrOgTLtiAf6EMQrLREW9dKdwp5cpoJ+t8Hnj4s20rspBiwJ9sSj/yR/JFHutIelqxnN9rRkvVtpBPkmEzhjbN6ps8Me1ZglaMlWPMPyHOVYz5HUo5U7LIM5o7AO3rF6t7RFy4gRkUuQzmYKFwsMPZmhapAyg2zcZYVxOSYlU9xU7VJ0HqzMJio+YP65Gh5mnya6Ei7AimInCYtrmtGuhAzp/avgQod6QIIcvRI4lmlLeSoZzro0pE24lgBPtXb3g7VKFvmSCZeIyKBQXhXGsJEzzyVGGmOU8xBzyrtHwqxYqzHJZKO9MJRDr559PNbXddRD6VkpD1YxLv/AMOtHOfCWUaWEz+8fi0fW3H4XUc6dtaj9fIWiiIzcQjL9DOLSLVr1M0/Y+x3/DhW4uwrHmMQp6ZQCXowWcOVnj9HGa4wG7BowB0JQUHCB28aJ8TCGJJNqcam0Gd/oLa9+KNh/Fg+6qhL5yEJaIT/DDToxdmTsctRCghhlFvsFkrjTTCPOZhsv7oTEVOQJITM+3QuDLE/DOYHEVWHAM3gUJ1ncKBKWIEH2q/wOMgpk8MS1fXFmVo4elKxUG9MLdoyD/3y3oYEN0dCvaxboTTSr0cierSCkEM+6Iw3XqxKI5LOJj2jf9ZQ8P38vXcdjT525cIDpEAED9JaPOa8vz57HUdcYGwWJh6vuhAwCMW8W4B93b6sunoMjxVYr/8w9gz0QY59Or8hSschKAqYzdJiorwL5JFoKGMVDG4+iZu8Y1dS3PIXfHs0R+t3w/cY1x7zKmDZcO0yGLsK5/fpueyBwdaFvQWyo7qxiVmZpIRMR9oj5EOqfuTiYhNAHenG9yuE/FBC2FIqQTQ2d9ooZLE9QhF1n6INMQ9OGFbGpkjGY6IW5HIF4eRkE9ljVHoGEulPL7LdJWrb1tOJk5NKRIbJIVyWGUhM+YE95n+HJsPDFPUWh+3ketg/JINtX9k0GeYrlWIWxrEh5X1qBvNe8G/QLb6l0tZq1JLA+sPKrWlaodTCKWVGCm2ten+ZnK9hPLuLtCofCecApCBfg5o8nqE1mtE8nYwO2V34xtL1FBV41Ma6/0AcywjRTW7dVRrSc298auzO1bppcWN8v2jnUV3XIvN2bCJ9B4mSsRfZP2c0XU/KNzpHZlhiKIw9c2IjuJvOgQcnRI52kP84Mkt3e4uyzivIMnePSVDFGJdk/EPYUd4hENJx6VM9u7mVMT1HnzrZdZYYMMqSMNNT2dOmVdhl6qlEnKdVM3/W04aeoplW3fJTUqZnOvW+4Nl0CoWZxJkrkwnjHRJMjNu9H8IbdZ6BlzatfhV5dXx+qgVWh/pSgtwEbIi9j5lY1O1uIr/nQUhH7ZcP3QXw+d6HaBi7cOF4G+AWhZjdB1DcNTFyKyzsgDiwY9P5ocvtzBzM/rJ+UUdaItfYeTN58+anyevQ2hz7HAK72hVOKNwwvuk8ZnNH3gZdrUn7P1qq21x5/OqnRQbGhsmSwjLREK79YyDSs259DpyTB/0S29DuNtKpYy9HqmoOjNeU1bU8viuRhOW3kV4BmebCu6l0Yli+J3q2gIy3r9phxL67aAv5e3XAjj7qVdexrfTrFWSl/NKR/oIP/X8DsqG/CNQTy/oLwLSBrW/rSKcIiSy3N1X78jiOsfCDYzsdcKN5/HZypSMNm7W5VYtB+yikqmokrtwXtHXdI/TyWwDW9b+eXWUZ
+sidebar_class_name: "get api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Lists an organization member or collaborator's workspace roles and effective permissions across the organization identified by `orgId`.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/retrieve-permissions.ParamsDetails.json b/platform-api-docs/docs/retrieve-permissions.ParamsDetails.json
new file mode 100644
index 000000000..4661c0329
--- /dev/null
+++ b/platform-api-docs/docs/retrieve-permissions.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"orgId","in":"query","description":"Organization numeric identifier.","schema":{"type":"integer","format":"int64"}},{"name":"workspaceId","in":"query","description":"Workspace numeric identifier.","schema":{"type":"integer","format":"int64"}}]}
diff --git a/platform-api-docs/docs/retrieve-permissions.RequestSchema.json b/platform-api-docs/docs/retrieve-permissions.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/retrieve-permissions.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/retrieve-permissions.StatusCodes.json b/platform-api-docs/docs/retrieve-permissions.StatusCodes.json
new file mode 100644
index 000000000..813fa4c1d
--- /dev/null
+++ b/platform-api-docs/docs/retrieve-permissions.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","description":"Roles and operations available to the authenticated user by context.","properties":{"user":{"type":"object","properties":{"operations":{"type":"array","items":{"type":"string"},"description":"Operation identifiers available in this context."},"roles":{"type":"array","items":{"type":"string"},"description":"Role names held in this context."}},"title":"ListPermissionsResponse.OperationsAndRolesDto"},"organization":{"type":"object","properties":{"operations":{"type":"array","items":{"type":"string"},"description":"Operation identifiers available in this context."},"roles":{"type":"array","items":{"type":"string"},"description":"Role names held in this context."}},"title":"ListPermissionsResponse.OperationsAndRolesDto"},"workspace":{"type":"object","properties":{"operations":{"type":"array","items":{"type":"string"},"description":"Operation identifiers available in this context."},"roles":{"type":"array","items":{"type":"string"},"description":"Role names held in this context."}},"title":"ListPermissionsResponse.OperationsAndRolesDto"}},"title":"ListPermissionsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"}}}
diff --git a/platform-api-docs/docs/retrieve-permissions.api.mdx b/platform-api-docs/docs/retrieve-permissions.api.mdx
new file mode 100644
index 000000000..21accf508
--- /dev/null
+++ b/platform-api-docs/docs/retrieve-permissions.api.mdx
@@ -0,0 +1,66 @@
+---
+id: retrieve-permissions
+title: "Retrieve permissions"
+description: "Lists the roles and operations available to the authenticated user in the current user, organization, and workspace contexts."
+sidebar_label: "Retrieve permissions"
+hide_title: true
+hide_table_of_contents: true
+api: eJztVk1v2zAM/SsCz0bS7uvg09p9odiAFd2GHYocGJuJ1dqSS9HtMsP/faBiJ04TtFt32GWnxBKl9/hIimxBcBkgvYSauLIhWO8CzBLIKWRsa7HeQQqfbJBgpCDDvqRg0OXG18So+8HgLdoS5yUZ8dEKGynIic1QKDdNIDbWxZ2sYSYncS0xnpfo7M94TRJvvfN8HWrMyGTeCf2QMIEENlhnOaRwQcKWbul8RDmBGhkrEmJ1pwWHFUEKnpdnOSRg1Y2bhngF9537PCJhXFMR28zYXPkvLLHih6ygCiFtQVa1Xmud0JIYElh4rlDWS69eQNclG+yNL48x+L5x+u/hZwkwhdq7QEFPPDs60p97Ln+EBKLATnQX67rUYFnvpldBTdp9UD+/okz2yF88NSPmqyHG6mPNelzsmrUaHILetdoCjmyRGVViK1SN14OwdUvo9sI/XDISfexATFwbtly7BGIV/AWmamY0S4IpqMwPYHQJiJWS+uIbpfpFH93Jhng4cXmMwlvxijWuqv8iPlHETfH+V/BJCj5+ErpOrV4ceqBOMTdMNw0F+ZOXSo9YplwbWkUh4JK0mT0cvsFwX6+RD++YPe8xf37gad3E0XkxWJb+jvJ4VaCsYSur2J5OCZn4pJEC0suZvtoVSeG1vS0pckTdgmm90+QC8e3Q4RouIYVCpA7pdIq1nWSlb/JJoBtinFi/91R/iTvmvETRvmHeqL05OT8DJTDw+6JyrqUZs9yoo4hDU9LveTSCpP/zfuhIV3cS/bZu4ePxXsqehcI+RlDdtRmF3ljzALOYB7vOj12mCm0ZG+LCv95udAmocmuc48nx8cvJkS7WPkiFMY/6tj2MF2ZX+h2m7TYn//lw1IdFv6d1idapW1Gfts+ivemu8EF0uW3nGOgbl12ny+vpRHMrt0Ep55AusAz0gPe/MT0dJHhNq9F4dotlozag49Pvgz82OD2AvDucbfFn+sFWCcTKTKAgzHUauWz7oydZRrWMTu09Sjv1/OHdV0gAd4voXtHE24dX3K1Gd7ft2uKrvybXdTDwF/2GbtZ13S/jqyR5
+sidebar_class_name: "get api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Lists the roles and operations available to the authenticated user in the current user, organization, and workspace contexts.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/sidebar.ts b/platform-api-docs/docs/sidebar.ts
index aa1d5438a..28b6fe38a 100644
--- a/platform-api-docs/docs/sidebar.ts
+++ b/platform-api-docs/docs/sidebar.ts
@@ -748,6 +748,30 @@ const sidebar: SidebarsConfig = {
label: "Describe organization quotas",
className: "api-method get",
},
+ {
+ type: "doc",
+ id: "list-user-roles-in-organization",
+ label: "List user roles in organization",
+ className: "api-method get",
+ },
+ ],
+ },
+ {
+ type: "category",
+ label: "permissions",
+ items: [
+ {
+ type: "doc",
+ id: "retrieve-permissions",
+ label: "Retrieve permissions",
+ className: "api-method get",
+ },
+ {
+ type: "doc",
+ id: "check-permission",
+ label: "Check permission",
+ className: "api-method get",
+ },
],
},
{
@@ -882,6 +906,54 @@ const sidebar: SidebarsConfig = {
},
],
},
+ {
+ type: "category",
+ label: "roles",
+ items: [
+ {
+ type: "doc",
+ id: "list-roles",
+ label: "List roles",
+ className: "api-method get",
+ },
+ {
+ type: "doc",
+ id: "create-role",
+ label: "Create role",
+ className: "api-method post",
+ },
+ {
+ type: "doc",
+ id: "list-role-permissions",
+ label: "List role permissions",
+ className: "api-method get",
+ },
+ {
+ type: "doc",
+ id: "describe-role",
+ label: "Describe role",
+ className: "api-method get",
+ },
+ {
+ type: "doc",
+ id: "update-role",
+ label: "Update role",
+ className: "api-method put",
+ },
+ {
+ type: "doc",
+ id: "delete-role",
+ label: "Delete role",
+ className: "api-method delete",
+ },
+ {
+ type: "doc",
+ id: "validate-role-name",
+ label: "Validate role name",
+ className: "api-method get",
+ },
+ ],
+ },
{
type: "category",
label: "service-info",
diff --git a/platform-api-docs/docs/update-role.ParamsDetails.json b/platform-api-docs/docs/update-role.ParamsDetails.json
new file mode 100644
index 000000000..178f18516
--- /dev/null
+++ b/platform-api-docs/docs/update-role.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"roleName","in":"path","description":"Role name.","required":true,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}}]}
diff --git a/platform-api-docs/docs/update-role.RequestSchema.json b/platform-api-docs/docs/update-role.RequestSchema.json
new file mode 100644
index 000000000..1bdd6991d
--- /dev/null
+++ b/platform-api-docs/docs/update-role.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body","body":{"description":"Role update request","content":{"application/json":{"schema":{"type":"object","description":"Request payload for updating a custom role in an organization.","properties":{"name":{"type":"string","description":"Role name."},"description":{"type":"string","description":"Role description."},"permissions":{"type":"array","items":{"type":"string"},"description":"List of permission names assigned to the role."}},"title":"UpdateRoleRequest"}}},"required":true}}
diff --git a/platform-api-docs/docs/update-role.StatusCodes.json b/platform-api-docs/docs/update-role.StatusCodes.json
new file mode 100644
index 000000000..6c90e5ce2
--- /dev/null
+++ b/platform-api-docs/docs/update-role.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"204":{"description":"OK - No content"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"},"404":{"description":"Role not found","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"409":{"description":"Duplicate role name","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}}}}
diff --git a/platform-api-docs/docs/update-role.api.mdx b/platform-api-docs/docs/update-role.api.mdx
new file mode 100644
index 000000000..762ff7b70
--- /dev/null
+++ b/platform-api-docs/docs/update-role.api.mdx
@@ -0,0 +1,66 @@
+---
+id: update-role
+title: "Update role"
+description: "Updates the details of the role identified by `roleName` in the organization identified by `orgId`."
+sidebar_label: "Update role"
+hide_title: true
+hide_table_of_contents: true
+api: eJzNVt9v3DYM/lcEPq2Ae5ds2YD5aUnXAcGGNkiTp+CA8GzenVJZciQ66c3w/15Qsn0/mwV9GPpmSxT58SP1iS0wLgPkd+CdoQCzDEoKhdc1a2chh9u6RKageEWqJEZtgnKL+CsnlC7Jsl5oKtV8re5l7QNWdK+0jUbOL9Hqf1Hc7Rs7v7ws7yeQgavJR5PLcox57QxBBjV6rIjJC8oWLFYEOQxxIAMtMGvkFexjFw9KDkgIT4+N9lRCzr6hDEKxogohb4HXtbgM7LVdQtdlY5QIcAjx2JBfH8T4uJ2fbSryutjk6V8VWVumJXnIYOF8hZyWfjuDrpul4xT4wpVrOXMkxSbypXpDyKBwlsmymGNdG11EeNOHIGfaQwBu/kAFH/KXHKoa18ZhqRbOp1jaLhWqognsqr4NrEK7U2zJvPZSWNYUJFgidZ/vF4rW7e296ujWUvRQk690CNrZsOUBvUcppmaqwpEm2Hf9jw4sfb/xFjEGhSHopaVSsRsvxUSaCFizoZ1u7vmETrZ3uyIuhNrZkLj6+eTssNgf/1Zv1QenhvJ2GZydnBzaXWD5Pc2wQXQHFYWASxI92O+R3aIOhsfu0UjBe++dv+7zk/Qj8l+OZDjogLKOFRrjnqlMeR7hI7WKY7VwjS1/5FR/PwT/Z5MA9jpqk5j9kBl0GQQqGq95HTX4gtCTP294BfndTDSqIl45ke66iVFFjXOYxjdl2g5i3YE48k+DljfeQA4r5jrk0ynWelIY15STQI/kcaLdwQ3/FHfUlUEWqVTvxF6dX12CoBhAfhKWUsbbUMekJSL0Oiz/82gEWf/x1yDCD88cmRH2rzcq/P4LVrWhjaR9S4/G5R0NuhvWZ528LAsXkfXk9wlKRv+VuzCpCwq9sXQOFrFzdnndZpMq1CY+Lwv3x2ajy0CKkuKcTk5Pf52cRO10gSu0W5ne9k9Nepv31Hls3v9paujLyfSFp7VBbQVzTL7tW3AYazLIx4lhlsHKBZbNtp1joFtvuk6W0wsvnVnqgHMjt2uBJtALmf503V/EN+oVo8BRxJ9pvTVrPKFpxCZ29BN6LUC+H9TODHQ0/PAi2vV29AHWSFsn7boiLMlHNGn7XYr59kacbI4faJcMVenEeVFQzS/abgvK1e2NXMx++KlcGac/fJa5Cp8TUhcpiPc9rrVg0C6bqHSQXMo1xl0V2Lv1MamjXLRtsrhxn8l23UgNy7/w0nVfAbzC6Gg=
+sidebar_class_name: "put api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Updates the details of the role identified by `roleName` in the organization identified by `orgId`.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/docs/validate-role-name.ParamsDetails.json b/platform-api-docs/docs/validate-role-name.ParamsDetails.json
new file mode 100644
index 000000000..dff5eb1c4
--- /dev/null
+++ b/platform-api-docs/docs/validate-role-name.ParamsDetails.json
@@ -0,0 +1 @@
+{"parameters":[{"name":"name","in":"query","description":"Role name to validate.","required":true,"schema":{"type":"string"}},{"name":"orgId","in":"query","description":"Organization numeric identifier.","required":true,"schema":{"type":"integer","format":"int64"}}]}
diff --git a/platform-api-docs/docs/validate-role-name.RequestSchema.json b/platform-api-docs/docs/validate-role-name.RequestSchema.json
new file mode 100644
index 000000000..188a349c4
--- /dev/null
+++ b/platform-api-docs/docs/validate-role-name.RequestSchema.json
@@ -0,0 +1 @@
+{"title":"Body"}
diff --git a/platform-api-docs/docs/validate-role-name.StatusCodes.json b/platform-api-docs/docs/validate-role-name.StatusCodes.json
new file mode 100644
index 000000000..91955c038
--- /dev/null
+++ b/platform-api-docs/docs/validate-role-name.StatusCodes.json
@@ -0,0 +1 @@
+{"responses":{"204":{"description":"OK - No content"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}},"403":{"description":"Operation not allowed"},"409":{"description":"Role name already exists","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"title":"ErrorResponse"}}}}}}
diff --git a/platform-api-docs/docs/validate-role-name.api.mdx b/platform-api-docs/docs/validate-role-name.api.mdx
new file mode 100644
index 000000000..414da1359
--- /dev/null
+++ b/platform-api-docs/docs/validate-role-name.api.mdx
@@ -0,0 +1,66 @@
+---
+id: validate-role-name
+title: "Validate role name"
+description: "Confirms that the given role name is valid and available within the organization identified by `orgId`."
+sidebar_label: "Validate role name"
+hide_title: true
+hide_table_of_contents: true
+api: eJzNVE1v1DAQ/SvWnEAKuy0UJHKirQqqkAoqhUu1UmeT2Y1bx07tyZYl8n9H4yTd7QcFcUCcEtvjmffGb14HjMsA+Tl4ZyjALIOSQuF1w9pZyOHQ2YX2dVBcISuuSC31iqyScGWxJqWDWqHRpUJbKlyhNjg3pG40V9qmG84v0eofKCmVLsmyXmgq1XytLpxfHpcXE8jANeRTyHEJOXyTlMh06gydYE2QQYMea2LygrcDKQ55/8lAC9jrlvwa7lM4vYXKroeKTFLR03WrPZWQs28pg1BUVCPkHfC6kdyBvbZLiDG7LZfwPl3v0zZd29bkdbGh7f+osrZMS/KQwcL5GrnferMHMc7kemicDRTkxsudPfncw/BRvVAnThXOMlmGmMHezs7DuAMslYChwJDBGJ13gE1jdJE4TC+DxHZbKDf4z6GmEHBJIp0BvJtfUiH5Gi+PyroHOgY+1l9gzUa2jrx3/nTgBzHGhPzVIwxHuSjrWKEx7obKnufbh9EbDaDxhOVa0XcdOPyvpGMGgYrWa14nsR8QevL7LVeQn89EAzVx5WRSlpSqohzBNI3xdFQ5SBq/Gkem9QZyqJibkE+n2OhJYVxbTgJdk8eJdg+0/CWdqM8GWYSoDiVe7X8+BsEwQvwiPer5bgO9pSwVYVC5rOcpCLLh5/0o8csbTn3RduHS9aE/Awop+zuAQlcXFIZgeVws0uPeJb9NmWrUJk3Ywr3bHMQMpHN9nd3J7u7ryY5sNi5wjUkcgymMZrVxxfs4u43M/qGlDu1n+s7TxqC2Aj/1oRsEM/p+BreSmWVQucBy1nVzDPTVmxhlu7c7EVKpgyAqIV+gCfQE2Wenw9Q8V7/04UdhXtF64+4rNK2EgDjxXxX/A1N+Asbo+hscM1l4LUDSRGZQEZbkU3v6S/tFQQ1v3XpgL3fm+MPRGWSAdyfn3qSk7MMR2vVW7q7rI87cFdkYYUTOsoY4izH+BAaDuuE=
+sidebar_class_name: "get api-method"
+info_path: platform-api//seqera-api
+custom_edit_url: null
+---
+
+import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint";
+import ParamsDetails from "@theme/ParamsDetails";
+import RequestSchema from "@theme/RequestSchema";
+import StatusCodes from "@theme/StatusCodes";
+import OperationTabs from "@theme/OperationTabs";
+import TabItem from "@theme/TabItem";
+import Heading from "@theme/Heading";
+import Translate from "@docusaurus/Translate";
+
+
+
+
+
+
+
+
+
+
+Confirms that the given role name is valid and available within the organization identified by `orgId`.
+
+
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/platform-api-docs/scripts/specs/seqera-api-latest-decorated.yml b/platform-api-docs/scripts/specs/seqera-api-latest-decorated.yml
index fcb2e80a6..9272cd43f 100644
--- a/platform-api-docs/scripts/specs/seqera-api-latest-decorated.yml
+++ b/platform-api-docs/scripts/specs/seqera-api-latest-decorated.yml
@@ -9515,6 +9515,495 @@ paths:
description: Operation not allowed
security:
- BearerAuth: []
+ /orgs/{orgId}/users/{userId}/roles:
+ get:
+ tags:
+ - orgs
+ summary: List user roles in organization
+ description: Lists an organization member or collaborator's workspace roles
+ and effective permissions across the organization identified by `orgId`.
+ operationId: ListUserRolesInOrganization
+ parameters:
+ - name: orgId
+ in: path
+ description: Organization numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: userId
+ in: path
+ description: User numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ListUserRolesResponse'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ security:
+ - BearerAuth: []
+ /permissions:
+ get:
+ tags:
+ - permissions
+ summary: Retrieve permissions
+ description: Lists the roles and operations available to the authenticated
+ user in a personal workspace context or an organization workspace context.
+ operationId: RetrievePermissions
+ parameters:
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ schema:
+ type: integer
+ format: int64
+ - name: workspaceId
+ in: query
+ description: Workspace numeric identifier.
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ListPermissionsResponse'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ security:
+ - BearerAuth: []
+ /permissions/check:
+ get:
+ tags:
+ - permissions
+ summary: Check permission
+ description: Checks whether the authenticated user is allowed to perform the
+ given operation in a personal workspace context or an organization workspace
+ context. Append `?operationId=` to specify the operation identifier
+ to check. Use [Retrieve permissions](https://docs.seqera.io/platform-api/retrieve-permissions)
+ to retrieve the available operation identifiers for the current context.
+ operationId: CheckPermission
+ parameters:
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ schema:
+ type: integer
+ format: int64
+ - name: workspaceId
+ in: query
+ description: Workspace numeric identifier.
+ schema:
+ type: integer
+ format: int64
+ - name: operationId
+ in: query
+ description: Operation identifier to check in the selected context.
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CheckPermissionResponse'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ security:
+ - BearerAuth: []
+ /permissions/features:
+ get:
+ tags:
+ - permissions
+ summary: List available features
+ description: Lists the available features enabled for the authenticated user
+ in a personal workspace context or an organization workspace context.
+ operationId: ListAvailableFeatures
+ parameters:
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ schema:
+ type: integer
+ format: int64
+ - name: workspaceId
+ in: query
+ description: Workspace numeric identifier.
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ListFeaturesResponse'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ security:
+ - BearerAuth: []
+ /roles:
+ get:
+ tags:
+ - roles
+ summary: List roles
+ description: Lists predefined and custom roles available in the organization
+ identified by `orgId`.
+ operationId: ListRoles
+ parameters:
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: max
+ in: query
+ description: 'Maximum number of results to return. Default: `50`. Maximum:
+ `100`.'
+ schema:
+ type: integer
+ format: int32
+ - name: offset
+ in: query
+ description: 'Number of results to skip for pagination. Default: `0`.'
+ schema:
+ type: integer
+ format: int32
+ - name: name
+ in: query
+ description: Role name search filter.
+ schema:
+ type: string
+ - name: type
+ in: query
+ description: Role type filter.
+ schema:
+ type: string
+ enum:
+ - predefined
+ - custom
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ListRolesResponse'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ security:
+ - BearerAuth: []
+ post:
+ tags:
+ - roles
+ summary: Create role
+ description: Creates a custom role in the organization identified by `orgId`.
+ operationId: CreateRole
+ parameters:
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ requestBody:
+ description: Role create request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateRoleRequest'
+ required: true
+ responses:
+ '201':
+ description: Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateRoleResponse'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ '409':
+ description: Duplicate role name
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - BearerAuth: []
+ /roles/permissions:
+ get:
+ tags:
+ - roles
+ summary: List role permissions
+ description: Lists the available role permissions for assignment in the organization
+ identified by `orgId`.
+ operationId: ListRolePermissions
+ parameters:
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Permission name search filter.
+ schema:
+ type: string
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ListRolePermissionsResponse'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ '404':
+ description: Not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - BearerAuth: []
+ /roles/{roleName}:
+ get:
+ tags:
+ - roles
+ summary: Describe role
+ description: Retrieves the details of the role identified by `roleName` in
+ the organization identified by `orgId`.
+ operationId: DescribeRole
+ parameters:
+ - name: roleName
+ in: path
+ description: Role name.
+ required: true
+ schema:
+ type: string
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DescribeRoleResponse'
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ '404':
+ description: Role not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - BearerAuth: []
+ put:
+ tags:
+ - roles
+ summary: Update role
+ description: Updates the details of the role identified by `roleName` in the
+ organization identified by `orgId`.
+ operationId: UpdateRole
+ parameters:
+ - name: roleName
+ in: path
+ description: Role name.
+ required: true
+ schema:
+ type: string
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ requestBody:
+ description: Role update request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateRoleRequest'
+ required: true
+ responses:
+ '204':
+ description: OK - No content
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ '404':
+ description: Role not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '409':
+ description: Duplicate role name
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - BearerAuth: []
+ delete:
+ tags:
+ - roles
+ summary: Delete role
+ description: Deletes the custom role identified by `roleName` in the organization
+ identified by `orgId`. Predefined roles cannot be deleted.
+ operationId: DeleteRole
+ parameters:
+ - name: roleName
+ in: path
+ description: Role name.
+ required: true
+ schema:
+ type: string
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '204':
+ description: OK - No content
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ '404':
+ description: Role not found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - BearerAuth: []
+ /roles/validate:
+ get:
+ tags:
+ - roles
+ summary: Validate role name
+ description: Confirms that the given role name is valid and available within
+ the organization identified by `orgId`.
+ operationId: ValidateRoleName
+ parameters:
+ - name: name
+ in: query
+ description: Role name to validate.
+ required: true
+ schema:
+ type: string
+ - name: orgId
+ in: query
+ description: Organization numeric identifier.
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ '204':
+ description: OK - No content
+ '400':
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ '403':
+ description: Operation not allowed
+ '409':
+ description: Role name already exists
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ security:
+ - BearerAuth: []
components:
schemas:
AbstractGridConfig:
@@ -17291,6 +17780,262 @@ components:
nullable: true
description: Optional relative path within the data-link root to mount.
Can be `null` to mount the data-link root.
+ CheckPermissionResponse:
+ type: object
+ description: Result of checking whether the authenticated user can perform a
+ given operation in the selected context.
+ properties:
+ authorized:
+ type: boolean
+ description: Whether the authenticated user is authorized to perform the
+ requested operation.
+ CreateRoleRequest:
+ type: object
+ description: Request payload for creating a custom role in an organization.
+ properties:
+ name:
+ type: string
+ description: Role name.
+ description:
+ type: string
+ description: Role description.
+ permissions:
+ type: array
+ items:
+ type: string
+ description: List of permission names assigned to the role.
+ CreateRoleResponse:
+ type: object
+ description: Created role details.
+ properties:
+ name:
+ type: string
+ description: Role name.
+ description:
+ type: string
+ description: Role description.
+ permissions:
+ type: array
+ items:
+ type: string
+ description: List of permission names assigned to the role.
+ DescribeRoleResponse:
+ type: object
+ description: Role description response.
+ properties:
+ role:
+ $ref: '#/components/schemas/RoleDto'
+ FeatureId:
+ type: string
+ description: Feature identifier.
+ enum:
+ - DATA_EXPLORER
+ - DATA_STUDIO
+ - MANAGED_IDENTITY
+ - SEQERA_COMPUTE
+ - DYNAMIC_RESOURCE_LABELS
+ - CONTAINERS
+ - METERING
+ - SEQERA_COMPUTE_ENABLE_CE_TYPE_CHOICE
+ - PIPELINE_VERSIONING
+ - STUDIO_METRICS
+ - DATA_STUDIO_CONNECT_IFRAME
+ - DATA_STUDIO_SSH_ENABLED
+ - SSH_KEYS_MANAGEMENT
+ - SEQERA_AI_DEBUG_BUTTON
+ - CUSTOM_ROLES
+ - CE_FORMS_V2
+ - AUDIT_LOG_V2
+ ListFeaturesResponse:
+ type: object
+ description: Features enabled in the selected context.
+ properties:
+ features:
+ type: array
+ items:
+ $ref: '#/components/schemas/FeatureId'
+ description: Feature identifiers enabled in the selected context.
+ ListPermissionsResponse:
+ type: object
+ description: Roles and operations available to the authenticated user by context.
+ properties:
+ user:
+ $ref: '#/components/schemas/ListPermissionsResponse.OperationsAndRolesDto'
+ organization:
+ $ref: '#/components/schemas/ListPermissionsResponse.OperationsAndRolesDto'
+ workspace:
+ $ref: '#/components/schemas/ListPermissionsResponse.OperationsAndRolesDto'
+ ListPermissionsResponse.OperationsAndRolesDto:
+ type: object
+ properties:
+ operations:
+ type: array
+ items:
+ type: string
+ description: Operation identifiers available in this context.
+ roles:
+ type: array
+ items:
+ type: string
+ description: Role names held in this context.
+ ListRolePermissionsResponse:
+ type: object
+ description: Available role permissions.
+ properties:
+ permissions:
+ type: array
+ items:
+ $ref: '#/components/schemas/RolePermissionResponseDto'
+ description: Permission definitions available for assignment to roles.
+ ListRolesResponse:
+ type: object
+ description: Paginated role list response.
+ properties:
+ roles:
+ type: array
+ items:
+ $ref: '#/components/schemas/ListRolesResponse.RoleInfo'
+ description: Roles matching the query.
+ totalSize:
+ type: integer
+ format: int32
+ description: Total number of matching roles.
+ ListRolesResponse.RoleInfo:
+ type: object
+ properties:
+ name:
+ type: string
+ description: Role name.
+ description:
+ type: string
+ description: Role description.
+ isPredefined:
+ type: boolean
+ description: Whether the role is predefined by the system.
+ ListUserRolesResponse:
+ type: object
+ description: A user's organization membership details and workspace-level roles
+ and permissions.
+ properties:
+ user:
+ $ref: '#/components/schemas/MemberDbDto'
+ userWorkspaces:
+ type: array
+ items:
+ $ref: '#/components/schemas/UserWorkspaceRolesDto'
+ description: Workspace access details for the user within the organization.
+ RoleDto:
+ type: object
+ description: Role details with assigned permissions.
+ properties:
+ name:
+ type: string
+ description: Role name.
+ description:
+ type: string
+ description: Role description.
+ isPredefined:
+ type: boolean
+ description: Whether the role is predefined by the system.
+ permissions:
+ type: array
+ items:
+ type: string
+ description: List of permission names assigned to the role.
+ RolePermissionResponseDto:
+ type: object
+ description: Metadata for a role permission.
+ properties:
+ name:
+ type: string
+ description: Permission name.
+ category:
+ type: string
+ description: Permission category.
+ TeamType:
+ type: string
+ description: Team type.
+ enum:
+ - regular
+ - system_owners
+ UpdateRoleRequest:
+ type: object
+ description: Request payload for updating a custom role in an organization.
+ properties:
+ name:
+ type: string
+ description: Role name.
+ description:
+ type: string
+ description: Role description.
+ permissions:
+ type: array
+ items:
+ type: string
+ description: List of permission names assigned to the role.
+ UserWorkspacePermissionDto:
+ type: object
+ description: A permission granted to the user in a workspace and the roles
+ that grant it.
+ properties:
+ permission:
+ type: string
+ description: Permission name.
+ roles:
+ type: array
+ items:
+ type: string
+ description: Roles that grant the permission.
+ UserWorkspaceRoleDto:
+ type: object
+ description: A role assigned to the user in a workspace and the source of that
+ assignment.
+ properties:
+ role:
+ type: string
+ description: Workspace role name.
+ roleSourceType:
+ $ref: '#/components/schemas/WspRoleSourceType'
+ sourceTeamId:
+ type: integer
+ format: int64
+ nullable: true
+ description: Source team numeric identifier when the role is inherited
+ from a team.
+ sourceTeamName:
+ type: string
+ nullable: true
+ description: Source team name when the role is inherited from a team.
+ sourceTeamType:
+ $ref: '#/components/schemas/TeamType'
+ nullable: true
+ UserWorkspaceRolesDto:
+ type: object
+ description: Workspace-specific roles and permissions for a user.
+ properties:
+ workspaceId:
+ type: integer
+ format: int64
+ description: Workspace numeric identifier.
+ workspaceName:
+ type: string
+ description: Workspace name.
+ roles:
+ type: array
+ items:
+ $ref: '#/components/schemas/UserWorkspaceRoleDto'
+ description: Roles held by the user in this workspace.
+ permissions:
+ type: array
+ items:
+ $ref: '#/components/schemas/UserWorkspacePermissionDto'
+ description: Effective permissions granted in this workspace.
+ WspRoleSourceType:
+ type: string
+ description: Source of a workspace role assignment.
+ enum:
+ - individual
+ - team
securitySchemes:
BearerAuth:
type: http
@@ -17319,12 +18064,16 @@ tags:
description: Workflow launch events
- name: orgs
description: Organizations
+- name: permissions
+ description: Frontend-visible permissions
- name: pipelines
description: Pipelines
- name: pipeline-secrets
description: Pipeline secrets in a user or workspace context
- name: platforms
description: Computing platforms
+- name: roles
+ description: Custom and predefined organization roles
- name: service-info
description: Seqera Platform API service information
- name: studios