Record what the shopper did with a decision
curl --request POST \
--url https://salespilot.crossup.ai/v1/connections/{connection_id}/storefront-signals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"signals": [
{
"signal_id": "sig_01JB3Z8YQK7N2VME5T4RD9WX0A",
"type": "impression",
"occurred_at": "2026-09-17T12:00:00Z",
"decision_id": "dec_7k2m9q4v8x1z5c3b6n0j7h2f4d",
"position": 1,
"visitor": {
"visitor_id": "vis_Q2x9mT4pL7rK1sV8",
"session_id": "ses_Hn3bW6yZ0cF5dJ2e"
},
"client": {
"page_url": "https://tienda-demo.example/productos/remera",
"languages": [
"es-AR"
],
"timezone": "America/Argentina/Buenos_Aires",
"viewport": {
"width": 390,
"height": 844,
"pixel_ratio": 3
}
}
},
{
"signal_id": "sig_01JB3Z9C6M0PT8RHY2KWFA5N3B",
"type": "add_to_cart",
"occurred_at": "2026-09-17T12:00:11Z",
"decision_id": "dec_7k2m9q4v8x1z5c3b6n0j7h2f4d",
"item_id": "itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8",
"variant_id": "var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1",
"position": 1,
"quantity": 1,
"visitor": {
"visitor_id": "vis_Q2x9mT4pL7rK1sV8",
"session_id": "ses_Hn3bW6yZ0cF5dJ2e"
}
}
]
}
'import requests
url = "https://salespilot.crossup.ai/v1/connections/{connection_id}/storefront-signals"
payload = { "signals": [
{
"signal_id": "sig_01JB3Z8YQK7N2VME5T4RD9WX0A",
"type": "impression",
"occurred_at": "2026-09-17T12:00:00Z",
"decision_id": "dec_7k2m9q4v8x1z5c3b6n0j7h2f4d",
"position": 1,
"visitor": {
"visitor_id": "vis_Q2x9mT4pL7rK1sV8",
"session_id": "ses_Hn3bW6yZ0cF5dJ2e"
},
"client": {
"page_url": "https://tienda-demo.example/productos/remera",
"languages": ["es-AR"],
"timezone": "America/Argentina/Buenos_Aires",
"viewport": {
"width": 390,
"height": 844,
"pixel_ratio": 3
}
}
},
{
"signal_id": "sig_01JB3Z9C6M0PT8RHY2KWFA5N3B",
"type": "add_to_cart",
"occurred_at": "2026-09-17T12:00:11Z",
"decision_id": "dec_7k2m9q4v8x1z5c3b6n0j7h2f4d",
"item_id": "itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8",
"variant_id": "var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1",
"position": 1,
"quantity": 1,
"visitor": {
"visitor_id": "vis_Q2x9mT4pL7rK1sV8",
"session_id": "ses_Hn3bW6yZ0cF5dJ2e"
}
}
] }
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({
signals: [
{
signal_id: 'sig_01JB3Z8YQK7N2VME5T4RD9WX0A',
type: 'impression',
occurred_at: '2026-09-17T12:00:00Z',
decision_id: 'dec_7k2m9q4v8x1z5c3b6n0j7h2f4d',
position: 1,
visitor: {visitor_id: 'vis_Q2x9mT4pL7rK1sV8', session_id: 'ses_Hn3bW6yZ0cF5dJ2e'},
client: {
page_url: 'https://tienda-demo.example/productos/remera',
languages: ['es-AR'],
timezone: 'America/Argentina/Buenos_Aires',
viewport: {width: 390, height: 844, pixel_ratio: 3}
}
},
{
signal_id: 'sig_01JB3Z9C6M0PT8RHY2KWFA5N3B',
type: 'add_to_cart',
occurred_at: '2026-09-17T12:00:11Z',
decision_id: 'dec_7k2m9q4v8x1z5c3b6n0j7h2f4d',
item_id: 'itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8',
variant_id: 'var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1',
position: 1,
quantity: 1,
visitor: {visitor_id: 'vis_Q2x9mT4pL7rK1sV8', session_id: 'ses_Hn3bW6yZ0cF5dJ2e'}
}
]
})
};
fetch('https://salespilot.crossup.ai/v1/connections/{connection_id}/storefront-signals', 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/connections/{connection_id}/storefront-signals",
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([
'signals' => [
[
'signal_id' => 'sig_01JB3Z8YQK7N2VME5T4RD9WX0A',
'type' => 'impression',
'occurred_at' => '2026-09-17T12:00:00Z',
'decision_id' => 'dec_7k2m9q4v8x1z5c3b6n0j7h2f4d',
'position' => 1,
'visitor' => [
'visitor_id' => 'vis_Q2x9mT4pL7rK1sV8',
'session_id' => 'ses_Hn3bW6yZ0cF5dJ2e'
],
'client' => [
'page_url' => 'https://tienda-demo.example/productos/remera',
'languages' => [
'es-AR'
],
'timezone' => 'America/Argentina/Buenos_Aires',
'viewport' => [
'width' => 390,
'height' => 844,
'pixel_ratio' => 3
]
]
],
[
'signal_id' => 'sig_01JB3Z9C6M0PT8RHY2KWFA5N3B',
'type' => 'add_to_cart',
'occurred_at' => '2026-09-17T12:00:11Z',
'decision_id' => 'dec_7k2m9q4v8x1z5c3b6n0j7h2f4d',
'item_id' => 'itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8',
'variant_id' => 'var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1',
'position' => 1,
'quantity' => 1,
'visitor' => [
'visitor_id' => 'vis_Q2x9mT4pL7rK1sV8',
'session_id' => 'ses_Hn3bW6yZ0cF5dJ2e'
]
]
]
]),
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/connections/{connection_id}/storefront-signals"
payload := strings.NewReader("{\n \"signals\": [\n {\n \"signal_id\": \"sig_01JB3Z8YQK7N2VME5T4RD9WX0A\",\n \"type\": \"impression\",\n \"occurred_at\": \"2026-09-17T12:00:00Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"position\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n },\n \"client\": {\n \"page_url\": \"https://tienda-demo.example/productos/remera\",\n \"languages\": [\n \"es-AR\"\n ],\n \"timezone\": \"America/Argentina/Buenos_Aires\",\n \"viewport\": {\n \"width\": 390,\n \"height\": 844,\n \"pixel_ratio\": 3\n }\n }\n },\n {\n \"signal_id\": \"sig_01JB3Z9C6M0PT8RHY2KWFA5N3B\",\n \"type\": \"add_to_cart\",\n \"occurred_at\": \"2026-09-17T12:00:11Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"item_id\": \"itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8\",\n \"variant_id\": \"var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1\",\n \"position\": 1,\n \"quantity\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n }\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/connections/{connection_id}/storefront-signals")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"signals\": [\n {\n \"signal_id\": \"sig_01JB3Z8YQK7N2VME5T4RD9WX0A\",\n \"type\": \"impression\",\n \"occurred_at\": \"2026-09-17T12:00:00Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"position\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n },\n \"client\": {\n \"page_url\": \"https://tienda-demo.example/productos/remera\",\n \"languages\": [\n \"es-AR\"\n ],\n \"timezone\": \"America/Argentina/Buenos_Aires\",\n \"viewport\": {\n \"width\": 390,\n \"height\": 844,\n \"pixel_ratio\": 3\n }\n }\n },\n {\n \"signal_id\": \"sig_01JB3Z9C6M0PT8RHY2KWFA5N3B\",\n \"type\": \"add_to_cart\",\n \"occurred_at\": \"2026-09-17T12:00:11Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"item_id\": \"itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8\",\n \"variant_id\": \"var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1\",\n \"position\": 1,\n \"quantity\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n }\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://salespilot.crossup.ai/v1/connections/{connection_id}/storefront-signals")
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 \"signals\": [\n {\n \"signal_id\": \"sig_01JB3Z8YQK7N2VME5T4RD9WX0A\",\n \"type\": \"impression\",\n \"occurred_at\": \"2026-09-17T12:00:00Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"position\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n },\n \"client\": {\n \"page_url\": \"https://tienda-demo.example/productos/remera\",\n \"languages\": [\n \"es-AR\"\n ],\n \"timezone\": \"America/Argentina/Buenos_Aires\",\n \"viewport\": {\n \"width\": 390,\n \"height\": 844,\n \"pixel_ratio\": 3\n }\n }\n },\n {\n \"signal_id\": \"sig_01JB3Z9C6M0PT8RHY2KWFA5N3B\",\n \"type\": \"add_to_cart\",\n \"occurred_at\": \"2026-09-17T12:00:11Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"item_id\": \"itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8\",\n \"variant_id\": \"var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1\",\n \"position\": 1,\n \"quantity\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"results": [
{
"index": 0,
"signal_id": "sig_01JB3Z8YQK7N2VME5T4RD9WX0A",
"status": "accepted"
},
{
"index": 1,
"signal_id": "sig_01JB3Z9C6M0PT8RHY2KWFA5N3B",
"status": "duplicate"
},
{
"index": 2,
"signal_id": "sig_01JB3ZAD7N1QU9SJZ3LXGB6P4C",
"status": "rejected",
"reason": "unknown_decision"
}
]
}{
"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/signal-batch-limit-exceeded",
"title": "Signal batch limit exceeded",
"status": 422,
"detail": "<string>",
"code": "signal_batch_limit_exceeded",
"request_id": "<string>",
"max_signals_per_batch": 50,
"actual_signals": 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>"
}{
"type": "https://api.crossup.ai/salespilot/errors/signals-unavailable",
"title": "Signals cannot be recorded right now",
"status": 503,
"detail": "<string>",
"code": "signals_unavailable",
"request_id": "<string>"
}Operations
Record storefront signals
Stores what the shopper did with an already served recommendation and forwards it to the engine, which remains the owner of interactions.
POST
/
v1
/
connections
/
{connection_id}
/
storefront-signals
Record what the shopper did with a decision
curl --request POST \
--url https://salespilot.crossup.ai/v1/connections/{connection_id}/storefront-signals \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"signals": [
{
"signal_id": "sig_01JB3Z8YQK7N2VME5T4RD9WX0A",
"type": "impression",
"occurred_at": "2026-09-17T12:00:00Z",
"decision_id": "dec_7k2m9q4v8x1z5c3b6n0j7h2f4d",
"position": 1,
"visitor": {
"visitor_id": "vis_Q2x9mT4pL7rK1sV8",
"session_id": "ses_Hn3bW6yZ0cF5dJ2e"
},
"client": {
"page_url": "https://tienda-demo.example/productos/remera",
"languages": [
"es-AR"
],
"timezone": "America/Argentina/Buenos_Aires",
"viewport": {
"width": 390,
"height": 844,
"pixel_ratio": 3
}
}
},
{
"signal_id": "sig_01JB3Z9C6M0PT8RHY2KWFA5N3B",
"type": "add_to_cart",
"occurred_at": "2026-09-17T12:00:11Z",
"decision_id": "dec_7k2m9q4v8x1z5c3b6n0j7h2f4d",
"item_id": "itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8",
"variant_id": "var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1",
"position": 1,
"quantity": 1,
"visitor": {
"visitor_id": "vis_Q2x9mT4pL7rK1sV8",
"session_id": "ses_Hn3bW6yZ0cF5dJ2e"
}
}
]
}
'import requests
url = "https://salespilot.crossup.ai/v1/connections/{connection_id}/storefront-signals"
payload = { "signals": [
{
"signal_id": "sig_01JB3Z8YQK7N2VME5T4RD9WX0A",
"type": "impression",
"occurred_at": "2026-09-17T12:00:00Z",
"decision_id": "dec_7k2m9q4v8x1z5c3b6n0j7h2f4d",
"position": 1,
"visitor": {
"visitor_id": "vis_Q2x9mT4pL7rK1sV8",
"session_id": "ses_Hn3bW6yZ0cF5dJ2e"
},
"client": {
"page_url": "https://tienda-demo.example/productos/remera",
"languages": ["es-AR"],
"timezone": "America/Argentina/Buenos_Aires",
"viewport": {
"width": 390,
"height": 844,
"pixel_ratio": 3
}
}
},
{
"signal_id": "sig_01JB3Z9C6M0PT8RHY2KWFA5N3B",
"type": "add_to_cart",
"occurred_at": "2026-09-17T12:00:11Z",
"decision_id": "dec_7k2m9q4v8x1z5c3b6n0j7h2f4d",
"item_id": "itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8",
"variant_id": "var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1",
"position": 1,
"quantity": 1,
"visitor": {
"visitor_id": "vis_Q2x9mT4pL7rK1sV8",
"session_id": "ses_Hn3bW6yZ0cF5dJ2e"
}
}
] }
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({
signals: [
{
signal_id: 'sig_01JB3Z8YQK7N2VME5T4RD9WX0A',
type: 'impression',
occurred_at: '2026-09-17T12:00:00Z',
decision_id: 'dec_7k2m9q4v8x1z5c3b6n0j7h2f4d',
position: 1,
visitor: {visitor_id: 'vis_Q2x9mT4pL7rK1sV8', session_id: 'ses_Hn3bW6yZ0cF5dJ2e'},
client: {
page_url: 'https://tienda-demo.example/productos/remera',
languages: ['es-AR'],
timezone: 'America/Argentina/Buenos_Aires',
viewport: {width: 390, height: 844, pixel_ratio: 3}
}
},
{
signal_id: 'sig_01JB3Z9C6M0PT8RHY2KWFA5N3B',
type: 'add_to_cart',
occurred_at: '2026-09-17T12:00:11Z',
decision_id: 'dec_7k2m9q4v8x1z5c3b6n0j7h2f4d',
item_id: 'itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8',
variant_id: 'var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1',
position: 1,
quantity: 1,
visitor: {visitor_id: 'vis_Q2x9mT4pL7rK1sV8', session_id: 'ses_Hn3bW6yZ0cF5dJ2e'}
}
]
})
};
fetch('https://salespilot.crossup.ai/v1/connections/{connection_id}/storefront-signals', 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/connections/{connection_id}/storefront-signals",
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([
'signals' => [
[
'signal_id' => 'sig_01JB3Z8YQK7N2VME5T4RD9WX0A',
'type' => 'impression',
'occurred_at' => '2026-09-17T12:00:00Z',
'decision_id' => 'dec_7k2m9q4v8x1z5c3b6n0j7h2f4d',
'position' => 1,
'visitor' => [
'visitor_id' => 'vis_Q2x9mT4pL7rK1sV8',
'session_id' => 'ses_Hn3bW6yZ0cF5dJ2e'
],
'client' => [
'page_url' => 'https://tienda-demo.example/productos/remera',
'languages' => [
'es-AR'
],
'timezone' => 'America/Argentina/Buenos_Aires',
'viewport' => [
'width' => 390,
'height' => 844,
'pixel_ratio' => 3
]
]
],
[
'signal_id' => 'sig_01JB3Z9C6M0PT8RHY2KWFA5N3B',
'type' => 'add_to_cart',
'occurred_at' => '2026-09-17T12:00:11Z',
'decision_id' => 'dec_7k2m9q4v8x1z5c3b6n0j7h2f4d',
'item_id' => 'itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8',
'variant_id' => 'var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1',
'position' => 1,
'quantity' => 1,
'visitor' => [
'visitor_id' => 'vis_Q2x9mT4pL7rK1sV8',
'session_id' => 'ses_Hn3bW6yZ0cF5dJ2e'
]
]
]
]),
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/connections/{connection_id}/storefront-signals"
payload := strings.NewReader("{\n \"signals\": [\n {\n \"signal_id\": \"sig_01JB3Z8YQK7N2VME5T4RD9WX0A\",\n \"type\": \"impression\",\n \"occurred_at\": \"2026-09-17T12:00:00Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"position\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n },\n \"client\": {\n \"page_url\": \"https://tienda-demo.example/productos/remera\",\n \"languages\": [\n \"es-AR\"\n ],\n \"timezone\": \"America/Argentina/Buenos_Aires\",\n \"viewport\": {\n \"width\": 390,\n \"height\": 844,\n \"pixel_ratio\": 3\n }\n }\n },\n {\n \"signal_id\": \"sig_01JB3Z9C6M0PT8RHY2KWFA5N3B\",\n \"type\": \"add_to_cart\",\n \"occurred_at\": \"2026-09-17T12:00:11Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"item_id\": \"itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8\",\n \"variant_id\": \"var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1\",\n \"position\": 1,\n \"quantity\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n }\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/connections/{connection_id}/storefront-signals")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"signals\": [\n {\n \"signal_id\": \"sig_01JB3Z8YQK7N2VME5T4RD9WX0A\",\n \"type\": \"impression\",\n \"occurred_at\": \"2026-09-17T12:00:00Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"position\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n },\n \"client\": {\n \"page_url\": \"https://tienda-demo.example/productos/remera\",\n \"languages\": [\n \"es-AR\"\n ],\n \"timezone\": \"America/Argentina/Buenos_Aires\",\n \"viewport\": {\n \"width\": 390,\n \"height\": 844,\n \"pixel_ratio\": 3\n }\n }\n },\n {\n \"signal_id\": \"sig_01JB3Z9C6M0PT8RHY2KWFA5N3B\",\n \"type\": \"add_to_cart\",\n \"occurred_at\": \"2026-09-17T12:00:11Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"item_id\": \"itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8\",\n \"variant_id\": \"var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1\",\n \"position\": 1,\n \"quantity\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n }\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://salespilot.crossup.ai/v1/connections/{connection_id}/storefront-signals")
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 \"signals\": [\n {\n \"signal_id\": \"sig_01JB3Z8YQK7N2VME5T4RD9WX0A\",\n \"type\": \"impression\",\n \"occurred_at\": \"2026-09-17T12:00:00Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"position\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n },\n \"client\": {\n \"page_url\": \"https://tienda-demo.example/productos/remera\",\n \"languages\": [\n \"es-AR\"\n ],\n \"timezone\": \"America/Argentina/Buenos_Aires\",\n \"viewport\": {\n \"width\": 390,\n \"height\": 844,\n \"pixel_ratio\": 3\n }\n }\n },\n {\n \"signal_id\": \"sig_01JB3Z9C6M0PT8RHY2KWFA5N3B\",\n \"type\": \"add_to_cart\",\n \"occurred_at\": \"2026-09-17T12:00:11Z\",\n \"decision_id\": \"dec_7k2m9q4v8x1z5c3b6n0j7h2f4d\",\n \"item_id\": \"itm_01JB2XQ7W9E4R6T8Y0U2I4O6P8\",\n \"variant_id\": \"var_01JB2XQ7W9E4R6T8Y0U2I4O6Q1\",\n \"position\": 1,\n \"quantity\": 1,\n \"visitor\": {\n \"visitor_id\": \"vis_Q2x9mT4pL7rK1sV8\",\n \"session_id\": \"ses_Hn3bW6yZ0cF5dJ2e\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"results": [
{
"index": 0,
"signal_id": "sig_01JB3Z8YQK7N2VME5T4RD9WX0A",
"status": "accepted"
},
{
"index": 1,
"signal_id": "sig_01JB3Z9C6M0PT8RHY2KWFA5N3B",
"status": "duplicate"
},
{
"index": 2,
"signal_id": "sig_01JB3ZAD7N1QU9SJZ3LXGB6P4C",
"status": "rejected",
"reason": "unknown_decision"
}
]
}{
"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/signal-batch-limit-exceeded",
"title": "Signal batch limit exceeded",
"status": 422,
"detail": "<string>",
"code": "signal_batch_limit_exceeded",
"request_id": "<string>",
"max_signals_per_batch": 50,
"actual_signals": 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>"
}{
"type": "https://api.crossup.ai/salespilot/errors/signals-unavailable",
"title": "Signals cannot be recorded right now",
"status": 503,
"detail": "<string>",
"code": "signals_unavailable",
"request_id": "<string>"
}This one records what the shopper did. To update the catalog, the
operation is Ingest a catalog event.
A signal belongs to a recommendation
Every signal carries thedecision_id: the id of the recommendation that
getRecommendations returned. In the API that
object is Decision, the list of products recommended for that moment. The id is
unique per response: two impressions of the same offer are two different recommendations.
The signal does not carry the engine’s ids: the server stored them when it
served the recommendation. If they came from the browser, anyone with the public key
could point an interaction at another offer.
decision_id must exist and belong to this connection. If not, the
response is rejected with reason: unknown_decision, the same as for an id
that never existed: that way nobody can probe other stores’ recommendations.
The batch is answered signal by signal
Up to 50 signals per request; more issignal_batch_limit_exceeded and none is stored. The
response is 202 with one result per position:
status | What happened |
|---|---|
accepted | Stored and queued for the engine |
duplicate | That signal_id already existed. No new work |
rejected | Not stored. reason says why |
Resending the same batch is safe
signal_id is generated by the SDK and is stable across retries: the
second arrival answers duplicate with no new work.
Which fields each type carries
type | item_id | quantity | order_external_id |
|---|---|---|---|
impression | — (it belongs to the whole recommendation) | — | — |
click | required | — | — |
add_to_cart | required | optional: added to the line (1 if missing) | — |
remove_from_cart | required | — | — |
update_quantity | required | required: sets the line; 0 removes it | — |
purchase | required | optional | optional |
dismiss | required | — | — |
item_id and variant_id are canonical ids (itm_, var_), the same as
in the recommendation. The server translates them to the store’s ids.
Each signal is a change, not the whole cart
The server keeps what the shopper holds from each recommendation: one line per item and variant.add_to_cart adds, update_quantity sets,
remove_from_cart removes. Each signal sends only its change and the server
builds the running state: a lost signal doesn’t erase what came before, and a
resend doesn’t add twice.
A 503 asks for a retry
If the store is unavailable, the response is503 signals_unavailable and
none of the batch’s signals was stored. The SDK keeps the batch and sends
it again. A recommendation, by contrast, is served even if recording fails.
What the server stores
To audit the request: IP,User-Agent, Accept-Language, Origin,
Referer and the SDK’s client. None of it comes back in the response.
The contract limits the shape of visitor: it can’t be an email or a phone.
A malformed visitor or client is dropped: the signal is stored without
it, with a warning that leaves out the value.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
CrossUp connection identifier.
Minimum string length:
1Body
application/json
Required array length:
1 - 50 elementsShow child attributes
Show child attributes
Response
The batch was answered signal by signal
Show child attributes
Show child attributes