roles
The methods of pd.roles. Inputs and outputs are described in Conventions; every method can also fail as described in Errors.
Methods
pd.roles.list(input, init?)
List a workspace's roles
GET /api/workspaces/{workspaceId}/roles
Needs roles.read. A member's permissions are the union of the permissions of the roles they hold, and an API key acts with the permissions of the one role it carries. Every workspace is provisioned with six system roles (isSystem): Owner (every permission), Admin (every permission except workspace.delete and credits.adjust), Editor (writes, reviews, approves and publishes content), Writer (writes and generates content, cannot approve or publish), SEO Manager (edits metadata, reviews, approves and rejects) and Viewer (read-only, plus commenting; the default role). Administrators can edit what a system role grants, so read permissions rather than assuming. Custom roles are created with POST /api/workspaces/{workspaceId}/roles.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
init |
init | { signal?: AbortSignal; timeoutMs?: number } |
no | The second argument: signal aborts the call, timeoutMs overrides the client's per-attempt timeout. |
Returns 200 OK
| Field | Type | Required | Description |
|---|---|---|---|
roles |
object[] |
yes | Every role of the workspace, system and custom. |
roles[].id |
string (uuid) |
yes | Id of the role. |
roles[].name |
string |
yes | Name of the role, unique in the workspace. |
roles[].description |
string |
yes | What the role is for; empty when none was given. |
roles[].isSystem |
boolean |
yes | true for the roles every workspace is provisioned with (Owner, Admin, Editor, Writer, SEO Manager, Viewer): they cannot be renamed or deleted, but their permissions can be edited. false for custom roles. |
roles[].isDefault |
boolean |
yes | true for the role given to a member added without roles (Viewer among the system roles). |
roles[].permissions |
string[] |
yes | Permission keys the role grants, resource.action, in no guaranteed order. |
Errors 400 invalid input, 401 missing or invalid key, 403 the key's roles lack the permission, 404 not found, 429 rate limited or out of quota. See Errors.
Example
import { PrismDraft } from "@prism-draft/sdk";
const pd = new PrismDraft({ apiKey: process.env.PRISMDRAFT_API_KEY! });
const result = await pd.roles.list({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);
pd.roles.create(input, init?)
Create a role
POST /api/workspaces/{workspaceId}/roles
Needs roles.create. Creates a custom role (isSystem and isDefault are false) granting exactly the permissions sent, which must all be permissions the caller holds: 403 FORBIDDEN otherwise, listing the others in details.permissions, so nobody can create a role stronger than themselves. Roles are then given to members with PATCH /api/workspaces/{workspaceId}/members/{memberId} or to API keys. Records a roles.created audit entry and answers 201.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
body |
body | object |
yes | |
body.name |
body | string |
yes | Name of the role, 1 to 60 characters, unique among the workspace's roles: a name already in use answers 409 CONFLICT with details.reason name_taken. |
body.description |
body | string |
no | What the role is for, up to 500 characters. Empty when omitted. |
body.permissions |
body | string[] |
no | Permission keys the role grants. A key not in the catalog answers 400 INVALID_REQUEST, listing the unknown ones in details.permissions. A key the caller does not hold answers 403 FORBIDDEN, listing those in details.permissions. Empty or omitted: a role that grants nothing. Default: []. |
init |
init | { signal?: AbortSignal; timeoutMs?: number } |
no | The second argument: signal aborts the call, timeoutMs overrides the client's per-attempt timeout. |
Returns 201 Created
| Field | Type | Required | Description |
|---|---|---|---|
roleId |
string (uuid) |
yes | Id of the new custom role. |
Errors 400 invalid input, 401 missing or invalid key, 403 the key's roles lack the permission, 404 not found, 429 rate limited or out of quota. See Errors.
Example
import { PrismDraft } from "@prism-draft/sdk";
const pd = new PrismDraft({ apiKey: process.env.PRISMDRAFT_API_KEY! });
const result = await pd.roles.create({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
body: {
name: "example",
},
});
console.log(result);
pd.roles.update(input, init?)
Update a role's name, description or permissions
PATCH /api/workspaces/{workspaceId}/roles/{roleId}
Needs roles.update. Only the fields sent change. A change to permissions takes effect at once for every member who holds the role and every API key that carries it. System roles can have their permissions and description edited but not their name. 409 CONFLICT (details.reason name_taken) when the new name is another role's. Changing permissions needs the caller to hold every permission of the role as it is now and every permission sent: otherwise 403 FORBIDDEN, listing the others in details.permissions, so a role stronger than the caller cannot be cut down or rewritten by it. Edits of the name or description alone are not held to this. The Owner role always holds every permission: a permissions list that leaves one out answers 403 FORBIDDEN with details.reason owner_role_fixed, and adding permissions is allowed. Records a roles.updated audit entry listing the fields sent.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
roleId |
path | string (uuid) |
yes | Id of a role of this workspace, as id in GET .../roles. A role of another workspace answers 404 RESOURCE_NOT_FOUND. |
body |
body | object |
no | |
body.name |
body | string |
no | New name, 1 to 60 characters. A system role cannot be renamed: sending a different name answers 403 FORBIDDEN. A name another role of the workspace has answers 409 CONFLICT with details.reason name_taken. Unchanged when omitted. |
body.description |
body | string |
no | New description, up to 500 characters. Unchanged when omitted. |
body.permissions |
body | string[] |
no | Permission keys the role should grant from now on. They replace the current grants entirely, so send the complete list. A key not in the catalog answers 400 INVALID_REQUEST. A key the caller does not hold answers 403 FORBIDDEN, and so does editing the permissions of a role that holds one the caller lacks, even to a smaller set. Unchanged when omitted. |
init |
init | { signal?: AbortSignal; timeoutMs?: number } |
no | The second argument: signal aborts the call, timeoutMs overrides the client's per-attempt timeout. |
Returns 200 OK
| Field | Type | Required | Description |
|---|---|---|---|
ok |
true |
yes | Always true: the change was made. A failure answers an error. |
Errors 400 invalid input, 401 missing or invalid key, 403 the key's roles lack the permission, 404 not found, 429 rate limited or out of quota. See Errors.
Example
import { PrismDraft } from "@prism-draft/sdk";
const pd = new PrismDraft({ apiKey: process.env.PRISMDRAFT_API_KEY! });
const result = await pd.roles.update({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
roleId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);
pd.roles.delete(input, init?)
Delete a role
DELETE /api/workspaces/{workspaceId}/roles/{roleId}
Needs roles.delete. Deletes a custom role; a system role answers 403 FORBIDDEN, and so does a role that holds a permission the caller lacks (details.permissions lists them), so nobody can strip a power they do not have. Members who held it lose it, and so lose its permissions, with no replacement role assigned. Pending invitations that list it skip it when accepted. While an active API key (not revoked, not expired) carries the role it answers 409 CONFLICT with details.reason role_in_use and details.apiKeys, the number of those keys: revoke them first, or let them expire. Revoked and expired keys that carried it stay listed with roleId null, can no longer be used, and keep their place in the audit trail. A role used as a project role (projects.addMember, projects.setMemberRole) is removed from those project members: they stay on the project with roleId null, so their workspace roles apply there without narrowing. Records a roles.deleted audit entry, whose detachedApiKeys and detachedProjectMembers count the keys and the project members.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
roleId |
path | string (uuid) |
yes | Id of a role of this workspace, as id in GET .../roles. A role of another workspace answers 404 RESOURCE_NOT_FOUND. |
init |
init | { signal?: AbortSignal; timeoutMs?: number } |
no | The second argument: signal aborts the call, timeoutMs overrides the client's per-attempt timeout. |
Returns 200 OK
| Field | Type | Required | Description |
|---|---|---|---|
ok |
true |
yes | Always true: the change was made. A failure answers an error. |
Errors 400 invalid input, 401 missing or invalid key, 403 the key's roles lack the permission, 404 not found, 429 rate limited or out of quota. See Errors.
Example
import { PrismDraft } from "@prism-draft/sdk";
const pd = new PrismDraft({ apiKey: process.env.PRISMDRAFT_API_KEY! });
const result = await pd.roles.delete({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
roleId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);
pd.roles.duplicate(input, init?)
Duplicate a role under a new name
POST /api/workspaces/{workspaceId}/roles/{roleId}/duplicate
Needs roles.create. Creates a custom role with the same permissions as the source (system or custom), which must all be permissions the caller holds (403 FORBIDDEN otherwise), and the description Copy of <source name>; members and API keys that hold the source do not get the copy. Records a roles.created audit entry naming the source, and answers 201.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
roleId |
path | string (uuid) |
yes | Id of a role of this workspace, as id in GET .../roles. A role of another workspace answers 404 RESOURCE_NOT_FOUND. |
body |
body | object |
yes | |
body.name |
body | string |
yes | Name of the copy, 1 to 60 characters, unique among the workspace's roles (409 CONFLICT with details.reason name_taken when taken). |
init |
init | { signal?: AbortSignal; timeoutMs?: number } |
no | The second argument: signal aborts the call, timeoutMs overrides the client's per-attempt timeout. |
Returns 201 Created
| Field | Type | Required | Description |
|---|---|---|---|
roleId |
string (uuid) |
yes | Id of the new custom role. |
Errors 400 invalid input, 401 missing or invalid key, 403 the key's roles lack the permission, 404 not found, 429 rate limited or out of quota. See Errors.
Example
import { PrismDraft } from "@prism-draft/sdk";
const pd = new PrismDraft({ apiKey: process.env.PRISMDRAFT_API_KEY! });
const result = await pd.roles.duplicate({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
roleId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
body: {
name: "example",
},
});
console.log(result);