curl --request POST \
--url https://api.example.com/api/operation/bundle \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenantid: <api-key>' \
--data '
{
"sessionId": "session-123",
"visitorId": "visitor-456",
"content": "Build a complete outfit around this jacket",
"requestOrigin": "Operation",
"pageSize": 6,
"operationHideAiMessage": false,
"operationReturnFullProductInfo": false,
"chatMetadata": {
"productId": "product-789"
}
}
'import requests
url = "https://api.example.com/api/operation/bundle"
payload = {
"sessionId": "session-123",
"visitorId": "visitor-456",
"content": "Build a complete outfit around this jacket",
"requestOrigin": "Operation",
"pageSize": 6,
"operationHideAiMessage": False,
"operationReturnFullProductInfo": False,
"chatMetadata": { "productId": "product-789" }
}
headers = {
"Authorization": "Bearer <token>",
"Tenantid": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
Tenantid: '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
sessionId: 'session-123',
visitorId: 'visitor-456',
content: 'Build a complete outfit around this jacket',
requestOrigin: 'Operation',
pageSize: 6,
operationHideAiMessage: false,
operationReturnFullProductInfo: false,
chatMetadata: {productId: 'product-789'}
})
};
fetch('https://api.example.com/api/operation/bundle', 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.example.com/api/operation/bundle",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sessionId' => 'session-123',
'visitorId' => 'visitor-456',
'content' => 'Build a complete outfit around this jacket',
'requestOrigin' => 'Operation',
'pageSize' => 6,
'operationHideAiMessage' => false,
'operationReturnFullProductInfo' => false,
'chatMetadata' => [
'productId' => 'product-789'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Tenantid: <api-key>"
],
]);
$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.example.com/api/operation/bundle"
payload := strings.NewReader("{\n \"sessionId\": \"session-123\",\n \"visitorId\": \"visitor-456\",\n \"content\": \"Build a complete outfit around this jacket\",\n \"requestOrigin\": \"Operation\",\n \"pageSize\": 6,\n \"operationHideAiMessage\": false,\n \"operationReturnFullProductInfo\": false,\n \"chatMetadata\": {\n \"productId\": \"product-789\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Tenantid", "<api-key>")
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.post("https://api.example.com/api/operation/bundle")
.header("Authorization", "Bearer <token>")
.header("Tenantid", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"sessionId\": \"session-123\",\n \"visitorId\": \"visitor-456\",\n \"content\": \"Build a complete outfit around this jacket\",\n \"requestOrigin\": \"Operation\",\n \"pageSize\": 6,\n \"operationHideAiMessage\": false,\n \"operationReturnFullProductInfo\": false,\n \"chatMetadata\": {\n \"productId\": \"product-789\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/operation/bundle")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Tenantid"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sessionId\": \"session-123\",\n \"visitorId\": \"visitor-456\",\n \"content\": \"Build a complete outfit around this jacket\",\n \"requestOrigin\": \"Operation\",\n \"pageSize\": 6,\n \"operationHideAiMessage\": false,\n \"operationReturnFullProductInfo\": false,\n \"chatMetadata\": {\n \"productId\": \"product-789\"\n }\n}"
response = http.request(request)
puts response.read_body"data: {\"chatStream\":\"I found several products that match your request.\"}\n\ndata: {\"data\":{\"responseType\":\"ProductSearch\",\"sessionId\":\"session-123\",\"visitorId\":\"visitor-456\",\"responsePayload\":[{\"id\":\"product-123\"}],\"hasMoreProducts\":false,\"total\":1}}\n\n""Tenant ID Invalid.""Tenant tenant-123 not found #000"Build a product bundle
Suggest complementary products for a base product.
curl --request POST \
--url https://api.example.com/api/operation/bundle \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenantid: <api-key>' \
--data '
{
"sessionId": "session-123",
"visitorId": "visitor-456",
"content": "Build a complete outfit around this jacket",
"requestOrigin": "Operation",
"pageSize": 6,
"operationHideAiMessage": false,
"operationReturnFullProductInfo": false,
"chatMetadata": {
"productId": "product-789"
}
}
'import requests
url = "https://api.example.com/api/operation/bundle"
payload = {
"sessionId": "session-123",
"visitorId": "visitor-456",
"content": "Build a complete outfit around this jacket",
"requestOrigin": "Operation",
"pageSize": 6,
"operationHideAiMessage": False,
"operationReturnFullProductInfo": False,
"chatMetadata": { "productId": "product-789" }
}
headers = {
"Authorization": "Bearer <token>",
"Tenantid": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
Tenantid: '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
sessionId: 'session-123',
visitorId: 'visitor-456',
content: 'Build a complete outfit around this jacket',
requestOrigin: 'Operation',
pageSize: 6,
operationHideAiMessage: false,
operationReturnFullProductInfo: false,
chatMetadata: {productId: 'product-789'}
})
};
fetch('https://api.example.com/api/operation/bundle', 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.example.com/api/operation/bundle",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sessionId' => 'session-123',
'visitorId' => 'visitor-456',
'content' => 'Build a complete outfit around this jacket',
'requestOrigin' => 'Operation',
'pageSize' => 6,
'operationHideAiMessage' => false,
'operationReturnFullProductInfo' => false,
'chatMetadata' => [
'productId' => 'product-789'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Tenantid: <api-key>"
],
]);
$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.example.com/api/operation/bundle"
payload := strings.NewReader("{\n \"sessionId\": \"session-123\",\n \"visitorId\": \"visitor-456\",\n \"content\": \"Build a complete outfit around this jacket\",\n \"requestOrigin\": \"Operation\",\n \"pageSize\": 6,\n \"operationHideAiMessage\": false,\n \"operationReturnFullProductInfo\": false,\n \"chatMetadata\": {\n \"productId\": \"product-789\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Tenantid", "<api-key>")
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.post("https://api.example.com/api/operation/bundle")
.header("Authorization", "Bearer <token>")
.header("Tenantid", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"sessionId\": \"session-123\",\n \"visitorId\": \"visitor-456\",\n \"content\": \"Build a complete outfit around this jacket\",\n \"requestOrigin\": \"Operation\",\n \"pageSize\": 6,\n \"operationHideAiMessage\": false,\n \"operationReturnFullProductInfo\": false,\n \"chatMetadata\": {\n \"productId\": \"product-789\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/operation/bundle")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Tenantid"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sessionId\": \"session-123\",\n \"visitorId\": \"visitor-456\",\n \"content\": \"Build a complete outfit around this jacket\",\n \"requestOrigin\": \"Operation\",\n \"pageSize\": 6,\n \"operationHideAiMessage\": false,\n \"operationReturnFullProductInfo\": false,\n \"chatMetadata\": {\n \"productId\": \"product-789\"\n }\n}"
response = http.request(request)
puts response.read_body"data: {\"chatStream\":\"I found several products that match your request.\"}\n\ndata: {\"data\":{\"responseType\":\"ProductSearch\",\"sessionId\":\"session-123\",\"visitorId\":\"visitor-456\",\"responsePayload\":[{\"id\":\"product-123\"}],\"hasMoreProducts\":false,\"total\":1}}\n\n""Tenant ID Invalid.""Tenant tenant-123 not found #000"intent field.
Identifying the base product
For the most deterministic result, provide the base product ID inchatMetadata.productId. The API can also attempt to resolve the base product from the natural-language content and other metadata.
productIds is not used to select the base product for this operation.
Request example
curl --no-buffer --request POST \
"$PREEZIE_API_URL/api/operation/bundle" \
--header "Authorization: Bearer $PREEZIE_OPERATION_TOKEN" \
--header "Tenantid: $PREEZIE_TENANT_ID" \
--header "Content-Type: application/json" \
--data '{
"sessionId": "session-123",
"visitorId": "visitor-456",
"content": "Build a complete outfit around this jacket",
"requestOrigin": "Operation",
"pageSize": 6,
"operationHideAiMessage": false,
"operationReturnFullProductInfo": false,
"chatMetadata": {
"productId": "product-789",
"title": "Waterproof Trail Jacket"
}
}'
Behaviour
- The API resolves the base product and determines suitable complementary product categories.
pageSizecontrols the requested number of bundle recommendations.- If multiple products match the supplied context, the stream may ask the shopper to confirm the base product.
- If the base product or complementary categories cannot be resolved, the stream returns a no-product response.
Streaming response
The response usestext/event-stream. Each data: line contains one JSON message:
data: {"chatStream":"Complete the look with these complementary products."}
data: {"data":{"responseType":"ProductBundling","responsePayload":[{"id":"product-901"}]}}
operationHideAiMessage to true to omit chatStream messages. Set operationReturnFullProductInfo to true to return full product objects instead of ID-only objects in responsePayload.Authorizations
A short-lived HS256 operation token. Its tenantId claim must exactly match the Tenantid header. Mint this token on a trusted server; never expose the tenant signing credential in browser code.
The preezie tenant identifier. This value identifies the catalogue and is not a secret.
Body
Natural-language request that guides the selected operation.
1"Show me lightweight black running shoes"
Conversation session identifier. Reuse it for related requests.
"session-123"
Stable identifier for the shopper or visitor.
"visitor-456"
Legacy top-level URL field. Use chatMetadata.websiteUrl for the current page context.
Optional context from the current product or page.
Show child attributes
Show child attributes
Source of the request. Use Operation for these endpoints.
Operation Explicit product identifiers consumed by operations such as comparison. For similarity and bundling, identify the base product with chatMetadata.productId instead.
Maximum number of product results requested. When omitted, the tenant's configured default is used.
x >= 1When true, suppresses chatStream events and returns only non-chat stream events.
When false, products in a conversation response payload are reduced to {"id": "..."} objects. When true, the full product objects are returned.
Response
A server-sent event stream. Each message is written as data: <JSON> followed by a blank line. The JSON payload contains one response key. operationHideAiMessage removes chatStream events; operationReturnFullProductInfo controls whether product payloads contain IDs only or full product objects.
A sequence of SSE messages whose data values follow the StreamEvent schema.
