Assign semantic IDs
curl --request POST \
--url https://api.jeantechnologies.com/v1/semantic-ids \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tokenizer_id": "tok_9k2m",
"items": [
{
"item_id": "sku_771",
"title": "Merino crew socks",
"description": "Mid-weight, charcoal.",
"image_url": "https://acme.com/771.jpg",
"attributes": {
"brand": "Acme",
"category": "hosiery"
}
}
]
}
'import requests
url = "https://api.jeantechnologies.com/v1/semantic-ids"
payload = {
"tokenizer_id": "tok_9k2m",
"items": [
{
"item_id": "sku_771",
"title": "Merino crew socks",
"description": "Mid-weight, charcoal.",
"image_url": "https://acme.com/771.jpg",
"attributes": {
"brand": "Acme",
"category": "hosiery"
}
}
]
}
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({
tokenizer_id: 'tok_9k2m',
items: [
{
item_id: 'sku_771',
title: 'Merino crew socks',
description: 'Mid-weight, charcoal.',
image_url: 'https://acme.com/771.jpg',
attributes: {brand: 'Acme', category: 'hosiery'}
}
]
})
};
fetch('https://api.jeantechnologies.com/v1/semantic-ids', 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.jeantechnologies.com/v1/semantic-ids",
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([
'tokenizer_id' => 'tok_9k2m',
'items' => [
[
'item_id' => 'sku_771',
'title' => 'Merino crew socks',
'description' => 'Mid-weight, charcoal.',
'image_url' => 'https://acme.com/771.jpg',
'attributes' => [
'brand' => 'Acme',
'category' => 'hosiery'
]
]
]
]),
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.jeantechnologies.com/v1/semantic-ids"
payload := strings.NewReader("{\n \"tokenizer_id\": \"tok_9k2m\",\n \"items\": [\n {\n \"item_id\": \"sku_771\",\n \"title\": \"Merino crew socks\",\n \"description\": \"Mid-weight, charcoal.\",\n \"image_url\": \"https://acme.com/771.jpg\",\n \"attributes\": {\n \"brand\": \"Acme\",\n \"category\": \"hosiery\"\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://api.jeantechnologies.com/v1/semantic-ids")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tokenizer_id\": \"tok_9k2m\",\n \"items\": [\n {\n \"item_id\": \"sku_771\",\n \"title\": \"Merino crew socks\",\n \"description\": \"Mid-weight, charcoal.\",\n \"image_url\": \"https://acme.com/771.jpg\",\n \"attributes\": {\n \"brand\": \"Acme\",\n \"category\": \"hosiery\"\n }\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.jeantechnologies.com/v1/semantic-ids")
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 \"tokenizer_id\": \"tok_9k2m\",\n \"items\": [\n {\n \"item_id\": \"sku_771\",\n \"title\": \"Merino crew socks\",\n \"description\": \"Mid-weight, charcoal.\",\n \"image_url\": \"https://acme.com/771.jpg\",\n \"attributes\": {\n \"brand\": \"Acme\",\n \"category\": \"hosiery\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"semantic_ids": [
{
"item_id": "sku_771",
"codes": [
1487,
302,
91,
12
],
"tokens": "<sid_0_1487><sid_1_302><sid_2_91><sid_3_12>",
"cold_start": false,
"collision_suffix": 123
}
]
}{
"error": {
"code": "invalid_request",
"message": "Field 'domain' is required.",
"details": {}
}
}Semantic IDs
Assign semantic IDs
Assign semantic IDs to items against a fitted tokenizer.
POST
/
semantic-ids
Assign semantic IDs
curl --request POST \
--url https://api.jeantechnologies.com/v1/semantic-ids \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tokenizer_id": "tok_9k2m",
"items": [
{
"item_id": "sku_771",
"title": "Merino crew socks",
"description": "Mid-weight, charcoal.",
"image_url": "https://acme.com/771.jpg",
"attributes": {
"brand": "Acme",
"category": "hosiery"
}
}
]
}
'import requests
url = "https://api.jeantechnologies.com/v1/semantic-ids"
payload = {
"tokenizer_id": "tok_9k2m",
"items": [
{
"item_id": "sku_771",
"title": "Merino crew socks",
"description": "Mid-weight, charcoal.",
"image_url": "https://acme.com/771.jpg",
"attributes": {
"brand": "Acme",
"category": "hosiery"
}
}
]
}
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({
tokenizer_id: 'tok_9k2m',
items: [
{
item_id: 'sku_771',
title: 'Merino crew socks',
description: 'Mid-weight, charcoal.',
image_url: 'https://acme.com/771.jpg',
attributes: {brand: 'Acme', category: 'hosiery'}
}
]
})
};
fetch('https://api.jeantechnologies.com/v1/semantic-ids', 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.jeantechnologies.com/v1/semantic-ids",
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([
'tokenizer_id' => 'tok_9k2m',
'items' => [
[
'item_id' => 'sku_771',
'title' => 'Merino crew socks',
'description' => 'Mid-weight, charcoal.',
'image_url' => 'https://acme.com/771.jpg',
'attributes' => [
'brand' => 'Acme',
'category' => 'hosiery'
]
]
]
]),
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.jeantechnologies.com/v1/semantic-ids"
payload := strings.NewReader("{\n \"tokenizer_id\": \"tok_9k2m\",\n \"items\": [\n {\n \"item_id\": \"sku_771\",\n \"title\": \"Merino crew socks\",\n \"description\": \"Mid-weight, charcoal.\",\n \"image_url\": \"https://acme.com/771.jpg\",\n \"attributes\": {\n \"brand\": \"Acme\",\n \"category\": \"hosiery\"\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://api.jeantechnologies.com/v1/semantic-ids")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tokenizer_id\": \"tok_9k2m\",\n \"items\": [\n {\n \"item_id\": \"sku_771\",\n \"title\": \"Merino crew socks\",\n \"description\": \"Mid-weight, charcoal.\",\n \"image_url\": \"https://acme.com/771.jpg\",\n \"attributes\": {\n \"brand\": \"Acme\",\n \"category\": \"hosiery\"\n }\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.jeantechnologies.com/v1/semantic-ids")
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 \"tokenizer_id\": \"tok_9k2m\",\n \"items\": [\n {\n \"item_id\": \"sku_771\",\n \"title\": \"Merino crew socks\",\n \"description\": \"Mid-weight, charcoal.\",\n \"image_url\": \"https://acme.com/771.jpg\",\n \"attributes\": {\n \"brand\": \"Acme\",\n \"category\": \"hosiery\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"semantic_ids": [
{
"item_id": "sku_771",
"codes": [
1487,
302,
91,
12
],
"tokens": "<sid_0_1487><sid_1_302><sid_2_91><sid_3_12>",
"cold_start": false,
"collision_suffix": 123
}
]
}{
"error": {
"code": "invalid_request",
"message": "Field 'domain' is required.",
"details": {}
}
}Encode items into codes. Use this to backfill a catalog after fitting, to register new items as they go live, or to export semantic IDs into a ranker you already operate.
The
curl https://api.jeantechnologies.com/v1/semantic-ids \
-H "Authorization: Bearer $JEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tokenizer_id": "tok_9k2m",
"items": [
{
"item_id": "sku_771",
"title": "Merino crew socks",
"description": "Mid-weight, charcoal.",
"image_url": "https://acme.com/771.jpg"
}
]
}'
res = requests.post(
"https://api.jeantechnologies.com/v1/semantic-ids",
headers={"Authorization": f"Bearer {os.environ['JEAN_API_KEY']}"},
json={
"tokenizer_id": "tok_9k2m",
"items": [
{
"item_id": "sku_771",
"title": "Merino crew socks",
"description": "Mid-weight, charcoal.",
}
],
},
).json()
const res = await fetch("https://api.jeantechnologies.com/v1/semantic-ids", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.JEAN_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
tokenizer_id: "tok_9k2m",
items: [
{
item_id: "sku_771",
title: "Merino crew socks",
description: "Mid-weight, charcoal.",
},
],
}),
});
const { semantic_ids } = await res.json();
Response
{
"semantic_ids": [
{
"item_id": "sku_771",
"codes": [1487, 302, 91, 12],
"tokens": "<sid_0_1487><sid_1_302><sid_2_91><sid_3_12>",
"cold_start": false,
"collision_suffix": null
}
]
}
Cold start
An item that was not in the catalog at fit time is still assignable, because the code is a function of content rather than of interaction history. Send it the moment it goes live and it is recommendable on the nextPOST /generate call.
{
"item_id": "sku_new",
"codes": [1487, 88, 405, 3],
"tokens": "<sid_0_1487><sid_1_88><sid_2_405><sid_3_3>",
"cold_start": true
}
cold_start flag is worth logging. It lets you measure quality on items the tokenizer never saw, which is the number that tells you whether the fit generalized or memorized.
Cold-start assignment does not update the codebooks. If your catalog drifts far enough that new items cluster in regions the fit never covered, utilization will look fine while quality quietly degrades. Refit on distribution shift.
Determinism and stability
The same item content against the sametokenizer_id always returns the same codes. This is the point of keeping collaborative signal out of the quantizer input: an item’s identifier does not move as it gets popular.
Codes are stable across POST /semantic-ids calls but not across refits. A new tokenizer_id is a new code space. Plan a reindex when you refit, and keep the old tokenizer live until the cutover completes.
Batches are capped at 1000 items per call. For a full catalog backfill, the tokenizer fit already assigns every item in
catalog.uri, so you should not need to page through it manually.Authorizations
API key issued by Jean Technologies. Contact the team for access.
Body
application/json
Response
Semantic IDs assigned
Show child attributes
Show child attributes
⌘I

