API Reference

Groups

A permission group is a named set of users. Owners of skills, tools, MCP servers, agents and workspaces can share them with a whole group at once, where their role allows it; see Share a resource. A group can be built by hand, or linked to a Microsoft Entra ID group so that its membership follows the directory; see Directory synchronisation.

Every membership records its source. Members added by an administrator are local; members added by a directory group import or sync are entra. A sync only adds and removes entra members, so the people you add by hand stay in the group whatever the directory says.

A member's access follows the groups they belonged to when they signed in, so membership changes take effect from their next sign-in. Only active groups give their members access.

Administrator access. Every endpoint on this page requires an administrator account.

The group object

Retrieve a group also returns the group's members.

Attributes

  • id integer

    Unique identifier for the group.

  • slug string

    A unique identifier of lowercase letters, digits and hyphens, at most 64 characters. A row of Create users in bulk can name the group by its slug.

  • name string

    The group's name, at most 150 characters.

  • description nullable string

    What the group is for.

  • source string

    local for a group created by hand, or entra for one that comes from Microsoft Entra ID.

  • entraGroupId nullable string

    Object ID of the Microsoft Entra ID group this group is linked to, or null. A directory sync keeps the membership of a linked group in step with the directory.

  • entraTenantId nullable string

    A directory tenant identifier stored with the link, if one was supplied. Import and sync don't use it, and importing the directory group again clears it.

  • isActive boolean

    Whether the group is active. Only active groups give their members access.

  • lastSyncedAt nullable string

    When the group's directory-sourced membership was last brought in line with the directory, or null if it never has been.

  • memberCount integer

    The number of members.

  • createdAt string

    When the group was created, in ISO 8601 format.

  • updatedAt string

    When the group was last changed or synchronised, in ISO 8601 format.

  • members array of objects

    The members, ordered by name. Returned by Retrieve a group only.

    Show child attributes Hide child attributes
    • id integer

      The user's ID.

    • email string

      The user's email address.

    • name string

      The user's display name.

    • userType string

      The user's role.

    • isActive boolean

      Whether the user's account is active.

    • source string

      local for a member added by an administrator, by hand or through an import's or bulk creation's group selection; entra for a member added by a directory group import or sync.

    • addedAt string

      When the user joined the group, in ISO 8601 format.

The group object
{
  "id": 7,
  "slug": "engineering",
  "name": "Engineering",
  "description": "Engineering staff",
  "source": "entra",
  "entraGroupId": "3f2b8c1e-5a4d-4e6f-9b7a-1c2d3e4f5a6b",
  "entraTenantId": null,
  "isActive": true,
  "lastSyncedAt": "2026-09-03T06:00:12.338190+00:00",
  "memberCount": 2,
  "createdAt": "2026-09-02T08:15:26.901233+00:00",
  "updatedAt": "2026-09-03T06:00:12.338190+00:00"
}

List groups

GET /api/admin/groups

Returns every permission group with its member count.

Returns all permission groups, active or not, ordered by name, each with its member count.

Authentication
Bearer token How it works
Permission
Requires an administrator account.

Parameters

No parameters.

Returns

Returns a list of group objects.

Request
curl "$VDF_BASE_URL/api/admin/groups" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "groups": [
    {
      "id": 7,
      "slug": "engineering",
      "name": "Engineering",
      "description": "Engineering staff",
      "source": "entra",
      "entraGroupId": "3f2b8c1e-5a4d-4e6f-9b7a-1c2d3e4f5a6b",
      "entraTenantId": null,
      "isActive": true,
      "lastSyncedAt": "2026-09-03T06:00:12.338190+00:00",
      "memberCount": 2,
      "createdAt": "2026-09-02T08:15:26.901233+00:00",
      "updatedAt": "2026-09-03T06:00:12.338190+00:00"
    },
    {
      "id": 8,
      "slug": "finance",
      "name": "Finance",
      "description": "Finance team",
      "source": "local",
      "entraGroupId": null,
      "entraTenantId": null,
      "isActive": true,
      "lastSyncedAt": null,
      "memberCount": 0,
      "createdAt": "2026-09-04T11:20:03.772915+00:00",
      "updatedAt": "2026-09-04T11:20:03.772915+00:00"
    }
  ]
}

Create a group

POST /api/admin/groups

Creates a permission group.

Creates an active group with no members. To link it to a Microsoft Entra ID group, pass entra_group_id; the next directory sync then brings its membership in line with the directory. To create linked groups from the directory instead, use Import directory groups.

Authentication
Bearer token How it works
Permission
Requires an administrator account.

