# Service Tools

https://dev.wisecp.com/es/service-tools

The five endpoints that run the provider panel's tools, call module methods and produce sign-in links.

## Overview

Tools let you do through the API what the service's provider panel does: create a database, add a mailbox, look at files. You get the same data the panel sees, but **raw** instead of as HTML.

Tools exist on hosting and server services only. Domain services have their own endpoints, and special products have no tool system at all — they use the **module method** route instead, which is where power operations, console details and the like are called.

## Reference

### Listing the Tools

get/api/v1/admin/services/{id}/tools

`Services/GetServiceTools` admin hosting and servers

Returns the tools the service's module offers and which operations each accepts.

Response fields data[] — 5

keystringThe tool key. The other endpoints use it in the path.

groupstringThe group the tool sits in.

labelstringThe display label.

iconstringThe icon class.

capabilitiesstring[]The operations the tool accepts. Calling one that is not listed is refused.

Errors 3

not_found404No such service.

tools_not_supported422This service type exposes no tools. Domain and special products have none.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/services/506/tools' \
  -H "Authorization: Bearer $API_KEY"
```

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

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

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

```php
// Read the capability before trying an operation: modules support tools to different degrees.
$tools = Api::Services()->GetServiceTools(['id' => 506])['data'];

foreach ($tools as $tool) {
    $canCreate = in_array('create', $tool['capabilities'], true);
}
```

Response 200 422

```json
{
  "data": [
    {
      "key": "databases",
      "group": "databases",
      "label": "Databases",
      "icon": "bi bi-database",
      "capabilities": ["list", "create", "delete"]
    },
    {
      "key": "email-accounts",
      "group": "email",
      "label": "Email Accounts",
      "icon": "bi bi-envelope",
      "capabilities": ["list", "create", "edit", "delete"]
    }
  ]
}
```

```json
{
  "error": {
    "code": "tools_not_supported",
    "message": "This service type does not expose tools."
  }
}
```

### Reading a Tool

get/api/v1/admin/services/{id}/tools/{tool}

`Services/GetServiceToolData` admin the shape comes from the module

Returns what the tool read from the provider, in its raw form.

Query parameters 2

actionstringThe sub-operation passed to the module. It defaults to the tool's index view.

*mixedAny other query parameter you give is passed straight to the module.

Response fields data

datamixedThe tool's own data. Its shape depends entirely on the module and the tool; there is no fixed schema.

Errors 5

not_found404The tool was not found or is not supported.

tools_not_supported422This service type exposes no tools. Domain and special products have none.

tool_required422The tool key was empty.

tool_data_failed500The module could not fetch the data.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/services/506/tools/databases' \
  -H "Authorization: Bearer $API_KEY"
```

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

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

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

```php
// The panel renders HTML, the API returns RAW data: the shape differs between modules.
$response = Api::Services()->GetServiceToolData(
    ['id' => 506, 'tool' => 'databases'],
);
```

Response 200

```json
{
  "data": {
    "databases": [
      {
        "name": "user_app",
        "size": 50855321,
        "tables": 42,
        "users": ["user_admin"]
      }
    ],
    "users": ["user_admin"],
    "prefix": "user_"
  }
}
```

### Running a Tool Operation

post/api/v1/admin/services/{id}/tools/{tool}/{action}

`Services/RunServiceToolAction` admin runs on the server

Runs an operation on the tool. The module's own validation checks the body fields.

Body *

*mixedWhatever the operation expects. The module decides; the fields are sanitised, validated and written to the history.

Response fields data

datamixedThe module's result. Usually a status and a message.

Errors 4

not_found404The tool was not found or is not supported.

tools_not_supported422This service type exposes no tools. Domain and special products have none.

tool_action_failed500The module could not complete the operation.

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/services/506/tools/databases/create' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"user_app"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/506/tools/databases/create', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'user_app' }),
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/tools/databases/create');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['name' => 'user_app']),
]);

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

