# Sub-users

https://dev.wisecp.com/es/sub-users

The five endpoints that manage the limited-permission accounts reaching a client's panel.

## Overview

A sub-user is a second person who reaches a client's panel with limited permissions: the accountant sees only invoices, the technical team only services.

The permission set is **fixed** and holds ten values. The owner's own profile, billing contacts and e-mail history cannot be handed over; those stay with the account itself.

## Reference

### Listing the Sub-users

get/api/v1/admin/clients/{id}/subusers

`Clients/GetClientSubusers` admin

Returns every sub-user the client has.

Response fields data[] — 12

idintSub-user id.

emailstringE-mail address.

labelstring | nullA label. For a department or role name.

statusstring`pending` is awaiting the invite, `active` is live, `inactive` is switched off.

permissionsarray 10 permissionsThe permissions granted.

view_servicespermissionSees the services.

view_passwordspermissionSees service passwords.

allow_ssopermissionSigns in to a service panel in one click.

view_domainspermissionSees the domains.

manage_domainspermissionManages the domains.

view_invoicespermissionSees the invoices.

view_ticketspermissionSees the support tickets.

view_affiliatepermissionSees the affiliate page.

view_resellerpermissionSees the reseller page.

new_orderspermissionPlaces new orders.

email_notificationsintE-mail notification preference. A bitmask.

sms_notificationsintSMS notification preference. A bitmask.

linked_user_idintId of the real client account it is linked to. `0` when there is none.

linked_user_namestring | nullName of the linked account.

invited_atstring | nullWhen the invite went out.

accepted_atstring | nullWhen the invite was accepted.

created_atstring | nullWhen the record was created.

Errors 2

not_found404No such client or sub-user.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/clients/42/subusers' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/42/subusers', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/subusers');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Clients()->GetClientSubusers(['id' => 42]);
```

Response 200

```json
{
  "data": [
    {
      "id": 4,
      "email": "accounting@example.com",
      "label": "Accounting",
      "status": "active",
      "permissions": ["view_invoices", "view_services"],
      "email_notifications": 0,
      "sms_notifications": 0,
      "linked_user_id": 31,
      "linked_user_name": "John Doe",
      "invited_at": "2026-06-01 10:00:00",
      "accepted_at": "2026-06-02 09:12:00",
      "created_at": "2026-06-01 10:00:00"
    }
  ]
}
```

### Adding a Sub-user

post/api/v1/admin/clients/{id}/subusers

`Clients/CreateClientSubuser` admin 201

Adds a sub-user to the client. The record starts out `pending`.

Body 6

emailstringrequiredE-mail address. It has to differ from the owner's and not be in use already.

labelstringA label.

permissionsarray 10 permissionsThe permissions to grant. An unrecognised key is dropped without a word.

view_servicespermissionSees the services.

view_passwordspermissionSees service passwords.

allow_ssopermissionSigns in to a service panel in one click.

view_domainspermissionSees the domains.

manage_domainspermissionManages the domains.

view_invoicespermissionSees the invoices.

view_ticketspermissionSees the support tickets.

view_affiliatepermissionSees the affiliate page.

view_resellerpermissionSees the reseller page.

new_orderspermissionPlaces new orders.

email_notificationsintE-mail notification preference. Defaults to 0.

sms_notificationsintSMS notification preference. Defaults to 0.

send_inviteboolSends the invite e-mail. On by default.

Response fields 201 — data

dataobjectThe sub-user created. Same shape as the listing endpoint.

Errors 6

not_found404No such client or sub-user.

email_invalid422The e-mail is not valid.

email_is_owner422The e-mail is the owner's own.

email_exists422A sub-user with this e-mail already exists.

subuser_add_failed500The insert failed.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/clients/42/subusers' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"email":"accounting@example.com","label":"Accounting","permissions":["view_invoices","view_services"]}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/subusers', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: 'accounting@example.com',
    label: 'Accounting',
    permissions: ['view_invoices', 'view_services'],
    send_invite: true,
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/subusers');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'email'       => 'accounting@example.com',
        'label'       => 'Accounting',
        'permissions' => ['view_invoices', 'view_services'],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Clients()->CreateClientSubuser([
    'id'          => 42,
    'email'       => 'accounting@example.com',
    'permissions' => ['view_invoices', 'view_services'],
]);

// Read the granted permissions back: an unrecognised key is dropped silently.
$granted = $response['data']['permissions'];
```

