User Management

Invite, list, and remove users, manage pending invitations, and define custom roles across Blue workspaces and organizations.


The User Management API covers the full lifecycle of a teammate’s access: inviting them, listing who has access, managing the invitations they haven’t accepted yet, removing them, and defining custom roles with granular permissions.

Access is granted at two scopes:

  • Workspace — a user belongs to a single workspace (Workspace) with an access level scoped to that workspace.
  • Organization — a user belongs to the organization (Organization) and, through it, to one or more of its workspaces.

In the API, workspaces are Workspace objects and organizations are Organization objects. Access levels are the UserAccessLevel enum; custom roles are ProjectUserRole objects scoped to a single workspace.

Authentication

All requests go to the GraphQL endpoint with your personal access token in headers:

POST https://api.blue.app/graphql
blue-token-id: YOUR_TOKEN_ID
blue-token-secret: YOUR_TOKEN_SECRET
blue-org-id: YOUR_ORG_ID
blue-workspace-id: project_123   # required for workspace-scoped operations

Headers are case-insensitive. The Company and Project headers accept either an ID or a slug. See Authentication for how to create a token.

Operations

Users

OperationTypeDescription
workspaceUserListQueryList users in a workspace, with pagination and search.
assigneesQueryList users who can be assigned to records in a workspace.
currentUserQueryReturn the authenticated user.
inviteUserMutationInvite a user to a workspace or organization.
removeProjectUserMutationRemove a user from a single workspace.
removeOrganizationUserMutationRemove a user from the entire organization.

Invitations

OperationTypeDescription
invitationsQueryList pending and accepted invitations for a workspace.
myInvitationsQueryList invitations addressed to the authenticated user.
resendInvitationMutationRe-send an invitation email and refresh its expiry.
cancelInvitationMutationRevoke a pending invitation.

Custom roles

OperationTypeDescription
createWorkspaceUserRoleMutationCreate a custom role in a workspace.
updateWorkspaceUserRoleMutationUpdate a custom role.
deleteWorkspaceUserRoleMutationDelete a custom role.
workspaceUserRole / workspaceUserRolesQueryRead one or many custom roles.

Access levels

UserAccessLevel has exactly six values, in descending order of capability:

LevelDescription
OWNERFull control over the workspace or organization. Ownership is single-slot per organization.
ADMINManages users, settings, and content.
MEMBERStandard teammate with full workspace functionality.
CLIENTExternal collaborator with limited visibility.
COMMENT_ONLYCan view and comment, but not edit.
VIEW_ONLYRead-only.

Who can invite which level

The level you can assign depends on your own access level in the target workspace. VIEW_ONLY and COMMENT_ONLY users cannot invite at all.

Inviter levelLevels they can assign
OWNERAll six levels, including OWNER.
ADMINEvery level except OWNER.
MEMBERMEMBER, CLIENT, COMMENT_ONLY, VIEW_ONLY.
CLIENTCLIENT, COMMENT_ONLY, VIEW_ONLY.
Organization invites require ownership

Passing companyId to inviteUser invites at the organization level, and only the organization OWNER can do this. When an existing organization owner is added to a workspace, they are always added as ADMIN regardless of the accessLevel you request.

Common patterns

Every example below is valid against the current schema. Inline IDs (project_123, user_123, …) are placeholders; substitute real IDs or slugs.

Invite a user to a workspace

inviteUser returns a plain Boolean! — there is no selection set. See Invite User for the full parameter reference.

mutation InviteToWorkspace {
  inviteUser(
    input: { email: "teammate@example.com", projectId: "project_123", accessLevel: MEMBER }
  )
}
{ "data": { "inviteUser": true } }

Invite a user to the organization

Supply companyId (requires organization OWNER) and, optionally, projectIds to add them to specific workspaces in the same call.