```php
// The operation really runs ON THE SERVER: delete calls cannot be undone.
$response = Api::Services()->RunServiceToolAction(
    ['id' => 506, 'tool' => 'databases', 'action' => 'create'],
    [],
    ['name' => 'user_app'],
);
```

### Calling a Module Method

post/api/v1/admin/services/{id}/module-method

`Services/UseServiceModuleMethod` admin bound to an allow list

Calls a method the module allows. This is the way in for service types with no tool system.

Body 2

methodstringrequiredName of the method to call. Only methods on the module's callable list, or with a matching handler, will run.

*mixedAny other field you give is passed to the method as a parameter.

Response fields data — 4

methodstringThe method that was called.

redirect_urlstring | nullThe address, when the method produced a redirect.

resultmixed | nullWhat the method returned. Filled only when it returns an array or a string.

outputstring | nullAnything the method printed.

Errors 5

not_found404No such service.

method_required422No method name was given.

invalid_method422The method is not callable on the module.

no_module422The service has no module attached.

module_method_failed500The method threw an error.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/services/506/module-method' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"method":"vnc_info"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/506/module-method', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ method: 'vnc_info' }),
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/module-method');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['method' => 'vnc_info']),
]);

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

```php
// The outcome can arrive in three different fields: a return value, printed output, or a redirect.
$response = Api::Services()->UseServiceModuleMethod([
    'id'     => 506,
    'method' => 'vnc_info',
]);

$data = $response['data']['result']
    ?? $response['data']['output']
    ?? $response['data']['redirect_url'];
```

Response 200 422

```json
{
  "data": {
    "method": "vnc_info",
    "redirect_url": null,
    "result": { "host": "203.0.113.10", "port": 5901 },
    "output": null
  }
}
```

```json
{
  "error": {
    "code": "invalid_method",
    "message": "Module method is not callable."
  }
}
```

### A Sign-in Link for the Panel

post/api/v1/admin/services/{id}/sso

`Services/GetServiceSso` admin one-click sign-in

Produces a one-click sign-in link for the service's panel.

Body 1

rootboolProduces an administrator sign-in. Off by default, and while off it signs in to the client's own account.

Response fields data — 2

urlstringThe sign-in link.

rootboolWhether an administrator sign-in was asked for.

Errors 4

not_found404No such service.

sso_not_supported422The module does not support one-click sign-in.

sso_failed500The module produced no link.

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/services/506/sso' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"root":false}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/services/506/sso', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ root: false }),
});

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

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/sso');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['root' => false]),
]);

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

```php
// The link carries a session: keep it out of logs, do not share it, use it quickly.
$response = Api::Services()->GetServiceSso(['id' => 506]);
$url      = $response['data']['url'];
```

## Pitfalls

> **A tool operation really runs on the server**
> 
> These endpoints do not update a record; they reach the provider and have the work done **there**. Delete operations really remove the client's data and cannot be undone. Check the capabilities in the tool list before trying one, since an unsupported operation is refused.

> **The response shape depends on the module**
> 
> Tool data comes back raw and its shape differs between modules: one hosting panel returns databases under different keys than another. Parsing written against a single module breaks on the second one, so do not assume a fixed schema.

> **Module methods run against an allow list**
> 
> You cannot pick the method name freely: only ones the module marks callable, or that have a matching handler, will run, and the rest answer `invalid_method`. That is a security boundary, so do not assume every public method on the module is reachable.

> **Client-side restrictions apply on the API too**
> 
> Tools switched off for the client on a server are switched off for API calls as well. A tool you can see as an administrator in the panel may be unreachable through the API with the same key, and the reason is the restriction setting on the server rather than your permissions.

> **The sign-in link carries a session**
> 
> The link opens a session when clicked. Logging it, storing it or sharing it means sharing access to that account, so treat it as a short-lived credential. A call asking for the administrator sign-in opens the **root of the panel**, not one client account.

## Related Articles

- [Service Endpoints](https://dev.wisecp.com/en/service-endpoints)
- [Service Settings and Server](https://dev.wisecp.com/en/service-settings-and-server)
- [Provisioning Servers](https://dev.wisecp.com/en/provisioning-servers)
