PrismDraft SDK

workspaces

The methods of pd.workspaces. Inputs and outputs are described in Conventions; every method can also fail as described in Errors.

Methods

pd.workspaces.list(init?)

List the workspaces the caller belongs to

GET /api/workspaces

Newest first, each with the caller's own memberId. Needs a signed-in user, or an API key created by one; no permission is checked since the list only holds workspaces the user is a member of.

Input

Name In Type Required Description
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
workspaces object[] yes The workspaces the caller is a member of, newest first.
workspaces[].id string (uuid) yes Id of the workspace, used in every /api/workspaces/{workspaceId} route.
workspaces[].name string yes Display name of the workspace.
workspaces[].slug string yes URL-safe identifier, unique across all workspaces.
workspaces[].iconUrl string | null yes Address of the workspace's icon, which the first website set up in it provides; null until then.
workspaces[].memberId string (uuid) yes Id of the caller's membership in this workspace (memberId in GET .../members).
workspaces[].createdAt string (date-time) yes When the workspace was created, as an ISO 8601 timestamp.

Errors 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.workspaces.list();
console.log(result);

pd.workspaces.create(input, init?)

Create a workspace

POST /api/workspaces

Any signed-in user may create a workspace; no permission is needed. In one transaction it provisions the six system roles (Owner, Admin, Editor, Writer, SEO Manager, Viewer), makes the caller its Owner, creates an empty credit wallet and applies the free plan's quotas. The caller's welcome credits are granted with it, once per user and only when their email address is verified. Records workspace.created (and credits.granted) audit entries and answers 201.

Input

Name In Type Required Description
body body object yes
body.name body string yes Display name of the workspace, 1 to 120 characters.
body.slug body string no Wanted URL slug, 1 to 120 characters, normalised to lowercase words joined by hyphens. Taken from name when omitted. Slugs are unique across all workspaces: when it is taken, a short random suffix is appended rather than the call failing. Cannot be changed afterwards.
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
workspace object yes The workspace as created, with the ids of what was provisioned alongside it.
workspace.id string (uuid) yes Id of the new workspace.
workspace.name string yes Display name of the workspace, as sent.
workspace.slug string yes The slug the workspace got: the one sent or the one derived from name, with a short random suffix when that was taken.
workspace.ownerMemberId string (uuid) yes The creator's membership, holding the Owner role.
workspace.ownerRoleId string (uuid) yes Id of the workspace's Owner role, which the creator's membership holds.
workspace.walletId string (uuid) yes Id of the workspace's credit wallet, created empty and topped up with the welcome credits when the creator qualifies for them.

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.workspaces.create({
  body: {
    name: "example",
  },
});
console.log(result);

pd.workspaces.get(input, init?)

Read a workspace, the caller's permissions in it, and the server's features

GET /api/workspaces/{workspaceId}

