curl --request POST \
--url https://salespilot.crossup.ai/v1/recommendations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"connection_id": "<string>",
"placement_key": "<string>",
"context_item_id": "<string>",
"cart_items": [
{
"item_id": "<string>",
"variant_id": "<string>",
"quantity": 2
}
],
"cart_id": "<string>",
"client": {
"page_url": "<string>",
"referrer": "<string>",
"utm": {
"source": "<string>",
"medium": "<string>",
"campaign": "<string>",
"term": "<string>",
"content": "<string>"
},
"languages": [
"<string>"
],
"timezone": "<string>",
"screen": {
"width": 1,
"height": 1,
"pixel_ratio": 1
},
"viewport": {
"width": 1,
"height": 1,
"pixel_ratio": 1
},
"connection": {
"effective_type": "<string>",
"downlink_mbps": 1,
"rtt_ms": 1,
"save_data": true
},
"device": {
"mobile": true,
"platform": "<string>",
"touch_points": 1,
"memory_gb": 1,
"cpu_cores": 1
}
}
}
'import requests
url = "https://salespilot.crossup.ai/v1/recommendations"
payload = {
"connection_id": "<string>",
"placement_key": "<string>",
"context_item_id": "<string>",
"cart_items": [
{
"item_id": "<string>",
"variant_id": "<string>",
"quantity": 2
}
],
"cart_id": "<string>",
"client": {
"page_url": "<string>",
"referrer": "<string>",
"utm": {
"source": "<string>",
"medium": "<string>",
"campaign": "<string>",
"term": "<string>",
"content": "<string>"
},
"languages": ["<string>"],
"timezone": "<string>",
"screen": {
"width": 1,
"height": 1,
"pixel_ratio": 1
},
"viewport": {
"width": 1,
"height": 1,
"pixel_ratio": 1
},
"connection": {
"effective_type": "<string>",
"downlink_mbps": 1,
"rtt_ms": 1,
"save_data": True
},
"device": {
"mobile": True,
"platform": "<string>",
"touch_points": 1,
"memory_gb": 1,
"cpu_cores": 1
}
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
connection_id: '<string>',
placement_key: '<string>',
context_item_id: '<string>',
cart_items: [{item_id: '<string>', variant_id: '<string>', quantity: 2}],
cart_id: '<string>',
client: {
page_url: '<string>',
referrer: '<string>',
utm: {
source: '<string>',
medium: '<string>',
campaign: '<string>',
term: '<string>',
content: '<string>'
},
languages: ['<string>'],
timezone: '<string>',
screen: {width: 1, height: 1, pixel_ratio: 1},
viewport: {width: 1, height: 1, pixel_ratio: 1},
connection: {effective_type: '<string>', downlink_mbps: 1, rtt_ms: 1, save_data: true},
device: {
mobile: true,
platform: '<string>',
touch_points: 1,
memory_gb: 1,
cpu_cores: 1
}
}
})
};
fetch('https://salespilot.crossup.ai/v1/recommendations', 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://salespilot.crossup.ai/v1/recommendations",
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([
'connection_id' => '<string>',
'placement_key' => '<string>',
'context_item_id' => '<string>',
'cart_items' => [
[
'item_id' => '<string>',
'variant_id' => '<string>',
'quantity' => 2
]
],
'cart_id' => '<string>',
'client' => [
'page_url' => '<string>',
'referrer' => '<string>',
'utm' => [
'source' => '<string>',
'medium' => '<string>',
'campaign' => '<string>',
'term' => '<string>',
'content' => '<string>'
],
'languages' => [
'<string>'
],
'timezone' => '<string>',
'screen' => [
'width' => 1,
'height' => 1,
'pixel_ratio' => 1
],
'viewport' => [
'width' => 1,
'height' => 1,
'pixel_ratio' => 1
],
'connection' => [
'effective_type' => '<string>',
'downlink_mbps' => 1,
'rtt_ms' => 1,
'save_data' => true
],
'device' => [
'mobile' => true,
'platform' => '<string>',
'touch_points' => 1,
'memory_gb' => 1,
'cpu_cores' => 1
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://salespilot.crossup.ai/v1/recommendations"
payload := strings.NewReader("{\n \"connection_id\": \"<string>\",\n \"placement_key\": \"<string>\",\n \"context_item_id\": \"<string>\",\n \"cart_items\": [\n {\n \"item_id\": \"<string>\",\n \"variant_id\": \"<string>\",\n \"quantity\": 2\n }\n ],\n \"cart_id\": \"<string>\",\n \"client\": {\n \"page_url\": \"<string>\",\n \"referrer\": \"<string>\",\n \"utm\": {\n \"source\": \"<string>\",\n \"medium\": \"<string>\",\n \"campaign\": \"<string>\",\n \"term\": \"<string>\",\n \"content\": \"<string>\"\n },\n \"languages\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\",\n \"screen\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"viewport\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"connection\": {\n \"effective_type\": \"<string>\",\n \"downlink_mbps\": 1,\n \"rtt_ms\": 1,\n \"save_data\": true\n },\n \"device\": {\n \"mobile\": true,\n \"platform\": \"<string>\",\n \"touch_points\": 1,\n \"memory_gb\": 1,\n \"cpu_cores\": 1\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
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.post("https://salespilot.crossup.ai/v1/recommendations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"connection_id\": \"<string>\",\n \"placement_key\": \"<string>\",\n \"context_item_id\": \"<string>\",\n \"cart_items\": [\n {\n \"item_id\": \"<string>\",\n \"variant_id\": \"<string>\",\n \"quantity\": 2\n }\n ],\n \"cart_id\": \"<string>\",\n \"client\": {\n \"page_url\": \"<string>\",\n \"referrer\": \"<string>\",\n \"utm\": {\n \"source\": \"<string>\",\n \"medium\": \"<string>\",\n \"campaign\": \"<string>\",\n \"term\": \"<string>\",\n \"content\": \"<string>\"\n },\n \"languages\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\",\n \"screen\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"viewport\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"connection\": {\n \"effective_type\": \"<string>\",\n \"downlink_mbps\": 1,\n \"rtt_ms\": 1,\n \"save_data\": true\n },\n \"device\": {\n \"mobile\": true,\n \"platform\": \"<string>\",\n \"touch_points\": 1,\n \"memory_gb\": 1,\n \"cpu_cores\": 1\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://salespilot.crossup.ai/v1/recommendations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"connection_id\": \"<string>\",\n \"placement_key\": \"<string>\",\n \"context_item_id\": \"<string>\",\n \"cart_items\": [\n {\n \"item_id\": \"<string>\",\n \"variant_id\": \"<string>\",\n \"quantity\": 2\n }\n ],\n \"cart_id\": \"<string>\",\n \"client\": {\n \"page_url\": \"<string>\",\n \"referrer\": \"<string>\",\n \"utm\": {\n \"source\": \"<string>\",\n \"medium\": \"<string>\",\n \"campaign\": \"<string>\",\n \"term\": \"<string>\",\n \"content\": \"<string>\"\n },\n \"languages\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\",\n \"screen\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"viewport\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"connection\": {\n \"effective_type\": \"<string>\",\n \"downlink_mbps\": 1,\n \"rtt_ms\": 1,\n \"save_data\": true\n },\n \"device\": {\n \"mobile\": true,\n \"platform\": \"<string>\",\n \"touch_points\": 1,\n \"memory_gb\": 1,\n \"cpu_cores\": 1\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"decision_id": "<string>",
"request_id": "<string>",
"store_id": "<string>",
"connection_id": "<string>",
"placement_key": "<string>",
"surface": "pdp",
"context": {
"cart_items": [
{
"item_id": "<string>",
"variant_id": "<string>",
"quantity": 2
}
],
"shooter": {
"item_id": "<string>",
"product": {
"item": {
"item_id": "<string>",
"store_id": "<string>",
"connection_id": "<string>",
"external_id": "<string>",
"title": {},
"status": "<string>",
"source_version": "<string>",
"primary_media": {
"url": "<string>",
"alt": {}
},
"description": {},
"handles": {},
"urls": {},
"media": [
{
"url": "<string>",
"alt": {}
}
],
"brand": "<string>",
"tags": [
"<string>"
],
"free_shipping": true,
"taxonomy": [
{
"taxonomy_id": "<string>",
"external_id": "<string>",
"name": {},
"handles": {},
"parent_id": "<string>"
}
]
},
"variants": [
{
"variant_id": "<string>",
"item_id": "<string>",
"external_id": "<string>",
"status": "<string>",
"sku": "<string>",
"title": {},
"price": {
"amount": "<string>",
"currency": "<string>"
},
"promotional_price": {
"amount": "<string>",
"currency": "<string>"
},
"attributes": [
{
"name": {},
"value": {}
}
]
}
],
"availability": [
{
"variant_id": "<string>",
"sellable": "<string>",
"as_of": "2023-11-07T05:31:56Z",
"quantity": 123
}
],
"refresh_revision": 2
}
}
},
"results": [
{
"item_id": "<string>",
"position": 2,
"reason_codes": [
"<string>"
],
"variant_id": "<string>",
"product": {
"item": {
"item_id": "<string>",
"store_id": "<string>",
"connection_id": "<string>",
"external_id": "<string>",
"title": {},
"status": "<string>",
"source_version": "<string>",
"primary_media": {
"url": "<string>",
"alt": {}
},
"description": {},
"handles": {},
"urls": {},
"media": [
{
"url": "<string>",
"alt": {}
}
],
"brand": "<string>",
"tags": [
"<string>"
],
"free_shipping": true,
"taxonomy": [
{
"taxonomy_id": "<string>",
"external_id": "<string>",
"name": {},
"handles": {},
"parent_id": "<string>"
}
]
},
"variants": [
{
"variant_id": "<string>",
"item_id": "<string>",
"external_id": "<string>",
"status": "<string>",
"sku": "<string>",
"title": {},
"price": {
"amount": "<string>",
"currency": "<string>"
},
"promotional_price": {
"amount": "<string>",
"currency": "<string>"
},
"attributes": [
{
"name": {},
"value": {}
}
]
}
],
"availability": [
{
"variant_id": "<string>",
"sellable": "<string>",
"as_of": "2023-11-07T05:31:56Z",
"quantity": 123
}
],
"refresh_revision": 2
}
}
],
"reason_codes": [
"<string>"
],
"generated_at": "2023-11-07T05:31:56Z",
"visitor": {
"visitor_id": "<string>",
"session_id": "<string>"
}
}{
"type": "https://api.crossup.ai/salespilot/errors/invalid-request",
"title": "Invalid request",
"status": 400,
"detail": "<string>",
"code": "invalid_request",
"request_id": "<string>",
"errors": [
{
"code": "<string>",
"detail": "<string>",
"pointer": "<string>"
}
]
}{
"type": "https://api.crossup.ai/salespilot/errors/unauthorized",
"title": "Authentication required",
"status": 401,
"detail": "<string>",
"code": "unauthorized",
"request_id": "<string>"
}{
"type": "https://api.crossup.ai/salespilot/errors/forbidden-connection",
"title": "Connection is not accessible",
"status": 403,
"detail": "<string>",
"code": "forbidden_connection",
"request_id": "<string>"
}{
"type": "https://api.crossup.ai/salespilot/errors/not-found",
"title": "Resource not found",
"status": 404,
"detail": "<string>",
"code": "not_found",
"request_id": "<string>"
}{
"type": "https://api.crossup.ai/salespilot/errors/cart-items-limit-exceeded",
"title": "Cart item limit exceeded",
"status": 422,
"detail": "<string>",
"code": "cart_items_limit_exceeded",
"request_id": "<string>",
"max_items_per_cart": 200,
"actual_items": 2
}{
"type": "https://api.crossup.ai/salespilot/errors/rate-limited",
"title": "Too many requests",
"status": 429,
"detail": "<string>",
"code": "rate_limited",
"request_id": "<string>"
}{
"type": "https://api.crossup.ai/salespilot/errors/internal-error",
"title": "Internal server error",
"status": 500,
"detail": "<string>",
"code": "internal_error",
"request_id": "<string>"
}Pedir una recomendación
Devuelve la recomendación para un momento del storefront: los productos en orden, cada uno ya proyectado al catálogo canónico.
curl --request POST \
--url https://salespilot.crossup.ai/v1/recommendations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"connection_id": "<string>",
"placement_key": "<string>",
"context_item_id": "<string>",
"cart_items": [
{
"item_id": "<string>",
"variant_id": "<string>",
"quantity": 2
}
],
"cart_id": "<string>",
"client": {
"page_url": "<string>",
"referrer": "<string>",
"utm": {
"source": "<string>",
"medium": "<string>",
"campaign": "<string>",
"term": "<string>",
"content": "<string>"
},
"languages": [
"<string>"
],
"timezone": "<string>",
"screen": {
"width": 1,
"height": 1,
"pixel_ratio": 1
},
"viewport": {
"width": 1,
"height": 1,
"pixel_ratio": 1
},
"connection": {
"effective_type": "<string>",
"downlink_mbps": 1,
"rtt_ms": 1,
"save_data": true
},
"device": {
"mobile": true,
"platform": "<string>",
"touch_points": 1,
"memory_gb": 1,
"cpu_cores": 1
}
}
}
'import requests
url = "https://salespilot.crossup.ai/v1/recommendations"
payload = {
"connection_id": "<string>",
"placement_key": "<string>",
"context_item_id": "<string>",
"cart_items": [
{
"item_id": "<string>",
"variant_id": "<string>",
"quantity": 2
}
],
"cart_id": "<string>",
"client": {
"page_url": "<string>",
"referrer": "<string>",
"utm": {
"source": "<string>",
"medium": "<string>",
"campaign": "<string>",
"term": "<string>",
"content": "<string>"
},
"languages": ["<string>"],
"timezone": "<string>",
"screen": {
"width": 1,
"height": 1,
"pixel_ratio": 1
},
"viewport": {
"width": 1,
"height": 1,
"pixel_ratio": 1
},
"connection": {
"effective_type": "<string>",
"downlink_mbps": 1,
"rtt_ms": 1,
"save_data": True
},
"device": {
"mobile": True,
"platform": "<string>",
"touch_points": 1,
"memory_gb": 1,
"cpu_cores": 1
}
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
connection_id: '<string>',
placement_key: '<string>',
context_item_id: '<string>',
cart_items: [{item_id: '<string>', variant_id: '<string>', quantity: 2}],
cart_id: '<string>',
client: {
page_url: '<string>',
referrer: '<string>',
utm: {
source: '<string>',
medium: '<string>',
campaign: '<string>',
term: '<string>',
content: '<string>'
},
languages: ['<string>'],
timezone: '<string>',
screen: {width: 1, height: 1, pixel_ratio: 1},
viewport: {width: 1, height: 1, pixel_ratio: 1},
connection: {effective_type: '<string>', downlink_mbps: 1, rtt_ms: 1, save_data: true},
device: {
mobile: true,
platform: '<string>',
touch_points: 1,
memory_gb: 1,
cpu_cores: 1
}
}
})
};
fetch('https://salespilot.crossup.ai/v1/recommendations', 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://salespilot.crossup.ai/v1/recommendations",
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([
'connection_id' => '<string>',
'placement_key' => '<string>',
'context_item_id' => '<string>',
'cart_items' => [
[
'item_id' => '<string>',
'variant_id' => '<string>',
'quantity' => 2
]
],
'cart_id' => '<string>',
'client' => [
'page_url' => '<string>',
'referrer' => '<string>',
'utm' => [
'source' => '<string>',
'medium' => '<string>',
'campaign' => '<string>',
'term' => '<string>',
'content' => '<string>'
],
'languages' => [
'<string>'
],
'timezone' => '<string>',
'screen' => [
'width' => 1,
'height' => 1,
'pixel_ratio' => 1
],
'viewport' => [
'width' => 1,
'height' => 1,
'pixel_ratio' => 1
],
'connection' => [
'effective_type' => '<string>',
'downlink_mbps' => 1,
'rtt_ms' => 1,
'save_data' => true
],
'device' => [
'mobile' => true,
'platform' => '<string>',
'touch_points' => 1,
'memory_gb' => 1,
'cpu_cores' => 1
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://salespilot.crossup.ai/v1/recommendations"
payload := strings.NewReader("{\n \"connection_id\": \"<string>\",\n \"placement_key\": \"<string>\",\n \"context_item_id\": \"<string>\",\n \"cart_items\": [\n {\n \"item_id\": \"<string>\",\n \"variant_id\": \"<string>\",\n \"quantity\": 2\n }\n ],\n \"cart_id\": \"<string>\",\n \"client\": {\n \"page_url\": \"<string>\",\n \"referrer\": \"<string>\",\n \"utm\": {\n \"source\": \"<string>\",\n \"medium\": \"<string>\",\n \"campaign\": \"<string>\",\n \"term\": \"<string>\",\n \"content\": \"<string>\"\n },\n \"languages\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\",\n \"screen\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"viewport\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"connection\": {\n \"effective_type\": \"<string>\",\n \"downlink_mbps\": 1,\n \"rtt_ms\": 1,\n \"save_data\": true\n },\n \"device\": {\n \"mobile\": true,\n \"platform\": \"<string>\",\n \"touch_points\": 1,\n \"memory_gb\": 1,\n \"cpu_cores\": 1\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
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.post("https://salespilot.crossup.ai/v1/recommendations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"connection_id\": \"<string>\",\n \"placement_key\": \"<string>\",\n \"context_item_id\": \"<string>\",\n \"cart_items\": [\n {\n \"item_id\": \"<string>\",\n \"variant_id\": \"<string>\",\n \"quantity\": 2\n }\n ],\n \"cart_id\": \"<string>\",\n \"client\": {\n \"page_url\": \"<string>\",\n \"referrer\": \"<string>\",\n \"utm\": {\n \"source\": \"<string>\",\n \"medium\": \"<string>\",\n \"campaign\": \"<string>\",\n \"term\": \"<string>\",\n \"content\": \"<string>\"\n },\n \"languages\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\",\n \"screen\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"viewport\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"connection\": {\n \"effective_type\": \"<string>\",\n \"downlink_mbps\": 1,\n \"rtt_ms\": 1,\n \"save_data\": true\n },\n \"device\": {\n \"mobile\": true,\n \"platform\": \"<string>\",\n \"touch_points\": 1,\n \"memory_gb\": 1,\n \"cpu_cores\": 1\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://salespilot.crossup.ai/v1/recommendations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"connection_id\": \"<string>\",\n \"placement_key\": \"<string>\",\n \"context_item_id\": \"<string>\",\n \"cart_items\": [\n {\n \"item_id\": \"<string>\",\n \"variant_id\": \"<string>\",\n \"quantity\": 2\n }\n ],\n \"cart_id\": \"<string>\",\n \"client\": {\n \"page_url\": \"<string>\",\n \"referrer\": \"<string>\",\n \"utm\": {\n \"source\": \"<string>\",\n \"medium\": \"<string>\",\n \"campaign\": \"<string>\",\n \"term\": \"<string>\",\n \"content\": \"<string>\"\n },\n \"languages\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\",\n \"screen\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"viewport\": {\n \"width\": 1,\n \"height\": 1,\n \"pixel_ratio\": 1\n },\n \"connection\": {\n \"effective_type\": \"<string>\",\n \"downlink_mbps\": 1,\n \"rtt_ms\": 1,\n \"save_data\": true\n },\n \"device\": {\n \"mobile\": true,\n \"platform\": \"<string>\",\n \"touch_points\": 1,\n \"memory_gb\": 1,\n \"cpu_cores\": 1\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"decision_id": "<string>",
"request_id": "<string>",
"store_id": "<string>",
"connection_id": "<string>",
"placement_key": "<string>",
"surface": "pdp",
"context": {
"cart_items": [
{
"item_id": "<string>",
"variant_id": "<string>",
"quantity": 2
}
],
"shooter": {
"item_id": "<string>",
"product": {
"item": {
"item_id": "<string>",
"store_id": "<string>",
"connection_id": "<string>",
"external_id": "<string>",
"title": {},
"status": "<string>",
"source_version": "<string>",
"primary_media": {
"url": "<string>",
"alt": {}
},
"description": {},
"handles": {},
"urls": {},
"media": [
{
"url": "<string>",
"alt": {}
}
],
"brand": "<string>",
"tags": [
"<string>"
],
"free_shipping": true,
"taxonomy": [
{
"taxonomy_id": "<string>",
"external_id": "<string>",
"name": {},
"handles": {},
"parent_id": "<string>"
}
]
},
"variants": [
{
"variant_id": "<string>",
"item_id": "<string>",
"external_id": "<string>",
"status": "<string>",
"sku": "<string>",
"title": {},
"price": {
"amount": "<string>",
"currency": "<string>"
},
"promotional_price": {
"amount": "<string>",
"currency": "<string>"
},
"attributes": [
{
"name": {},
"value": {}
}
]
}
],
"availability": [
{
"variant_id": "<string>",
"sellable": "<string>",
"as_of": "2023-11-07T05:31:56Z",
"quantity": 123
}
],
"refresh_revision": 2
}
}
},
"results": [
{
"item_id": "<string>",
"position": 2,
"reason_codes": [
"<string>"
],
"variant_id": "<string>",
"product": {
"item": {
"item_id": "<string>",
"store_id": "<string>",
"connection_id": "<string>",
"external_id": "<string>",
"title": {},
"status": "<string>",
"source_version": "<string>",
"primary_media": {
"url": "<string>",
"alt": {}
},
"description": {},
"handles": {},
"urls": {},
"media": [
{
"url": "<string>",
"alt": {}
}
],
"brand": "<string>",
"tags": [
"<string>"
],
"free_shipping": true,
"taxonomy": [
{
"taxonomy_id": "<string>",
"external_id": "<string>",
"name": {},
"handles": {},
"parent_id": "<string>"
}
]
},
"variants": [
{
"variant_id": "<string>",
"item_id": "<string>",
"external_id": "<string>",
"status": "<string>",
"sku": "<string>",
"title": {},
"price": {
"amount": "<string>",
"currency": "<string>"
},
"promotional_price": {
"amount": "<string>",
"currency": "<string>"
},
"attributes": [
{
"name": {},
"value": {}
}
]
}
],
"availability": [
{
"variant_id": "<string>",
"sellable": "<string>",
"as_of": "2023-11-07T05:31:56Z",
"quantity": 123
}
],
"refresh_revision": 2
}
}
],
"reason_codes": [
"<string>"
],
"generated_at": "2023-11-07T05:31:56Z",
"visitor": {
"visitor_id": "<string>",
"session_id": "<string>"
}
}{
"type": "https://api.crossup.ai/salespilot/errors/invalid-request",
"title": "Invalid request",
"status": 400,
"detail": "<string>",
"code": "invalid_request",
"request_id": "<string>",
"errors": [
{
"code": "<string>",
"detail": "<string>",
"pointer": "<string>"
}
]
}{
"type": "https://api.crossup.ai/salespilot/errors/unauthorized",
"title": "Authentication required",
"status": 401,
"detail": "<string>",
"code": "unauthorized",
"request_id": "<string>"
}{
"type": "https://api.crossup.ai/salespilot/errors/forbidden-connection",
"title": "Connection is not accessible",
"status": 403,
"detail": "<string>",
"code": "forbidden_connection",
"request_id": "<string>"
}{
"type": "https://api.crossup.ai/salespilot/errors/not-found",
"title": "Resource not found",
"status": 404,
"detail": "<string>",
"code": "not_found",
"request_id": "<string>"
}{
"type": "https://api.crossup.ai/salespilot/errors/cart-items-limit-exceeded",
"title": "Cart item limit exceeded",
"status": 422,
"detail": "<string>",
"code": "cart_items_limit_exceeded",
"request_id": "<string>",
"max_items_per_cart": 200,
"actual_items": 2
}{
"type": "https://api.crossup.ai/salespilot/errors/rate-limited",
"title": "Too many requests",
"status": 429,
"detail": "<string>",
"code": "rate_limited",
"request_id": "<string>"
}{
"type": "https://api.crossup.ai/salespilot/errors/internal-error",
"title": "Internal server error",
"status": 500,
"detail": "<string>",
"code": "internal_error",
"request_id": "<string>"
}Los seis momentos
surface | Cuándo | Qué hace falta |
|---|---|---|
pdp | Página de producto | context_item_id (el producto de partida) o al menos un ítem en cart_items |
cart | Al agregar al carrito (el popup, no la página del carrito) | ídem |
checkout | Al iniciar la compra | ídem |
success-page | Compra terminada | al menos un ítem en cart_items |
in-checkout | Dentro del checkout | al menos un ítem en cart_items |
carousel | La página del carrito | al menos un ítem en cart_items |
400 invalid_request y
pointer dice qué campo. Un context_item_id en un momento de carrito se
devuelve en context, pero no cambia la recomendación.
El request no elige la tienda
No haystore_id: el servidor saca la tienda de la clave y valida que
connection_id sea suyo. Ningún campo del cuerpo lee datos ajenos.
El visitante
visitor es opcional: { visitor_id, session_id? }, con forma vis_… y
ses_…. Nunca hace fallar el pedido: con otra forma se descarta y no se
guarda. Nunca es un dato del comprador:
Visitante y contexto.
Cada pedido queda registrado con su visitante y la recomendación que devolvió:
así un clic se liga después a ella.
Lo que devuelve
La respuesta es la recomendación (en la API,Decision: la lista de productos recomendados para ese momento).
decision_id: el id de la recomendación, único por respuesta. Dos pedidos iguales son dos recomendaciones.request_id: el mismo valor que el headerX-Request-ID.context: de qué partió la recomendación.shootertrae el producto de partida, ycart_items, el carrito tal como llegó.results[]:item_id,variant_id?,position,reason_codes[]yproduct, completo: ítem, taxonomía, variantes con precio y disponibilidad.
score ni id de la sugerencia del motor. El ranking es la
position, y un test del contrato falla si aparece un puntaje.product es opcional: si no se pudo leer, el resultado sale sin él y se
resuelve con leer el catálogo. item.description
viaja como la manda la plataforma; Tiendanube manda HTML, así que
sanitizalo.
reason_codes aparece en la recomendación y en cada resultado: uno explica la
respuesta entera, el otro esa posición. En una lista vacía, dice qué pasó:
| Código | Qué pasó |
|---|---|
no_offer | El motor no tiene nada para ese momento. |
module_not_configured | La tienda no tiene activado ese momento. |
missing_price | Un ítem llegó sin precio, y el motor lo necesita. |
unknown_external_id | El motor recomendó algo que el catálogo todavía no tiene; se omite. |
brain_unavailable | El motor no contestó a tiempo. La tienda sigue vendiendo. |
brain_error:<status> | El motor rechazó la consulta con ese status. |
cart_items es un array de objetos
Opcional (omitido es []), pero nunca null. Cada elemento es
{ item_id, variant_id, quantity }, con quantity ≥ 1. Pasado el límite, la
respuesta es cart_items_limit_exceeded,
con max_items_per_cart y actual_items.Autorizaciones
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Cuerpo
Every field but the connection, the placement and the surface is optional in the schema, and the surface decides what is needed. pdp, cart and checkout need a shooter (context_item_id) or at least one cart item. success-page, in-checkout and carousel need at least one cart item; a shooter sent with them is recorded and echoed but does not drive the engine. A request with neither is a 400.
cart_id is the store's own id for the cart and belongs with cart_items: send it whenever the cart is not empty. It is not required by the schema — a request without it is served normally — but the decision it produces cannot be tied back to a sale.
11The storefront moment that asks for recommendations. Three moments start from a product the shopper is looking at or just added (the shooter, context_item_id): pdp (product page), cart (right after adding to the cart) and checkout (when the purchase starts). The other three read only the cart: success-page (purchase finished), in-checkout (inside the checkout) and carousel (the cart page).
pdp, cart, checkout, success-page, in-checkout, carousel 1The shooter item (the product the moment starts from), when the moment has one.
1The cart as the storefront sees it. Omitted means empty.
Show child attributes
Show child attributes
The store's own id for this cart. Send it whenever cart_items is not empty: it is what ties the sale back to the offer once the order comes in through the webhook. A request that carries a cart without it still answers 200 and still serves a recommendation, but that decision cannot be attributed to a sale later.
1 - 256Pseudonymous identity of the browser that asks. The storefront SDK creates and keeps it; it carries no personal data and must never be an email, a phone number or a platform customer id. Sending it is optional, and a visitor that does not match this shape never fails the request: the server drops it, answers without it and does not store it.
Show child attributes
Show child attributes
What the storefront SDK can read in the browser about the request. Every field is optional and sending it never fails the request: a context the server cannot read is dropped and the recommendation is served anyway. The server also records the client IP, User-Agent, Accept-Language, Origin and Referer from the HTTP request; none of this is returned.
Show child attributes
Show child attributes
Respuesta
Recommendation decision
Unique per response. Signals about what was shown reference it.
1The same value as the X-Request-ID response header.
1111The storefront moment that asks for recommendations. Three moments start from a product the shopper is looking at or just added (the shooter, context_item_id): pdp (product page), cart (right after adding to the cart) and checkout (when the purchase starts). The other three read only the cart: success-page (purchase finished), in-checkout (inside the checkout) and carousel (the cart page).
pdp, cart, checkout, success-page, in-checkout, carousel 1What the decision was taken from, echoed so the storefront does not have to remember it.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
1Pseudonymous identity of the browser that asks. The storefront SDK creates and keeps it; it carries no personal data and must never be an email, a phone number or a platform customer id. Sending it is optional, and a visitor that does not match this shape never fails the request: the server drops it, answers without it and does not store it.
Show child attributes
Show child attributes