---
title: "Subusers API Reference"
description: "Silly Development API reference for subusers: give other accounts access to a server with their own permissions, change them and remove them."
url: "https://sillydev.co.uk/docs/panel/subusers"
updated: "2026-10-10"
---

API reference

# Subusers

Share a server with other people, each with their own permissions.

[← API docs](https://sillydev.co.uk/docs/panel) · 5 endpoints · Updated 10 October 2026

**Browse the docs**

## Subusers

Other accounts given access to a server, each with its own set of permissions. Call `GET /permissions` (`listPermissions`) for every permission there is and what each one allows.

### List subusers

GET`/servers/{server}/users`

Permission user.read

Returns every subuser of the server with their permissions. The server's owner is not listed. The list is not paginated.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| serverrequired | string | The server's 8-character identifier, as shown in the panel, or its full UUID. |

Example

```
curl "https://sillydev.co.uk/panel/api/client/servers/1a7ce997/users" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200The server's subusers.

```
{
    "object": "list",
    "data": [
        {
            "object": "server_subuser",
            "attributes": {
                "uuid": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f",
                "identifier": "user_l4gc3dr3djgh3hrpnkfqyhjoh4",
                "username": "friend",
                "email": "friend@example.com",
                "image": "https://www.gravatar.com/avatar/0f2c9a7e4b1d8c6a3e5f7b9d1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c?d=404",
                "2fa_enabled": false,
                "created_at": "2026-09-15T18:30:00+00:00",
                "permissions": [
                    "websocket.connect",
                    "control.console",
                    "control.restart",
                    "file.read",
                    "file.read-content"
                ]
            }
        }
    ]
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| datarequired | array of object |  |
| data\[\].objectrequired | string |  |
| data\[\].attributesrequired | object |  |
| data\[\].attributes.uuidrequired | string (uuid) | The account's UUID, used as `{user}` in the subuser paths. |
| data\[\].attributes.identifierrequired | string | The account's public identifier. |
| data\[\].attributes.usernamerequired | string |  |
| data\[\].attributes.emailrequired | string (email) |  |
| data\[\].attributes.imagerequired | string (uri) | Gravatar URL for the email address; it answers 404 if there is no Gravatar. |
| data\[\].attributes.2fa_enabledrequired | boolean |  |
| data\[\].attributes.created_atrequired | string (date-time) | When the account was created. |
| data\[\].attributes.permissionsrequired | array of string | The subuser's permissions on this server. See `listPermissions` for every one. |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.

### Add a subuser

POST`/servers/{server}/users`

Permission user.create Limited to 10 per 15 minutes per server

Gives the account with this email access to the server. If no account has the email, one is created and sent an email to set its password. `websocket.connect` is always added, and unknown permissions are silently dropped. You cannot give permissions you do not have yourself, nor any your API key is not allowed. Limited to 10 every 15 minutes per server, shared by everyone managing that server.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| serverrequired | string | The server's 8-character identifier, as shown in the panel, or its full UUID. |

Body

| Name | Type | Description |
| --- | --- | --- |
| emailrequired | string (email) |  |
| permissionsrequired | array of string | Permission strings such as `control.console` or `file.read`. Unknown ones are dropped and `websocket.connect` is always added. See `listPermissions`. |

Example

```
curl -X POST "https://sillydev.co.uk/panel/api/client/servers/1a7ce997/users" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"email":"friend@example.com","permissions":["control.console","control.restart","file.read","file.read-content"]}'
```

Response 200The new subuser.

```
{
    "object": "server_subuser",
    "attributes": {
        "uuid": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f",
        "identifier": "user_l4gc3dr3djgh3hrpnkfqyhjoh4",
        "username": "friend",
        "email": "friend@example.com",
        "image": "https://www.gravatar.com/avatar/0f2c9a7e4b1d8c6a3e5f7b9d1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c?d=404",
        "2fa_enabled": false,
        "created_at": "2026-09-15T18:30:00+00:00",
        "permissions": [
            "control.console",
            "control.restart",
            "file.read",
            "file.read-content",
            "websocket.connect"
        ]
    }
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| attributesrequired | object |  |
| attributes.uuidrequired | string (uuid) | The account's UUID, used as `{user}` in the subuser paths. |
| attributes.identifierrequired | string | The account's public identifier. |
| attributes.usernamerequired | string |  |
| attributes.emailrequired | string (email) |  |
| attributes.imagerequired | string (uri) | Gravatar URL for the email address; it answers 404 if there is no Gravatar. |
| attributes.2fa_enabledrequired | boolean |  |
| attributes.created_atrequired | string (date-time) | When the account was created. |
| attributes.permissionsrequired | array of string | The subuser's permissions on this server. See `listPermissions` for every one. |

Errors

- 400 The email belongs to the server's owner or to an existing subuser.
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key lacks `user.create`, or you tried to give permissions that you or your API key do not have.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 422 Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.
- 429 Too many requests. Wait for the number of seconds in the `Retry-After` header, then try again.

### Get a subuser

GET`/servers/{server}/users/{user}`

Permission user.read

Returns one subuser of the server. You cannot look yourself up here (403).

Parameters

| Name | Type | Description |
| --- | --- | --- |
| serverrequired | string | The server's 8-character identifier, as shown in the panel, or its full UUID. |
| userrequired | string (uuid) | The subuser's account UUID (`attributes.uuid` from `listSubusers`). |

Example

```
curl "https://sillydev.co.uk/panel/api/client/servers/1a7ce997/users/{user}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200The subuser.

```
{
    "object": "server_subuser",
    "attributes": {
        "uuid": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f",
        "identifier": "user_l4gc3dr3djgh3hrpnkfqyhjoh4",
        "username": "friend",
        "email": "friend@example.com",
        "image": "https://www.gravatar.com/avatar/0f2c9a7e4b1d8c6a3e5f7b9d1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c?d=404",
        "2fa_enabled": false,
        "created_at": "2026-09-15T18:30:00+00:00",
        "permissions": [
            "websocket.connect",
            "control.console"
        ]
    }
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| attributesrequired | object |  |
| attributes.uuidrequired | string (uuid) | The account's UUID, used as `{user}` in the subuser paths. |
| attributes.identifierrequired | string | The account's public identifier. |
| attributes.usernamerequired | string |  |
| attributes.emailrequired | string (email) |  |
| attributes.imagerequired | string (uri) | Gravatar URL for the email address; it answers 404 if there is no Gravatar. |
| attributes.2fa_enabledrequired | boolean |  |
| attributes.created_atrequired | string (date-time) | When the account was created. |
| attributes.permissionsrequired | array of string | The subuser's permissions on this server. See `listPermissions` for every one. |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.

### Change a subuser's permissions

POST`/servers/{server}/users/{user}`

Permission user.update

Replaces the subuser's permissions with the list sent (`websocket.connect` is always kept). If they change, the subuser's open SFTP sessions and console connections are dropped so the new set applies at once (this drops everyone's open console connections to the server, who then reconnect). The same limits on what you can give apply as for `createSubuser`, and you cannot change your own permissions.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| serverrequired | string | The server's 8-character identifier, as shown in the panel, or its full UUID. |
| userrequired | string (uuid) | The subuser's account UUID (`attributes.uuid` from `listSubusers`). |

Body

| Name | Type | Description |
| --- | --- | --- |
| permissionsrequired | array of string | The full new set of permissions. See `listPermissions`. |

Example

```
curl -X POST "https://sillydev.co.uk/panel/api/client/servers/1a7ce997/users/{user}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"permissions":["control.console","control.start","control.stop","control.restart"]}'
```

Response 200The updated subuser.

```
{
    "object": "server_subuser",
    "attributes": {
        "uuid": "5f0c2d8e-3b1a-4c7d-9e2f-6a8b0c1d2e3f",
        "identifier": "user_l4gc3dr3djgh3hrpnkfqyhjoh4",
        "username": "friend",
        "email": "friend@example.com",
        "image": "https://www.gravatar.com/avatar/0f2c9a7e4b1d8c6a3e5f7b9d1c3e5a7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c?d=404",
        "2fa_enabled": false,
        "created_at": "2026-09-15T18:30:00+00:00",
        "permissions": [
            "control.console",
            "control.start",
            "control.stop",
            "control.restart",
            "websocket.connect"
        ]
    }
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| attributesrequired | object |  |
| attributes.uuidrequired | string (uuid) | The account's UUID, used as `{user}` in the subuser paths. |
| attributes.identifierrequired | string | The account's public identifier. |
| attributes.usernamerequired | string |  |
| attributes.emailrequired | string (email) |  |
| attributes.imagerequired | string (uri) | Gravatar URL for the email address; it answers 404 if there is no Gravatar. |
| attributes.2fa_enabledrequired | boolean |  |
| attributes.created_atrequired | string (date-time) | When the account was created. |
| attributes.permissionsrequired | array of string | The subuser's permissions on this server. See `listPermissions` for every one. |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key lacks `user.update`, this is your own account, or you tried to give permissions that you or your API key do not have.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 422 Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.

### Remove a subuser

DELETE`/servers/{server}/users/{user}`

Permission user.delete

Takes away the account's access to the server and ends its open SFTP sessions; open console connections to the server are dropped and reconnect. The account itself is not deleted. You cannot remove yourself here.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| serverrequired | string | The server's 8-character identifier, as shown in the panel, or its full UUID. |
| userrequired | string (uuid) | The subuser's account UUID (`attributes.uuid` from `listSubusers`). |

Example

```
curl -X DELETE "https://sillydev.co.uk/panel/api/client/servers/1a7ce997/users/{user}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 204Done. There is no response body.

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