mutation InviteToOrganization {
  inviteUser(
    input: {
      email: "manager@example.com"
      companyId: "company_123"
      projectIds: ["project_123", "project_456"]
      accessLevel: ADMIN
    }
  )
}

List users in a workspace

workspaceUserList returns a ProjectUserList with users, a pageInfo, and a totalCount.

query WorkspaceUsers {
  workspaceUserList(projectId: "project_123", first: 25) {
    users {
      id
      fullName
      email
      image {
        medium
      }
      projectLevel(projectId: "project_123")
    }
    pageInfo {
      totalItems
      hasNextPage
    }
    totalCount
  }
}
{
  "data": {
    "workspaceUserList": {
      "users": [
        {
          "id": "clm4n8qwx000008l0g4oxdqn7",
          "fullName": "Ada Lovelace",
          "email": "ada@example.com",
          "image": { "medium": "https://blue.app/files/clm4n8qwx/medium.png" },
          "projectLevel": "MEMBER"
        }
      ],
      "pageInfo": { "totalItems": 12, "hasNextPage": false },
      "totalCount": 12
    }
  }
}

List pending invitations

Pass pending: true to return only invitations that haven’t been accepted yet.

query PendingInvitations {
  invitations(projectId: "project_123", pending: true) {
    id
    email
    accessLevel
    expiredAt
    invitedBy {
      fullName
    }
  }
}

Resend or cancel an invitation

resendInvitation refreshes the invitation’s expiry and returns the Invitation. cancelInvitation revokes it and returns a Boolean!.

mutation RefreshInvite {
  resendInvitation(id: "invitation_123") {
    id
    email
    expiredAt
  }
}
mutation RevokeInvite {
  cancelInvitation(id: "invitation_123")
}

Remove a user

Use removeProjectUser to revoke a single workspace, or removeOrganizationUser to remove the user from the whole organization. removeProjectUser returns a MutationResult (success, operationId); removeOrganizationUser returns a nullable Boolean.

mutation RemoveFromWorkspace {
  removeProjectUser(input: { projectId: "project_123", userId: "user_123" }) {
    success
    operationId
  }
}
mutation RemoveFromOrganization {
  removeOrganizationUser(input: { companyId: "company_123", userId: "user_123" })
}

You cannot remove a user whose level is OWNER; transfer ownership first. See Remove Users for the cleanup each removal performs.

Create a custom role

createWorkspaceUserRole takes flat boolean toggles (no nested permissions object) and returns a ProjectUserRole. Select only the fields the role exposes.

mutation CreateRole {
  createWorkspaceUserRole(
    input: {
      projectId: "project_123"
      name: "Content Reviewer"
      isRecordsEnabled: true
      canCreateRecords: false
      canDeleteRecords: false
    }
  ) {
    id
    name
    canCreateRecords
    canDeleteRecords
  }
}
{
  "data": {
    "createWorkspaceUserRole": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "name": "Content Reviewer",
      "canCreateRecords": false,
      "canDeleteRecords": false
    }
  }
}

See Custom Roles for the full toggle list and per-field/per-list visibility controls.

Errors

CodeWhen
FORBIDDENThe caller lacks permission for the requested action (e.g. inviting a level above their own, or inviting at the organization level without being OWNER).
PLAN_LIMIT_REACHEDThe organization’s seat limit is reached: “Users limit reached (current/limit). Upgrade your plan for more.”
USER_ALREADY_IN_THE_PROJECTThe invitee is already a member of the workspace.
ADD_SELFThe caller tried to invite their own email address.
PROJECT_NOT_FOUNDThe projectId does not resolve to a workspace the caller can access.
COMPANY_NOT_FOUNDThe companyId does not resolve to an organization.
USER_NOT_FOUNDThe userId being removed does not exist or is not in the target scope.
PROJECT_USER_ROLE_NOT_FOUNDThe roleId passed to inviteUser does not exist in the target workspace.
COMPANY_BANNEDThe organization account is suspended. Contact support.