### Updating a Sub-user

patch/api/v1/admin/clients/{id}/subusers/{subuser_id}

`Clients/UpdateClientSubuser` admin can link an account

Updates the fields you send and leaves the rest alone.

Body 5

labelstringThe label.

statusstringThe new status. An unrecognised value keeps the current one.

permissionsarray 10 permissionsThe permission list. If you send it, the list is written whole.

view_servicespermissionSees the services.

view_passwordspermissionSees service passwords.

allow_ssopermissionSigns in to a service panel in one click.

view_domainspermissionSees the domains.

manage_domainspermissionManages the domains.

view_invoicespermissionSees the invoices.

view_ticketspermissionSees the support tickets.

view_affiliatepermissionSees the affiliate page.

view_resellerpermissionSees the reseller page.

new_orderspermissionPlaces new orders.

email_notificationsintE-mail notification preference.

sms_notificationsintSMS notification preference.

Response fields data

dataobjectThe sub-user as it now stands. Same shape as the listing endpoint.

Errors 2

not_found404No such client or sub-user.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PATCH 'https://panel.example.com/api/v1/admin/clients/42/subusers/5' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"status":"active"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/subusers/5', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ status: 'active' }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/subusers/5');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['status' => 'active']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Clients()->UpdateClientSubuser([
    'id'         => 42,
    'subuser_id' => 5,
    'status'     => 'active',
]);

// Going active for the first time links a real account when the e-mail matches.
$linkedTo = $response['data']['linked_user_id'];
```

### Resending the Invite

post/api/v1/admin/clients/{id}/subusers/{subuser_id}/resend-invite

`Clients/ResendClientSubuserInvite` admin pending only

Sends the invite again to a sub-user still waiting for one.

Body —

——No body is needed, send an empty one. The invite goes to the address already stored on the record and cannot be redirected here.

Response fields data — 2

resentboolWhether the invite went out again.

idintSub-user id.

Errors 3

not_found404No such client or sub-user.

not_pending422The sub-user is not awaiting an invite. A live or switched-off record cannot be invited.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/clients/42/subusers/5/resend-invite' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/subusers/5/resend-invite', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/subusers/5/resend-invite');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Clients()->ResendClientSubuserInvite([
    'id'         => 42,
    'subuser_id' => 5,
]);
```

### Deleting a Sub-user

delete/api/v1/admin/clients/{id}/subusers/{subuser_id}

`Clients/DeleteClientSubuser` admin

Deletes the sub-user. The real client account it was linked to is not affected.

Response fields data — 2

deletedboolWhether the delete succeeded.

idintId of the deleted sub-user.

Errors 2

not_found404No such client or sub-user.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X DELETE 'https://panel.example.com/api/v1/admin/clients/42/subusers/5' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/subusers/5', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/subusers/5');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Clients()->DeleteClientSubuser([
    'id'         => 42,
    'subuser_id' => 5,
]);
```

## Pitfalls

> **An unrecognised permission is dropped silently**
> 
> The permission list is a closed set. Send a key that is not in it and you get no error; the key is thrown away and the record is stored with fewer permissions than you meant. Read the `permissions` field back from the write to see what was granted.

> **Going active can link an account**
> 
> The first time a sub-user is set to `active`, a matching e-mail on an existing client account **links that account**. That means someone can sign in as themselves and step into another client's panel, so know whose e-mail it is before changing status.

> **The invite only goes to one still waiting**
> 
> The resend endpoint only works on a record that is still `pending`. To invite a live sub-user you have to move the status back first.

## Related Articles

- [Client Endpoints](https://dev.wisecp.com/en/client-endpoints)
- [Client Security Endpoints](https://dev.wisecp.com/en/client-security-endpoints)
