Get recommendation sets
curl --request POST \
--url https://api.neuronsearchlab.com/v1/recommendations/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"user_id": "user-abc123",
"requests": [
{
"key": "for_you",
"context_id": 101,
"limit": 12
},
{
"key": "similar",
"context_id": 102,
"item_id": 3187,
"limit": 6
}
]
}
'import requests
url = "https://api.neuronsearchlab.com/v1/recommendations/batch"
payload = {
"user_id": "user-abc123",
"requests": [
{
"key": "for_you",
"context_id": 101,
"limit": 12
},
{
"key": "similar",
"context_id": 102,
"item_id": 3187,
"limit": 6
}
]
}
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({
user_id: 'user-abc123',
requests: [
{key: 'for_you', context_id: 101, limit: 12},
{key: 'similar', context_id: 102, item_id: 3187, limit: 6}
]
})
};
fetch('https://api.neuronsearchlab.com/v1/recommendations/batch', 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.neuronsearchlab.com/v1/recommendations/batch",
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([
'user_id' => 'user-abc123',
'requests' => [
[
'key' => 'for_you',
'context_id' => 101,
'limit' => 12
],
[
'key' => 'similar',
'context_id' => 102,
'item_id' => 3187,
'limit' => 6
]
]
]),
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://api.neuronsearchlab.com/v1/recommendations/batch"
payload := strings.NewReader("{\n \"user_id\": \"user-abc123\",\n \"requests\": [\n {\n \"key\": \"for_you\",\n \"context_id\": 101,\n \"limit\": 12\n },\n {\n \"key\": \"similar\",\n \"context_id\": 102,\n \"item_id\": 3187,\n \"limit\": 6\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://api.neuronsearchlab.com/v1/recommendations/batch")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"user_id\": \"user-abc123\",\n \"requests\": [\n {\n \"key\": \"for_you\",\n \"context_id\": 101,\n \"limit\": 12\n },\n {\n \"key\": \"similar\",\n \"context_id\": 102,\n \"item_id\": 3187,\n \"limit\": 6\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.neuronsearchlab.com/v1/recommendations/batch")
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 \"user_id\": \"user-abc123\",\n \"requests\": [\n {\n \"key\": \"for_you\",\n \"context_id\": 101,\n \"limit\": 12\n },\n {\n \"key\": \"similar\",\n \"context_id\": 102,\n \"item_id\": 3187,\n \"limit\": 6\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"object": "recommendation_set_list",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"results": [
{
"key": "<string>",
"status": 200,
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"context_id": 123,
"data": [
{
"id": 3187,
"object": "recommendation",
"item_id": 3187,
"rank": 1,
"score": 0.94,
"item": {
"id": 3187,
"object": "item",
"name": "Wireless Headphones",
"description": "Noise-cancelling Bluetooth headphones.",
"metadata": {
"category": "electronics",
"brand": "Acme",
"price": 10999,
"currency": "usd"
}
},
"entity_id": 3187,
"name": "Wireless Headphones",
"description": "Noise-cancelling Bluetooth headphones.",
"metadata": {
"category": "electronics",
"brand": "Acme",
"price": 10999,
"currency": "usd"
},
"source": "model",
"explanation": {
"item_id": 2,
"rank": 123,
"summary": "<string>",
"shown_because": [
"<string>"
],
"source": "<string>",
"score": {
"final": 123,
"base": 123,
"cosine_distance": 123,
"retrieval": 123,
"ranker": 123
},
"context": {
"context_id": 2,
"mode": "single",
"filters": [
{}
],
"request_filters": [
{
"column": "<string>",
"operator": "<string>",
"value": "<string>",
"logic": "AND"
}
],
"group_by": [
"<string>"
],
"exclude_viewed_items": {
"value": 123,
"unit": "<string>",
"interval": "<string>"
},
"auto_section": {
"section_id": "<string>",
"title": "<string>",
"subtitle": "<string>",
"reason": {}
}
},
"embedding": {},
"pipeline": {
"id": 123,
"stages": [
{
"stage": "<string>",
"enabled": true,
"status": "<string>",
"pipeline_id": 123,
"config": {},
"note": "<string>",
"item_events": [
{}
]
}
]
},
"rules": [
{}
],
"experiments": [
{
"experiment_id": 123,
"experiment_name": "<string>",
"variant_id": 123,
"variant_name": "<string>"
}
],
"user_segments": [
"<string>"
]
}
}
],
"reuse": {
"reused": true,
"age_ms": 123
},
"error": {
"code": "<string>",
"message": "<string>"
}
}
],
"usage": {
"sets": 123,
"computed": 123,
"reused": 123,
"coalesced": 123
}
}{
"error": {
"type": "invalid_request_error",
"code": "validation_error",
"message": "Validation error",
"details": {
"fieldErrors": {
"name": [
"Required"
]
}
}
}
}{
"error": {
"type": "authentication_error",
"code": "unauthorized_no_client_id_in_jwt",
"message": "Unauthorized: No client ID in JWT"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"details": "<unknown>",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"details": "<unknown>",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}Recommendations
Get recommendation sets
Every recommendation rail on a page in one request.
POST
/
v1
/
recommendations
/
batch
Get recommendation sets
curl --request POST \
--url https://api.neuronsearchlab.com/v1/recommendations/batch \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"user_id": "user-abc123",
"requests": [
{
"key": "for_you",
"context_id": 101,
"limit": 12
},
{
"key": "similar",
"context_id": 102,
"item_id": 3187,
"limit": 6
}
]
}
'import requests
url = "https://api.neuronsearchlab.com/v1/recommendations/batch"
payload = {
"user_id": "user-abc123",
"requests": [
{
"key": "for_you",
"context_id": 101,
"limit": 12
},
{
"key": "similar",
"context_id": 102,
"item_id": 3187,
"limit": 6
}
]
}
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({
user_id: 'user-abc123',
requests: [
{key: 'for_you', context_id: 101, limit: 12},
{key: 'similar', context_id: 102, item_id: 3187, limit: 6}
]
})
};
fetch('https://api.neuronsearchlab.com/v1/recommendations/batch', 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.neuronsearchlab.com/v1/recommendations/batch",
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([
'user_id' => 'user-abc123',
'requests' => [
[
'key' => 'for_you',
'context_id' => 101,
'limit' => 12
],
[
'key' => 'similar',
'context_id' => 102,
'item_id' => 3187,
'limit' => 6
]
]
]),
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://api.neuronsearchlab.com/v1/recommendations/batch"
payload := strings.NewReader("{\n \"user_id\": \"user-abc123\",\n \"requests\": [\n {\n \"key\": \"for_you\",\n \"context_id\": 101,\n \"limit\": 12\n },\n {\n \"key\": \"similar\",\n \"context_id\": 102,\n \"item_id\": 3187,\n \"limit\": 6\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://api.neuronsearchlab.com/v1/recommendations/batch")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"user_id\": \"user-abc123\",\n \"requests\": [\n {\n \"key\": \"for_you\",\n \"context_id\": 101,\n \"limit\": 12\n },\n {\n \"key\": \"similar\",\n \"context_id\": 102,\n \"item_id\": 3187,\n \"limit\": 6\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.neuronsearchlab.com/v1/recommendations/batch")
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 \"user_id\": \"user-abc123\",\n \"requests\": [\n {\n \"key\": \"for_you\",\n \"context_id\": 101,\n \"limit\": 12\n },\n {\n \"key\": \"similar\",\n \"context_id\": 102,\n \"item_id\": 3187,\n \"limit\": 6\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"object": "recommendation_set_list",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"results": [
{
"key": "<string>",
"status": 200,
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"context_id": 123,
"data": [
{
"id": 3187,
"object": "recommendation",
"item_id": 3187,
"rank": 1,
"score": 0.94,
"item": {
"id": 3187,
"object": "item",
"name": "Wireless Headphones",
"description": "Noise-cancelling Bluetooth headphones.",
"metadata": {
"category": "electronics",
"brand": "Acme",
"price": 10999,
"currency": "usd"
}
},
"entity_id": 3187,
"name": "Wireless Headphones",
"description": "Noise-cancelling Bluetooth headphones.",
"metadata": {
"category": "electronics",
"brand": "Acme",
"price": 10999,
"currency": "usd"
},
"source": "model",
"explanation": {
"item_id": 2,
"rank": 123,
"summary": "<string>",
"shown_because": [
"<string>"
],
"source": "<string>",
"score": {
"final": 123,
"base": 123,
"cosine_distance": 123,
"retrieval": 123,
"ranker": 123
},
"context": {
"context_id": 2,
"mode": "single",
"filters": [
{}
],
"request_filters": [
{
"column": "<string>",
"operator": "<string>",
"value": "<string>",
"logic": "AND"
}
],
"group_by": [
"<string>"
],
"exclude_viewed_items": {
"value": 123,
"unit": "<string>",
"interval": "<string>"
},
"auto_section": {
"section_id": "<string>",
"title": "<string>",
"subtitle": "<string>",
"reason": {}
}
},
"embedding": {},
"pipeline": {
"id": 123,
"stages": [
{
"stage": "<string>",
"enabled": true,
"status": "<string>",
"pipeline_id": 123,
"config": {},
"note": "<string>",
"item_events": [
{}
]
}
]
},
"rules": [
{}
],
"experiments": [
{
"experiment_id": 123,
"experiment_name": "<string>",
"variant_id": 123,
"variant_name": "<string>"
}
],
"user_segments": [
"<string>"
]
}
}
],
"reuse": {
"reused": true,
"age_ms": 123
},
"error": {
"code": "<string>",
"message": "<string>"
}
}
],
"usage": {
"sets": 123,
"computed": 123,
"reused": 123,
"coalesced": 123
}
}{
"error": {
"type": "invalid_request_error",
"code": "validation_error",
"message": "Validation error",
"details": {
"fieldErrors": {
"name": [
"Required"
]
}
}
}
}{
"error": {
"type": "authentication_error",
"code": "unauthorized_no_client_id_in_jwt",
"message": "Unauthorized: No client ID in JWT"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"details": "<unknown>",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": {
"type": "invalid_request_error",
"code": "<string>",
"message": "<string>",
"details": "<unknown>",
"request_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}Description
A page with several rails, such as “For you”, “Similar items” and “Trending”, can ask for all of them in one request instead of one request per rail. Each set runs exactly asGET /v1/recommendations would run it, so a set returns the same results it would return on its own.
The sets share the work they have in common. The visitor’s history is read once for the whole page, and two identical sets in one batch are computed once.
Each set is billed as its own recommendation set, the same as a separate GET /v1/recommendations call: a batch of five different sets counts as five. Two identical sets in one batch are computed once and billed once.
Request
POST /v1/recommendations/batch
Content-Type: application/json
{
"user_id": "user-abc123",
"session_id": "session-42",
"requests": [
{ "key": "for_you", "context_id": 101, "limit": 12 },
{ "key": "similar", "context_id": 102, "item_id": 3187, "limit": 6 },
{ "key": "vans_only", "context_id": 103, "filters": ["type:van"] }
]
}
| Field | Type | Required | Description |
|---|---|---|---|
user_id | string | no | End-user identifier, shared by every set. Falls back to the token subject when omitted. |
anonymous_id | string | no | Anonymous identifier for visitors without a user_id. |
session_id | string | no | Session identifier for served-recommendation telemetry. |
request_id | string (UUID) | no | Batch ID. Retrying with the same request_id gives each set the same request ID, so a retried page is billed once. |
requests | array | yes | One to eight sets. |
| Field | Type | Required | Description |
|---|---|---|---|
key | string | yes | Your name for the rail, unique within the batch. Letters, digits, _, ., : and -, at most 64 characters. |
context_id | integer | yes | Context ID generated by the dashboard. |
limit | integer | no | Number of recommendations. Defaults to 20, maximum 100. A batch holds at most 200 items in total. |
item_id | integer | no | Seed item for item-to-item contexts. |
cart_item_ids | integer[] | no | Basket items for basket-aware contexts. |
page_type | string | no | Page type, as on GET /v1/recommendations. |
filters | string[] | no | Metadata filter shorthand, as repeated filter parameters. |
scope | object | no | Request scope, currently honouring filters. |
query | string | no | Runs this set as a search. |
mode, cursor, starting_after) is not part of a batch. Page through a rail with GET /v1/recommendations.
Response
{
"object": "recommendation_set_list",
"request_id": "0b8e5f4c-8a37-4c1e-9b0f-3d5f2a6c1e90",
"results": [
{
"key": "for_you",
"status": 200,
"request_id": "5b6f3f0e-0d1c-5a7e-9f3b-2c1d4e5f6a7b",
"context_id": 101,
"object": "list",
"data": [
{ "id": "7f3a2c9e", "object": "recommendation", "item_id": 3187, "rank": 1, "score": 0.94 }
],
"limit": 12
},
{
"key": "vans_only",
"status": 404,
"request_id": "a1d2c3b4-5e6f-5a7b-8c9d-0e1f2a3b4c5d",
"context_id": 103,
"error": { "code": "invalid_context", "message": "Context not found" }
}
],
"usage": { "sets": 3, "computed": 3, "reused": 0, "coalesced": 0 }
}
results has one entry per set, in request order. A served set carries the same fields as a GET /v1/recommendations response, except the duplicate recommendations array. Send each set’s own request_id with the events from that rail so clicks are attributed to it.
A set that fails comes back with its own status and error, and the other sets are still served. The batch itself fails only when the request is malformed or unauthorised.
usage.sets is the number of sets in the batch. computed, reused and coalesced say how many were ranked, served again from an identical answer a moment earlier, or shared with an identical set in the same batch. Computed and reused sets are billed; a coalesced set is not, and it carries the same request_id as the set it shares, since it is the same answer. A reused set carries reuse: { "reused": true, "age_ms": … } and its own request_id.
SDKs
const { sets } = await sdk.getRecommendationSets({
userId: 'user-abc123',
sets: [
{ key: 'for_you', contextId: 101, limit: 12 },
{ key: 'similar', contextId: 102, itemId: 3187, limit: 6 },
],
});
getRecommendationSets, and @neuronsearchlab/nextjs offers nsl.recommendSets. Each one splits a page of more than eight sets into several batches for you. The embed script batches placeholders on the same page automatically.
Errors
| Status | Scenario |
|---|---|
400 | Malformed body, more than eight sets, more than 200 items in total, a duplicate or invalid key, or a pagination field in a set |
401 | Missing/invalid access token or tenant resolution failed |
403 | Token does not include neuronsearchlab-api/read |
500 | Unexpected failure before any set ran |
Authorizations
The access token received from the authorization server in the OAuth 2.0 flow.
Body
application/json
Was this page helpful?