Needs workspace.read. permissions lists what the caller can do here, so a client can decide what to offer, and features lists the server's enabled feature flags: a client must not offer a capability whose flag is absent. A caller who is not a member gets 404 RESOURCE_NOT_FOUND.

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
workspace object yes The workspace record: id, name, slug, free-form settings, icon and timestamps. The caller's permissions and the server's feature flags are alongside it.
workspace.id string (uuid) yes Id of the workspace.
workspace.name string yes Display name of the workspace, 1 to 120 characters.
workspace.slug string yes URL-safe identifier, unique across all workspaces; fixed at creation.
workspace.settings Record<string, unknown> yes Free-form object stored as sent through PATCH /api/workspaces/{workspaceId}; {} until then. The server does not read any key of it.
workspace.iconUrl string | null yes Address of the workspace's icon, which the first website set up in it provides; null until then.
workspace.rbacVersion integer yes Version of the platform's default roles and permissions the workspace was provisioned with. Workspaces created before the platform revised them keep their older number until their system roles are migrated. Read-only: no request sets it.
workspace.createdAt string (date-time) yes When the workspace was created, as an ISO 8601 timestamp.
workspace.updatedAt string (date-time) yes When the workspace row last changed, as an ISO 8601 timestamp.
permissions string[] yes The caller's effective permission keys in this workspace (resource.action, as listed by GET /api/permissions), sorted: the union of their roles'. For an API key, those of its role.
features string[] yes The feature flags switched on in the server, sorted; a client must not claim others.

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.workspaces.get({
  workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);

pd.workspaces.update(input, init?)

Update a workspace

PATCH /api/workspaces/{workspaceId}

Needs workspace.update. Only the fields sent change; the slug cannot be changed. settings replaces the stored object as a whole rather than merging. Records a workspace.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.
body body object no
body.name body string no New display name, 1 to 120 characters. Unchanged when omitted.
body.settings body Record<string, unknown> no Free-form settings object. It replaces the stored object as a whole, so send every key you want to keep: unlike a project's settings, keys are not merged. The server stores it as sent and does not read any key from it. 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
workspace object yes The workspace record as stored once the update is applied, so it shows the new name and settings and the new updatedAt.
workspace.id string (uuid) yes Id of the workspace.
workspace.name string yes Display name of the workspace, 1 to 120 characters.
workspace.slug string yes URL-safe identifier, unique across all workspaces; fixed at creation.
workspace.settings Record<string, unknown> yes Free-form object stored as sent through PATCH /api/workspaces/{workspaceId}; {} until then. The server does not read any key of it.
workspace.iconUrl string | null yes Address of the workspace's icon, which the first website set up in it provides; null until then.
workspace.rbacVersion integer yes Version of the platform's default roles and permissions the workspace was provisioned with. Workspaces created before the platform revised them keep their older number until their system roles are migrated. Read-only: no request sets it.
workspace.createdAt string (date-time) yes When the workspace was created, as an ISO 8601 timestamp.
workspace.updatedAt string (date-time) yes When the workspace row last changed, as an ISO 8601 timestamp.

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.workspaces.update({
  workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);

pd.workspaces.listMembers(input, init?)

List a workspace's members

GET /api/workspaces/{workspaceId}/members

Needs members.read. Members have no status: a person either holds a membership here or does not. Invited addresses that have not accepted yet are not members; they are listed by GET /api/workspaces/{workspaceId}/invitations.

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
members object[] yes Every member of the workspace, in no guaranteed order.
members[].memberId string (uuid) yes Id of the membership, used in /members/{memberId} routes and as workspaceMemberId when adding the member to a project. Not the user id.
members[].userId string yes Id of the member's user account.
members[].name string yes The member's display name.
members[].email string yes The member's email address.
members[].roles object[] yes The roles the member holds; their permissions are the union of the roles' permissions. Empty when every role was taken off.
members[].roles[].id string (uuid) yes Id of the role (GET .../roles).
members[].roles[].name string yes Name of the role.
members[].createdAt string (date-time) yes When the member joined the workspace, as an ISO 8601 timestamp.

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.workspaces.listMembers({
  workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);

pd.workspaces.addMember(input, init?)

Add a member, or invite an address by email

POST /api/workspaces/{workspaceId}/members

Needs members.invite. An address with an account joins at once, is told so by email, and the call answers { memberId, member }; one already in the workspace answers 409 CONFLICT. Any other address is invited: it gets an email with a link valid for seven days, and the call answers { invitation }. The roles given (the default role when none is sent) may only hold permissions the caller holds: 403 FORBIDDEN, with those permissions in details.permissions. Inviting an address that already has an open invitation renews it (new link, roles and expiry; the old link stops working), and answers 429 RATE_LIMITED with Retry-After within a minute of the last send. Both paths count against the users quota (429 QUOTA_EXCEEDED at the limit), and an open invitation holds a seat until it is accepted, revoked or expires. Either email is queued with the change and sent in the background, in the member's own language for an account and in locale for an invitation. Records a members.invited 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.email body string (email) yes Email address to add. Matched case-insensitively against existing accounts: one with an account joins at once, any other is invited by email.
body.roleIds body string (uuid)[] no Ids of the roles to give (GET .../roles); every one must belong to this workspace, else 400 INVALID_REQUEST, and none may carry a permission the caller lacks, else 403 FORBIDDEN. Empty or omitted: the workspace's default role (isDefault) is given. For an invitation the roles are applied when it is accepted. Default: [].
body.locale body "en" | "fr" no Language of the invitation email, en or fr. Only used when the address has no account. Omitted: the first language of the request's Accept-Language header when it is French or English, else en.
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
(response) object<variant 1> | object<variant 2> yes
<variant 1>.memberId string (uuid) yes Kept for clients written before invitations existed.
<variant 1>.member object yes The new member, as GET .../members lists them.
<variant 1>.member.memberId string (uuid) yes Id of the membership, used in /members/{memberId} routes and as workspaceMemberId when adding the member to a project. Not the user id.
<variant 1>.member.userId string yes Id of the member's user account.
<variant 1>.member.name string yes The member's display name.
<variant 1>.member.email string yes The member's email address.
<variant 1>.member.roles object[] yes The roles the member holds; their permissions are the union of the roles' permissions. Empty when every role was taken off.
<variant 1>.member.roles[].id string (uuid) yes Id of the role (GET .../roles).
<variant 1>.member.roles[].name string yes Name of the role.
<variant 1>.member.createdAt string (date-time) yes When the member joined the workspace, as an ISO 8601 timestamp.
<variant 2>.invitation object yes The invitation that was created, or renewed when the address already had an open one.
<variant 2>.invitation.id string (uuid) yes Id of the invitation, used to resend or revoke it.
<variant 2>.invitation.email string yes The invited address, lowercased. The invitation can only be accepted by it.
<variant 2>.invitation.roleIds string (uuid)[] yes The roles the invitee receives on accepting; any that no longer exist by then are skipped, and when none is left the workspace's default roles apply.
<variant 2>.invitation.invitedBy object | null yes The inviter; null when it was an API key without a creator, or the user is gone.
<variant 2>.invitation.invitedBy.id string yes Id of the inviting user.
<variant 2>.invitation.invitedBy.name string yes Display name of the inviting user.
<variant 2>.invitation.expiresAt string (date-time) yes When the emailed link stops working, as an ISO 8601 timestamp: seven days after the last send. Past it the invitation is expired but stays listed, so it can be resent.
<variant 2>.invitation.createdAt string (date-time) yes When the invitation was first created, as an ISO 8601 timestamp.
<variant 2>.invitation.lastSentAt string (date-time) yes When the link was last emailed, as an ISO 8601 timestamp; resending is refused for a minute after.

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.workspaces.addMember({
  workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
  body: {
    email: "ada@example.com",
  },
});
console.log(result);

pd.workspaces.setMemberRoles(input, init?)

Replace a member's roles

PATCH /api/workspaces/{workspaceId}/members/{memberId}

Needs roles.assign. Replaces all of the member's roles with the ones sent, in effect immediately. 403 FORBIDDEN when a role sent, or a role the member holds now, carries a permission the caller lacks (details.permissions lists them), so nobody can raise a member above themselves or demote someone more powerful than themselves. 403 FORBIDDEN also when it would take the Owner role from the workspace's last owner. 404 RESOURCE_NOT_FOUND when the member is not in the workspace. Records a members.roles_updated audit entry.

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.
memberId path string (uuid) yes Id of a membership of this workspace, as memberId in GET .../members (not the user id). A membership of another workspace answers 404 RESOURCE_NOT_FOUND.
body body object yes
body.roleIds body string (uuid)[] yes Ids of the roles the member should hold from now on; every one must belong to this workspace, else 400 INVALID_REQUEST, and none may carry a permission the caller lacks, else 403 FORBIDDEN. They replace the current roles entirely. An empty array leaves the member with no role and so no permissions; no default role is applied.
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.workspaces.setMemberRoles({
  workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
  memberId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
  body: {
    roleIds: ["3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c"],
  },
});
console.log(result);

pd.workspaces.removeMember(input, init?)

Remove a member from a workspace

DELETE /api/workspaces/{workspaceId}/members/{memberId}

Needs members.remove. Deletes the membership, and with it the member's roles and project memberships; their user account is untouched. 403 FORBIDDEN when the member holds a permission the caller lacks (details.permissions lists them), so nobody can remove someone more powerful than themselves; removing yourself is always allowed. 403 FORBIDDEN also for the workspace's last owner: give someone else the Owner role first. 404 RESOURCE_NOT_FOUND when the member is not in the workspace. Records a members.removed audit entry.

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.
memberId path string (uuid) yes Id of a membership of this workspace, as memberId in GET .../members (not the user id). A membership 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.workspaces.removeMember({
  workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
  memberId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);