curl --request PUT \
--url https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-tenant-id: <x-tenant-id>' \
--data '
{
"customerGroups": [
{
"customerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"isDefault": true
}
],
"replacements": [
{
"removedCustomerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"replacementCustomerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000"
}
]
}
'import requests
url = "https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups"
payload = {
"customerGroups": [
{
"customerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"isDefault": True
}
],
"replacements": [
{
"removedCustomerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"replacementCustomerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000"
}
]
}
headers = {
"x-tenant-id": "<x-tenant-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {
'x-tenant-id': '<x-tenant-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
customerGroups: [{customerGroupId: 'b45f6432-2462-4c6f-b00f-1d9d01000000', isDefault: true}],
replacements: [
{
removedCustomerGroupId: 'b45f6432-2462-4c6f-b00f-1d9d01000000',
replacementCustomerGroupId: 'b45f6432-2462-4c6f-b00f-1d9d01000000'
}
]
})
};
fetch('https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'customerGroups' => [
[
'customerGroupId' => 'b45f6432-2462-4c6f-b00f-1d9d01000000',
'isDefault' => true
]
],
'replacements' => [
[
'removedCustomerGroupId' => 'b45f6432-2462-4c6f-b00f-1d9d01000000',
'replacementCustomerGroupId' => 'b45f6432-2462-4c6f-b00f-1d9d01000000'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"x-tenant-id: <x-tenant-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups"
payload := strings.NewReader("{\n \"customerGroups\": [\n {\n \"customerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"isDefault\": true\n }\n ],\n \"replacements\": [\n {\n \"removedCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"replacementCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\"\n }\n ]\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("x-tenant-id", "<x-tenant-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups")
.header("x-tenant-id", "<x-tenant-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customerGroups\": [\n {\n \"customerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"isDefault\": true\n }\n ],\n \"replacements\": [\n {\n \"removedCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"replacementCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["x-tenant-id"] = '<x-tenant-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"customerGroups\": [\n {\n \"customerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"isDefault\": true\n }\n ],\n \"replacements\": [\n {\n \"removedCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"replacementCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"customerGroups": [
{
"customerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"isAssigned": true,
"isDefault": true
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}Save Shop Customer Groups
Declaratively replaces the complete set of tenant-wide customer groups assigned to a shop. The request describes the full desired state - every customer group contained in it is assigned and every customer group not contained in it is unassigned. Exactly one assignment must be marked as the default customer group, and the list must not be empty. When an assigned customer group is removed and still has customers assigned to it, the request must name a replacement customer group for it via Replacements - all affected groups are reported together in a single batched error rather than one at a time. Note on the response shape: unlike a command that returns only the minimal necessary data, this one echoes the complete resulting assignment list, matching the existing sales channel precedent (see SaveShopCurrencies) and the declarative-replace example in ADR-57. Concurrency: this write is last-writer-wins, like SaveShopCurrencies - it takes no If-Match header and no row version, so two concurrent calls for the same shop overwrite each other without a conflict being reported.
curl --request PUT \
--url https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'x-tenant-id: <x-tenant-id>' \
--data '
{
"customerGroups": [
{
"customerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"isDefault": true
}
],
"replacements": [
{
"removedCustomerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"replacementCustomerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000"
}
]
}
'import requests
url = "https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups"
payload = {
"customerGroups": [
{
"customerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"isDefault": True
}
],
"replacements": [
{
"removedCustomerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"replacementCustomerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000"
}
]
}
headers = {
"x-tenant-id": "<x-tenant-id>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {
'x-tenant-id': '<x-tenant-id>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
customerGroups: [{customerGroupId: 'b45f6432-2462-4c6f-b00f-1d9d01000000', isDefault: true}],
replacements: [
{
removedCustomerGroupId: 'b45f6432-2462-4c6f-b00f-1d9d01000000',
replacementCustomerGroupId: 'b45f6432-2462-4c6f-b00f-1d9d01000000'
}
]
})
};
fetch('https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'customerGroups' => [
[
'customerGroupId' => 'b45f6432-2462-4c6f-b00f-1d9d01000000',
'isDefault' => true
]
],
'replacements' => [
[
'removedCustomerGroupId' => 'b45f6432-2462-4c6f-b00f-1d9d01000000',
'replacementCustomerGroupId' => 'b45f6432-2462-4c6f-b00f-1d9d01000000'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"x-tenant-id: <x-tenant-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups"
payload := strings.NewReader("{\n \"customerGroups\": [\n {\n \"customerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"isDefault\": true\n }\n ],\n \"replacements\": [\n {\n \"removedCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"replacementCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\"\n }\n ]\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("x-tenant-id", "<x-tenant-id>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups")
.header("x-tenant-id", "<x-tenant-id>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"customerGroups\": [\n {\n \"customerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"isDefault\": true\n }\n ],\n \"replacements\": [\n {\n \"removedCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"replacementCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.jtl-cloud.com/erp/v2/sales-channels/{salesChannelId}/shop/customer-groups")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["x-tenant-id"] = '<x-tenant-id>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"customerGroups\": [\n {\n \"customerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"isDefault\": true\n }\n ],\n \"replacements\": [\n {\n \"removedCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\",\n \"replacementCustomerGroupId\": \"b45f6432-2462-4c6f-b00f-1d9d01000000\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"customerGroups": [
{
"customerGroupId": "b45f6432-2462-4c6f-b00f-1d9d01000000",
"isAssigned": true,
"isDefault": true
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}{
"type": "https://www.rfc-editor.org/rfc/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"instance": "/api/route",
"traceId": "0HMPNHL0JHL76:00000001",
"detail": "<string>",
"errors": [
{
"name": "Error or field name",
"reason": "Error reason",
"code": "<string>",
"severity": "<string>"
}
]
}Authorizations
The access token received from the authorization server in the OAuth 2.0 flow.
Headers
The tenant ID for the target ERP instance.
Path Parameters
Sales channel id of the Wawi-managed shop whose customer groups are replaced. This is a tenant-local, composite identifier and not a UUID (ADR-69) - it is opaque to the caller and must be taken verbatim from a sales channel listing; the internal shop key (kShop) is never accepted here.
Body
Request model for SaveShopCustomerGroups command endpoint. Route parameters bind from the route, query parameters from the query string, everything else from the body.
The complete desired set of customer groups for the shop. Any customer group currently assigned but not contained in this list is unassigned. Must contain at least one entry, exactly one of which is marked as the default.
Show child attributes
Show child attributes
For every removed customer group that still has assigned customers, names the customer group taking over those customers. Optional and empty by default - only required when a removal actually needs one.
Show child attributes
Show child attributes
Response
Successfully replaced the shop customer groups. Returns the resulting assignments.
Declaratively replaces the complete set of tenant-wide customer groups assigned to a shop. The request describes the full desired state - every customer group contained in it is assigned and every customer group not contained in it is unassigned. Exactly one assignment must be marked as the default customer group, and the list must not be empty. When an assigned customer group is removed and still has customers assigned to it, the request must name a replacement customer group for it via Replacements - all affected groups are reported together in a single batched error rather than one at a time. Note on the response shape: unlike a command that returns only the minimal necessary data, this one echoes the complete resulting assignment list, matching the existing sales channel precedent (see SaveShopCurrencies) and the declarative-replace example in ADR-57. Concurrency: this write is last-writer-wins, like SaveShopCurrencies - it takes no If-Match header and no row version, so two concurrent calls for the same shop overwrite each other without a conflict being reported. - Response
The persisted customer group assignments, in the order submitted.
Show child attributes
Show child attributes
Was this page helpful?