Service Settings and Server
The four endpoints behind a service's access details, limits, server and information blocks.
Overview
These four endpoints touch a service's settings. The update on the service endpoints handles billing and dates; these decide how the service is reached, which server it sits on, and what the client reads on their page.
The management form behaves differently per service type: access details and limits are handled on hosting, server and special products, while licence fields apply to software services only. A field sent to the wrong type is ignored without a word.
Reference
Saving the Management Form
Saves a service's access details, resource limits and licence fields.
options to confirm the access details that are not secret.curl -X PATCH 'https://panel.example.com/api/v1/admin/services/506/management' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"access":{"username":"john"},"override_product_limits":true,"limits":{"disk_limit":50}}'const res = await fetch('https://panel.example.com/api/v1/admin/services/506/management', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
access: { username: 'john' },
override_product_limits: true,
limits: { disk_limit: 50 },
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/management');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'access' => ['username' => 'john'],
'override_product_limits' => true,
'limits' => ['disk_limit' => 50],
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Sending limits is not enough: turn the override on first, or the product's limits still rule.
$response = Api::Services()->UpdateServiceManagement([
'id' => 506,
'override_product_limits' => true,
'limits' => ['disk_limit' => 50, 'bandwidth_limit' => 500],
]);Moving to Another Server
Points the service record at another server and updates the module to match.
none when left without a server.curl -X PUT 'https://panel.example.com/api/v1/admin/services/506/server' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"server_id":5}'const res = await fetch('https://panel.example.com/api/v1/admin/services/506/server', {
method: 'PUT',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ server_id: 5 }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/server');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['server_id' => 5]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// This endpoint moves the RECORD only; building the account on the new server is separate work.
$response = Api::Services()->SetServiceServer([
'id' => 506,
'server_id' => 5,
]);
$module = $response['data']['module'];{
"data": {
"server_id": 5,
"module": "Mailcow",
"id": 506
}
}{
"error": {
"code": "same_server",
"message": "Service is already on this server."
}
}Writing the Information Blocks
Writes the free-text blocks the client sees on the service page.
blocks is not an array.curl -X PUT 'https://panel.example.com/api/v1/admin/services/506/blocks' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"blocks":[{"title":"Connection","description":"Connect over SSH on port 22."}]}'const res = await fetch('https://panel.example.com/api/v1/admin/services/506/blocks', {
method: 'PUT',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
blocks: [
{ title: 'Connection', description: 'Connect over SSH on port 22.' },
],
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/blocks');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'blocks' => [
['title' => 'Connection', 'description' => 'Connect over SSH on port 22.'],
],
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// To ADD a block send the existing list too: what you send becomes the truth.
$service = Api::Services()->GetService(['id' => 506])['data'];
$blocks = $service['options']['blocks'] ?? [];
$blocks[] = ['title' => 'Backups', 'description' => 'Nightly, kept for 7 days.'];
Api::Services()->SetServiceBlocks(['id' => 506, 'blocks' => $blocks]);Clearing the Status Message
Removes the sticky status message the module left behind.
curl -X POST 'https://panel.example.com/api/v1/admin/services/506/clear-status-message' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/services/506/clear-status-message', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/506/clear-status-message');
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);// Clearing the message does not fix its cause: the module can write the same error again.
$response = Api::Services()->ClearServiceStatusMessage(['id' => 506]);Pitfalls
This endpoint only points the record at the new server and swaps the module to match. The account stays exactly where it was on the old server and is never created on the new one. The real migration is separate work; this call is for lining the record up afterwards.
Sending resource limits is not enough on its own: with override_product_limits off the product's limits still rule and your values are not applied. No error is raised either, so read the service detail back to confirm.
What you send becomes the truth: blocks missing from the list are deleted. To add one, read the current list first, append to it and send all of it back. A block empty in both title and description is skipped without a word.
The status message is a trace the module left. Clearing it removes the text only; if the same error persists the module writes it again on its next operation. Look at why it was written before hiding it.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.