Special Groups
The seven endpoints that manage the special groups holding product families outside the fixed types.
Overview
A special group holds together a family of products that falls outside the fixed types. SSL certificates are the canonical case: products with no type of their own live inside a special group.
A group is not only a container but a storefront setting. Payment gateways, the list template and the upgrade permission are set at group level and reach every product inside.
Reference
Listing the Groups
Returns the top-level special product groups.
active ya da inactive.curl 'https://panel.example.com/api/v1/admin/products/special-groups' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/products/special-groups', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/products/special-groups');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Products()->GetProductGroupsList();{
"data": [
{
"id": 5,
"key": "special-5",
"title": "SSL Certificates",
"route": "ssl-certificates",
"status": "active",
"product_count": 8,
"service_count": 40,
"created_at": "2026-01-01 10:00:00"
}
],
"meta": { "total": 3, "page": 1, "limit": 25, "next_page": 0 }
}Group Detail
Returns one group with all of its settings and language content.
active ya da inactive.visible ya da invisible.font ya da image.curl 'https://panel.example.com/api/v1/admin/products/special-groups/5' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/products/special-groups/5', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/products/special-groups/5');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Products()->GetProductGroup(['id' => 5]);Creating a Group
Opens a top-level special group.
active ya da inactive.font ya da image.201. Same shape as the group detail schema.curl -X POST 'https://panel.example.com/api/v1/admin/products/special-groups' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"title":{"en":"SSL Certificates"},"status":"active","icon_type":"font","icon":"fa-lock","color":"3366ff"}'const res = await fetch('https://panel.example.com/api/v1/admin/products/special-groups', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: { en: 'SSL Certificates' },
status: 'active',
icon_type: 'font',
icon: 'fa-lock',
color: '3366ff',
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/products/special-groups');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'title' => ['en' => 'SSL Certificates'],
'status' => 'active',
'icon_type' => 'font',
'icon' => 'fa-lock',
'color' => '3366ff',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The new group's key is what you use when opening products and categories inside it.
$group = Api::Products()->CreateProductGroup([
'title' => ['en' => 'SSL Certificates'],
]);
Api::Products()->CreateProduct([
'type' => 'special',
'group_id' => $group['data']['id'],
'name' => 'Wildcard SSL',
]);Updating a Group
Applies the fields you send and leaves the rest as they were.
active ya da inactive.font ya da image.curl -X PATCH 'https://panel.example.com/api/v1/admin/products/special-groups/5' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"status":"inactive","color":"ff0000"}'const res = await fetch('https://panel.example.com/api/v1/admin/products/special-groups/5', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: 'inactive', color: 'ff0000' }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/products/special-groups/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' => 'inactive',
'color' => 'ff0000',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The FAQ, columns and payment gateways are NOT edited here; they are preserved.
$response = Api::Products()->UpdateProductGroup([
'id' => 5,
'status' => 'inactive',
]);Deleting a Group
Deletes the group. Its products, sub-categories and images go with it.
gate:product.group_delete hook vetoed the operation.curl -X DELETE 'https://panel.example.com/api/v1/admin/products/special-groups/5' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/products/special-groups/5', {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/products/special-groups/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);// The delete takes everything in the group - count the contents first.
$group = Api::Products()->GetProductGroupsList()['data'][0];
if ($group['product_count'] > 0 || $group['service_count'] > 0) {
return;
}
Api::Products()->DeleteProductGroup(['id' => $group['id']]);Uploading a Group Image
Uploads the group's icon or its header background.
icon or header-background. Defaults to icon.icon or header-background. Compare it with what you sent to catch a silent fallback.header-background images are resized to the configured dimensions.curl -X POST 'https://panel.example.com/api/v1/admin/products/special-groups/5/image' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"image":"https://cdn.example.com/ssl.png","type":"icon"}'const res = await fetch('https://panel.example.com/api/v1/admin/products/special-groups/5/image', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
image: 'https://cdn.example.com/ssl.png',
type: 'icon',
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/products/special-groups/5/image');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'image' => 'https://cdn.example.com/ssl.png',
'type' => 'icon',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Products()->UploadGroupImage([
'id' => 5,
'image' => 'https://cdn.example.com/ssl.png',
'type' => 'icon',
]);Deleting a Group Image
Removes the group's icon or its header background.
icon or header-background. Defaults to icon.curl -X DELETE -G 'https://panel.example.com/api/v1/admin/products/special-groups/5/image' \
-H "Authorization: Bearer $API_KEY" \
-d type=iconconst url = new URL('https://panel.example.com/api/v1/admin/products/special-groups/5/image');
url.searchParams.set('type', 'icon');
const res = await fetch(url, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$url = 'https://panel.example.com/api/v1/admin/products/special-groups/5/image?' . http_build_query(['type' => 'icon']);
$ch = curl_init($url);
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);$response = Api::Products()->DeleteProductGroupImage(['id' => 5], ['type' => 'icon']);Pitfalls
Deleting a group also deletes the products, sub-categories and images inside it. The product_count and service_count fields on the list exist for exactly this; read both before you delete.
The FAQ, the column layout, the operator notes and the payment gateway lists are not in the update body. They keep their current values, so leaving them out does not wipe them. They are managed from the panel's own screens.
The colour field wants the six digits without a leading hash. Sending it with one can leave the value unreadable, so read the detail back after writing to see what was stored.
Related Articles
Vielen Dank für Ihre Rückmeldung!
Unser Support-Team ist rund um die Uhr für Sie da, wenn Sie oben nicht fündig werden.