Add-on Modules
The seven endpoints that list, configure, test and remove the installed add-on modules.
Overview
Add-on modules are pieces that extend the installation: accounting integrations, chat, translation. These seven endpoints list them, configure them, test them, run their own methods and remove them.
Every module supports different things. The capability list on the detail says what is possible. Whether it has settings, whether it offers a connection test, which methods can be called. Read the method name from that list rather than guessing it.
Reference
Listing the Add-ons
Returns the add-on modules installed.
meta, not in the installed list.curl -G 'https://panel.example.com/api/v1/admin/tools/addons' \
-H "Authorization: Bearer $API_KEY" \
-d status=enabledconst url = new URL('https://panel.example.com/api/v1/admin/tools/addons');
url.searchParams.set('status', 'enabled');
const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();$url = 'https://panel.example.com/api/v1/admin/tools/addons?' . http_build_query(['status' => 'enabled']);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Store modules are not in the INSTALLED list; they come separately under meta.
$response = Api::Tools()->GetAddons([], ['include_premium' => 1]);
$installed = $response['data'];
$buyable = $response['meta']['premium'] ?? [];Add-on Detail
Returns an add-on's settings, its form definition and what it can do.
curl 'https://panel.example.com/api/v1/admin/tools/addons/Parasut' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/addons/Parasut', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/addons/Parasut');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The list of callable methods comes from HERE; do not guess a method name.
$module = Api::Tools()->GetAddon(['module' => 'Parasut'])['data'];
$methods = $module['capabilities']['methods'];Changing the Status
Switches the add-on on or off.
1 switches it on, 0 switches it off.curl -X PUT 'https://panel.example.com/api/v1/admin/tools/addons/Parasut/status' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"status":1}'const res = await fetch('https://panel.example.com/api/v1/admin/tools/addons/Parasut/status', {
method: 'PUT',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: 1 }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/addons/Parasut/status');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['status' => 1]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Switching one on runs the module's own setup: it can create tables and register hooks.
Api::Tools()->UpdateAddonStatus(['module' => 'Parasut', 'status' => 1]);Saving the Settings
Writes the module's settings and, if you like, changes its status in the same request.
curl -X PUT 'https://panel.example.com/api/v1/admin/tools/addons/Parasut/settings' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"fields":{"api_key":"xxxx"},"status":1}'const res = await fetch('https://panel.example.com/api/v1/admin/tools/addons/Parasut/settings', {
method: 'PUT',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
fields: { api_key: secret },
status: 1,
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/addons/Parasut/settings');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'fields' => ['api_key' => $secret],
'status' => 1,
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Password fields read from the detail are MASKED: send them back as they are and you store the mask.
$module = Api::Tools()->GetAddon(['module' => 'Parasut'])['data'];
$fields = $module['settings'];
unset($fields['api_key']); // leave it out when it should not change
$fields['webhook_url'] = $url;
Api::Tools()->UpdateAddonSettings(['module' => 'Parasut', 'fields' => $fields]);Testing the Connection
Tries whether the module can reach its service with the settings it has.
curl -X POST 'https://panel.example.com/api/v1/admin/tools/addons/Parasut/test-connection' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/addons/Parasut/test-connection', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/addons/Parasut/test-connection');
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);// The test uses the STORED settings: save first, then try.
Api::Tools()->UpdateAddonSettings(['module' => 'Parasut', 'fields' => $fields]);
$test = Api::Tools()->TestAddonConnection(['module' => 'Parasut']);Running a Module Method
Runs one of the add-on's own methods.
curl -X POST 'https://panel.example.com/api/v1/admin/tools/addons/Parasut/methods/sync' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/addons/Parasut/methods/sync', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/addons/Parasut/methods/sync');
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);// An empty return counts as FAILURE: a method that returns nothing answers 'method_failed'.
$module = Api::Tools()->GetAddon(['module' => 'Parasut'])['data'];
if (in_array('sync', $module['capabilities']['methods'], true)) {
Api::Tools()->RunAddonMethod(['module' => 'Parasut', 'method' => 'sync']);
}Deleting an Add-on
Uninstalls the module and deletes its files from disk.
curl -X DELETE 'https://panel.example.com/api/v1/admin/tools/addons/Parasut' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/tools/addons/Parasut', {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/tools/addons/Parasut');
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);// This endpoint also deletes the module's DIRECTORY: coming back means uploading it again.
// To stop it for a while, switch the status off instead of deleting.
Api::Tools()->UpdateAddonStatus(['module' => 'Parasut', 'status' => 0]);Pitfalls
The detail returns password-type fields masked. Write those settings straight back and you store the mask in place of the real password. The module can then no longer reach its service. Leave password fields you are not changing out of the body entirely.
The delete does not merely switch the module off: it runs the module's own uninstall and deletes its files from disk. Coming back means uploading it again. To stop a module for a while, switch its status off instead.
The connection test takes no body; it runs with the settings the module already has. Trying a new key means saving it first, so a failed test leaves the wrong setting already written.
The run endpoint answers method_failed when the method returns nothing. So a method that genuinely ran but produced no result also looks like an error. Without knowing what the module returns, do not read that code as a definite failure.
When you ask for the purchasable modules they are not mixed into the main list. They come back in a field of their own. Every row in the main list is installed, so do not try to tell them apart by the installed field.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.