Body parameters application/json

  • name string Required

    The group's name, at most 150 characters.

  • slug string

    A unique identifier of lowercase letters, digits and hyphens, 1 to 64 characters, starting and ending with a letter or digit. Upper-case letters are lowercased. Derived from name when omitted.

  • description string

    What the group is for.

  • source string

    Where the group comes from. entra requires entra_group_id.

    Defaults to local.

    Possible values
    • local
    • entra
  • entra_group_id string

    Object ID (a GUID) of the Microsoft Entra ID group to link. A directory group can be linked to only one permission group. Also accepted as entraGroupId.

  • entra_tenant_id string

    A directory tenant identifier to store with the link. Also accepted as entraTenantId.

Returns

Returns the new group object.

Errors

  • 400 name is missing or longer than 150 characters; the slug (given or derived from name) isn't valid; source isn't local or entra; entra_group_id isn't a GUID; or source is entra without entra_group_id.
  • 409 A group with this slug already exists, or the directory group is already linked to another group.
Request
curl -X POST "$VDF_BASE_URL/api/admin/groups" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Finance",
    "description": "Finance team"
  }'
Response 201
{
  "success": true,
  "group": {
    "id": 8,
    "slug": "finance",
    "name": "Finance",
    "description": "Finance team",
    "source": "local",
    "entraGroupId": null,
    "entraTenantId": null,
    "isActive": true,
    "lastSyncedAt": null,
    "memberCount": 0,
    "createdAt": "2026-09-04T11:20:03.772915+00:00",
    "updatedAt": "2026-09-04T11:20:03.772915+00:00"
  }
}

Retrieve a group

GET /api/admin/groups/{group_id}

Returns a permission group with its members.

Returns the group, whether active or not, together with its members.

Authentication
Bearer token How it works
Permission
Requires an administrator account.

Path parameters

  • group_id integer Required

    The group's ID.

Returns

Returns the group object, including members.

Errors

  • 404 No group has this ID.
Request
curl "$VDF_BASE_URL/api/admin/groups/7" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "group": {
    "id": 7,
    "slug": "engineering",
    "name": "Engineering",
    "description": "Engineering staff",
    "source": "entra",
    "entraGroupId": "3f2b8c1e-5a4d-4e6f-9b7a-1c2d3e4f5a6b",
    "entraTenantId": null,
    "isActive": true,
    "lastSyncedAt": "2026-09-03T06:00:12.338190+00:00",
    "memberCount": 2,
    "createdAt": "2026-09-02T08:15:26.901233+00:00",
    "updatedAt": "2026-09-03T06:00:12.338190+00:00",
    "members": [
      {
        "id": 42,
        "email": "ada@example.com",
        "name": "Ada Lovelace",
        "userType": "default",
        "isActive": true,
        "source": "local",
        "addedAt": "2026-09-02T09:02:11.574402+00:00"
      },
      {
        "id": 43,
        "email": "grace@example.com",
        "name": "Grace Hopper",
        "userType": "expert",
        "isActive": true,
        "source": "entra",
        "addedAt": "2026-09-02T08:15:27.340118+00:00"
      }
    ]
  }
}

Update a group

PUT /api/admin/groups/{group_id}

Replaces a permission group's settings.

Replaces the group's settings with the ones you send. Fields you omit are reset rather than kept: slug is derived from name again, description, entra_group_id and entra_tenant_id are cleared, source becomes local and is_active becomes true. To change one setting, send the group's current values with that one changed. Membership isn't affected.

Clearing entra_group_id unlinks the group from the directory, and its current members stay. Setting is_active to false keeps the group and its members, but the group stops giving access from its members' next sign-in.

Authentication
Bearer token How it works
Permission
Requires an administrator account.

Path parameters

  • group_id integer Required

    The group's ID.

Body parameters application/json

  • name string Required

    The group's name, at most 150 characters.

  • slug string

    A unique identifier of lowercase letters, digits and hyphens, 1 to 64 characters, starting and ending with a letter or digit. Upper-case letters are lowercased. Derived from name when omitted.

  • description string

    What the group is for. Cleared when omitted.

  • source string

    Where the group comes from. entra requires entra_group_id.

    Defaults to local.

    Possible values
    • local
    • entra
  • entra_group_id string

    Object ID (a GUID) of the linked Microsoft Entra ID group. A directory group can be linked to only one permission group. Omit it to unlink the group. Also accepted as entraGroupId.

  • entra_tenant_id string

    A directory tenant identifier to store with the link. Also accepted as entraTenantId.

  • is_active boolean

    Whether the group is active. Also accepted as isActive.

    Defaults to true.

Returns

Returns the updated group object.

