Skip to content

Users API

Users are workspace members. Each user has one or more roles that determine their permissions across projects and resources.

The list endpoint is available to all authenticated users — useful for resolving user IDs to names. Update, delete, and invitation endpoints require admin-level access.

Permissions

ActionRequired PermissionScope
ListUsers: ReadVisible users only — see Visibility scope
UpdateUsers: UpdateVisible users only — out-of-scope targets return 403
Resend InvitationUsers: CreateVisible users only — out-of-scope targets return 403
DeleteUsers: DeleteVisible users only — out-of-scope targets return 403

Admins bypass all permission checks. Users are tenant-scoped (not project-scoped), so the project owner bypass does not apply.

Visibility scope

/api/users and the three /api/users/{userId} action routes (update, delete, resend-invitation) only expose users the caller is allowed to see. The scope composes as:

  • Self — the caller is always visible to themselves, even when they have no team or project membership.
  • Admins — every admin is always visible, so cross-team name resolution (e.g. an admin commenting on an issue) keeps working.
  • Users with access_all_users — every user holding a role with the access_all_users flag is always visible, regardless of project membership.
  • Project-affiliated users — users on any team that has access to a project the caller can access, plus direct project members.

Two role flags bypass the scope entirely:

FlagEffect on /api/users
is_adminReturns every user; action routes are not gated by visibility.
access_all_usersReturns every user; action routes are not gated by visibility.
access_all_projectsWidens the scope to every user affiliated with any project (every team member, every direct project member). Orphan invites with no project link remain hidden unless the caller also has access_all_users.

See Roles API — Role Flags for how to grant the flags.

The action routes (POST /api/users/{userId}, POST /api/users/{userId}/resend-invitation, DELETE /api/users/{userId}) return 403 Forbidden (not 404) when the caller lacks visibility to the target.

Endpoints

MethodEndpointDescription
GET/api/usersList all users
POST/api/users/{userId}Update a user
POST/api/users/{userId}/resend-invitationResend invitation email
DELETE/api/users/{userId}Delete a user
GET/api/users/{userId}/profile-picture/{variant}Stream an avatar image. {variant} is avif or webp. Cached for 7 days via Cache-Control: public, max-age=604800 + ETag.

List Users

GET /api/users

Returns the users visible to the caller (see Visibility scope — admins and access_all_users holders see everyone; all other callers see a filtered set). Admins receive the full response including email and detailed role permissions. All other users, including non-admin holders of access_all_users, receive the public response shown below.

bash
curl https://{tenant}.kendo.dev/api/users \
  -H "Authorization: Bearer your-token"
json
[
  {
    "id": 4,
    "first_name": "Alice",
    "last_name": "Johnson",
    "roles": [
      {"id": 1, "name": "Admin", "slug": "admin"}
    ],
    "created_at": "2026-01-22T07:29:17.000000Z",
    "deleted_at": null,
    "profile_picture": {
      "avif": "https://{tenant}.kendo.dev/api/users/4/profile-picture/avif",
      "webp": "https://{tenant}.kendo.dev/api/users/4/profile-picture/webp"
    },
    "issue_ids": [1, 42, 105],
    "project_ids": [1, 3],
    "team_ids": [1],
    "has_pending_invite": false
  },
  {
    "id": 8,
    "first_name": "Bob",
    "last_name": "Smith",
    "roles": [
      {"id": 2, "name": "Member", "slug": "member"}
    ],
    "created_at": "2026-02-01T09:00:00.000000Z",
    "deleted_at": null,
    "profile_picture": null,
    "issue_ids": [23, 67],
    "project_ids": [1],
    "team_ids": [2],
    "has_pending_invite": false
  }
]

Admin Response

When the requesting user is an admin, the response includes additional fields: email and expanded role permissions.

json
{
  "id": 8,
  "first_name": "Bob",
  "last_name": "Smith",
  "email": "bob@example.com",
  "roles": [
    {
      "id": 2,
      "name": "Member",
      "slug": "member",
      "is_admin": false,
      "permissions": [
        {
          "resource": 2,
          "can_create": true,
          "can_read": true,
          "can_update": 1,
          "can_delete": 1
        }
      ]
    }
  ],
  "created_at": "2026-02-01T09:00:00.000000Z",
  "deleted_at": null,
  "profile_picture": null,
  "issue_ids": [23, 67],
  "project_ids": [1],
  "team_ids": [2],
  "has_pending_invite": false
}

See the Roles API for the full list of permission resources and scope values.

Update User

POST /api/users/{userId}

Request Fields

FieldTypeRequiredDescription
first_namestringYesFirst name, max 255 characters
last_namestringYesLast name, max 255 characters
emailstringYesEmail address, must be unique
role_idsinteger[]NoRole IDs to assign. At least 1 if provided.
bash
curl -X POST https://{tenant}.kendo.dev/api/users/8 \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Bob",
    "last_name": "Smith",
    "email": "bob@example.com",
    "role_ids": [2, 5]
  }'
json
{
  "id": 8,
  "first_name": "Bob",
  "last_name": "Smith",
  "roles": [
    {"id": 2, "name": "Member", "slug": "member"},
    {"id": 5, "name": "Developer", "slug": "developer"}
  ],
  "created_at": "2026-02-01T09:00:00.000000Z",
  "deleted_at": null,
  "profile_picture": null,
  "issue_ids": [23, 67],
  "project_ids": [1],
  "team_ids": [2],
  "has_pending_invite": false
}

Resend Invitation

POST /api/users/{userId}/resend-invitation

Resends the invitation email for a user with a pending invite. Returns 204 No Content on success.

bash
curl -X POST https://{tenant}.kendo.dev/api/users/12/resend-invitation \
  -H "Authorization: Bearer your-token"

Delete User

DELETE /api/users/{userId}

Returns 204 No Content on success.

bash
curl -X DELETE https://{tenant}.kendo.dev/api/users/8 \
  -H "Authorization: Bearer your-token"

See Also

  • Roles API — Manage roles and permissions assigned to users
  • Issues API — Issues assigned to users via assignee_id