# Server Groups

https://dev.wisecp.com/es/server-groups

The five endpoints that manage the server groups letting products provision into a pool.

## Overview

A server group lets a product be provisioned into a **pool** rather than onto one server. The product points at the group, and the fill strategy decides which server a new service lands on.

The group's type is not a field of its own: it comes from the members. That is why only servers on the **same type and the same module** can go into one group; a mixed list is refused outright.

## Reference

### Listing the Groups

get/api/v1/admin/products/server-groups

`Products/GetServerGroups` admin paged

Returns the server groups.

Query parameters 3

searchstringSearches the group name.

pageintDefaults to 1.

limitintDefaults to 25, maximum 100.

Response fields data[] — 6

idintGroup id.

namestringThe group name.

typestring`hosting` or `server`. It comes from the members; you do not set it.

fill_typeintThe fill strategy deciding which server a new service lands on.

server_idsint[]Ids of the servers in the group.

server_countintHow many servers are in the group.

Meta 4

totalintTotal records matching the filter.

pageintThe page you are on.

limitintThe page size.

next_pageintThe next page. Zero means you are on the last one.

Errors 1

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/products/server-groups' \
  -H "Authorization: Bearer $API_KEY"
```

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/server-groups');
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::Products()->GetServerGroups();
```

Response 200

```json
{
  "data": [
    {
      "id": 2,
      "name": "Shared Pool",
      "type": "hosting",
      "fill_type": 1,
      "server_ids": [34, 35],
      "server_count": 2
    }
  ],
  "meta": { "total": 1, "page": 1, "limit": 25, "next_page": 0 }
}
```

### Group Detail

get/api/v1/admin/products/server-groups/{id}

`Products/GetServerGroup` admin

Returns one server group. The schema is the same as a list item.

Response fields data — 6

idintGroup id.

namestringThe group name.

typestring`hosting` or `server`. It comes from the members; you do not set it.

fill_typeintThe fill strategy deciding which server a new service lands on.

server_idsint[]Ids of the servers in the group.

server_countintHow many servers are in the group.

Errors 2

not_found404No such server group.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/products/server-groups/2' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/products/server-groups/2', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/server-groups/2');
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::Products()->GetServerGroup(['id' => 2]);
```

### Creating a Group

post/api/v1/admin/products/server-groups

`Products/CreateServerGroup` admin 201

Opens a server group. Every member has to share the same type and the same module.

Body 3

namestringrequiredThe group name.

serversint[]requiredIds of the servers to put in. At least one, and all on the same type and module.

fill_typeintThe fill strategy. Defaults to 1.

Response fields data — 6

idintId of the new group.

namestringThe group name.

typestring`hosting` or `server`. It comes from the members, so it is never part of the request.

fill_typeintThe fill strategy deciding which server a new service lands on.

server_idsint[]Ids of the servers in the group.

server_countintHow many servers are in the group.

Errors 6

name_required422`name` was empty.

servers_required422No server was given.

invalid_server422One of the servers you gave does not exist.

no_capacity422One of the servers has no account capacity.

mixed_servers422The servers do not share a type and a module.

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/products/server-groups' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"Shared Pool","servers":[34,35],"fill_type":1}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/server-groups', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Shared Pool',
    servers: [34, 35],
    fill_type: 1,
  }),
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/server-groups');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'name'      => 'Shared Pool',
        'servers'   => [34, 35],
        'fill_type' => 1,
    ]),
]);

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

```php
// Filter out type and module mismatches yourself: a mixed list is refused outright.
$servers = Api::Products()->GetServers([], ['limit' => 100])['data'];
$cpanel  = array_column(
    array_filter($servers, fn (array $s): bool => $s['type'] === 'cPanel'),
    'id',
);

Api::Products()->CreateServerGroup([
    'name'    => 'Shared Pool',
    'servers' => $cpanel,
]);
```

### Updating a Group

patch/api/v1/admin/products/server-groups/{id}

`Products/UpdateServerGroup` admin the member list is written whole

Applies the fields you send. Send the member list and the group becomes exactly that list.

Body 3

namestringThe group name. If you send it, it cannot be empty.

serversint[]The complete set of servers. A server missing from the list leaves the group.

fill_typeintThe fill strategy.

Response fields data — 6

idintGroup id.

namestringThe group name.

typestring`hosting` or `server`. It comes from the members; you do not set it.

fill_typeintThe fill strategy deciding which server a new service lands on.

server_idsint[]Ids of the servers in the group. The up-to-date list, after your change.

server_countintHow many servers are in the group.

Errors 6

not_found404No such server group.

name_required422The group name you sent was empty.

invalid_server422One of the servers you gave does not exist.

no_capacity422One of the servers has no account capacity.

mixed_servers422The servers do not share a type and a module.

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/products/server-groups/2' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"servers":[34,35,36]}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/server-groups/2', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ servers: [34, 35, 36] }),
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/server-groups/2');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['servers' => [34, 35, 36]]),
]);

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

```php
// To ADD a server send the current list too, or the others leave the group.
$group = Api::Products()->GetServerGroup(['id' => 2])['data'];

Api::Products()->UpdateServerGroup([
    'id'      => 2,
    'servers' => [...$group['server_ids'], 36],
]);
```

### Deleting a Group

delete/api/v1/admin/products/server-groups/{id}

`Products/DeleteServerGroup` admin refused while in use

Deletes the server group. The delete is refused while a product still points at it.

Response fields data — 2

deletedboolWhether the delete succeeded.

idintId of the deleted group.

Errors 4

not_found404No such server group.

group_in_use422The group is still used by products.

blocked_by_gate422The `gate:product.server_group_delete` hook vetoed the operation.

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/products/server-groups/2' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/server-groups/2', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/server-groups/2');
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
// Deleting the group does not delete its members: the servers stay, only the grouping goes.
$response = Api::Products()->DeleteServerGroup(['id' => 2]);
```

## Pitfalls

> **A mixed list is refused outright**
> 
> Because the group takes its type from its members, servers on different types or different modules cannot sit together. Send such a list and **none** of them is added; the request comes back as `mixed_servers`. Filter the list on your side first.

> **The member list is written whole**
> 
> Sending a server list on an update makes the group **exactly** that list; servers missing from it leave. To add one server, read the current list first, append to it, and send all of it back.

> **A server with no capacity cannot join**
> 
> A server with no account capacity cannot be a member, and the request comes back as `no_capacity`. The fill strategy decides by capacity, so this is not a formality but a working condition.

## Related Articles

- [Provisioning Servers](https://dev.wisecp.com/en/provisioning-servers)
- [Product Endpoints](https://dev.wisecp.com/en/product-endpoints)