Errors

  • 400 name is missing or longer than 150 characters; the slug (given or derived from name) isn't valid; source isn't local or entra; entra_group_id isn't a GUID; or source is entra without entra_group_id.
  • 404 No group has this ID.
  • 409 Another group already has this slug.
Request
curl -X PUT "$VDF_BASE_URL/api/admin/groups/8" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Finance and Legal",
    "slug": "finance",
    "description": "Finance and legal teams",
    "is_active": true
  }'
Response 200
{
  "success": true,
  "group": {
    "id": 8,
    "slug": "finance",
    "name": "Finance and Legal",
    "description": "Finance and legal teams",
    "source": "local",
    "entraGroupId": null,
    "entraTenantId": null,
    "isActive": true,
    "lastSyncedAt": null,
    "memberCount": 0,
    "createdAt": "2026-09-04T11:20:03.772915+00:00",
    "updatedAt": "2026-09-04T11:22:10.604419+00:00"
  }
}

Delete a group

DEL /api/admin/groups/{group_id}

Deletes a permission group and its memberships.

Permanently deletes the group and all of its memberships. The members' accounts aren't affected, and deleting a linked group doesn't change the directory. Members lose the access the group gave them from their next sign-in.

Authentication
Bearer token How it works
Permission
Requires an administrator account.

Path parameters

  • group_id integer Required

    The group's ID.

Returns

Returns a success marker.

Errors

  • 404 No group has this ID.
Request
curl -X DELETE "$VDF_BASE_URL/api/admin/groups/8" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true
}

List group members

GET /api/admin/groups/{group_id}/members

Returns the members of a permission group.

Returns the group's members, including deactivated accounts, ordered by name and then email address. Each member's source says whether a directory sync manages the membership.

Authentication
Bearer token How it works
Permission
Requires an administrator account.

Path parameters

  • group_id integer Required

    The group's ID.

Returns

Returns the list of members, each shaped like an entry of the group's members.

Errors

  • 404 No group has this ID.
Request
curl "$VDF_BASE_URL/api/admin/groups/7/members" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true,
  "members": [
    {
      "id": 42,
      "email": "ada@example.com",
      "name": "Ada Lovelace",
      "userType": "default",
      "isActive": true,
      "source": "local",
      "addedAt": "2026-09-02T09:02:11.574402+00:00"
    },
    {
      "id": 43,
      "email": "grace@example.com",
      "name": "Grace Hopper",
      "userType": "expert",
      "isActive": true,
      "source": "entra",
      "addedAt": "2026-09-02T08:15:27.340118+00:00"
    }
  ]
}

Add group members

POST /api/admin/groups/{group_id}/members

Adds the users to the group as local members, so a directory sync never removes them. Users who are already members are left as they are, including their source, and aren't counted in added. If any ID doesn't match an account, nothing is added.

Authentication
Bearer token How it works
Permission
Requires an administrator account.

Path parameters

  • group_id integer Required

    The group's ID.

Body parameters application/json

  • user_ids array of integers Required

    IDs of the users to add. Also accepted as userIds; a single ID can be sent as user_id instead.

Returns

Returns the number of users added and the group's members.

Errors

  • 400 user_ids is missing, empty or not a list of integers, or an ID doesn't match any account.
  • 404 No group has this ID.
Request
curl -X POST "$VDF_BASE_URL/api/admin/groups/8/members" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user_ids": [
      42,
      44
    ]
  }'
Response 200
{
  "success": true,
  "added": 2,
  "members": [
    {
      "id": 42,
      "email": "ada@example.com",
      "name": "Ada Lovelace",
      "userType": "default",
      "isActive": true,
      "source": "local",
      "addedAt": "2026-09-04T11:25:40.118233+00:00"
    },
    {
      "id": 44,
      "email": "katherine@example.com",
      "name": "Katherine Johnson",
      "userType": "expert",
      "isActive": true,
      "source": "local",
      "addedAt": "2026-09-04T11:25:40.118233+00:00"
    }
  ]
}

Remove a group member

DEL /api/admin/groups/{group_id}/members/{user_id}

Removes a user from a permission group.

Removes the user from the group, whatever the membership's source. The account isn't affected. If the membership came from the directory and the user is still in the linked directory group, the next sync adds them back.

Authentication
Bearer token How it works
Permission
Requires an administrator account.

Path parameters

  • group_id integer Required

    The group's ID.

  • user_id integer Required

    The member's user ID.

Returns

Returns a success marker.

Errors

  • 404 The user isn't a member of this group, or no group has this ID.
Request
curl -X DELETE "$VDF_BASE_URL/api/admin/groups/7/members/42" \
  -H "Authorization: Bearer $VDF_ACCESS_TOKEN"
Response 200
{
  "success": true
}