Predict
POST /models/{model_id}/predict
The backbone without the catalog decoder in front of it. Send a history, get a distribution over what happens next.
This differs from /generate in a way that matters. /generate decodes
semantic IDs under a beam constrained to a fitted tokenizer, so it always returns items you
stock. /predict needs no tokenizer and can answer about the action as well as the object,
including actions that are not catalog items at all.
- curl
- Python
- TypeScript
curl https://api.jeantechnologies.com/v1/models/jean-rec-1/predict \
-H "Authorization: Bearer $JEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"history": [
{"action": "view", "item_id": "sku_310", "ts": 1735689600},
{"action": "view", "item_id": "sku_884", "ts": 1736294400},
{"action": "add_cart", "item_id": "sku_884", "ts": 1736294460}
],
"top_k": 5
}'
out = requests.post(
"https://api.jeantechnologies.com/v1/models/jean-rec-1/predict",
headers={"Authorization": f"Bearer {os.environ['JEAN_API_KEY']}"},
json={
"history": [
{"action": "view", "item_id": "sku_310", "ts": 1735689600},
{"action": "add_cart", "item_id": "sku_884", "ts": 1736294460},
],
"top_k": 5,
},
).json()
const res = await fetch(
"https://api.jeantechnologies.com/v1/models/jean-rec-1/predict",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.JEAN_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
history: [
{ action: "view", item_id: "sku_310", ts: 1735689600 },
{ action: "add_cart", item_id: "sku_884", ts: 1736294460 },
],
top_k: 5,
}),
},
);
const { predictions } = await res.json();
Body
| Field | Type | Default | Notes |
|---|---|---|---|
history | object[] | required | Ordered oldest first. Each entry takes action, an optional item_id, and an optional ts unix timestamp. |
top_k | integer | 10 | 1 to 100. |
horizon | integer | 1 | How many steps ahead to predict. Above 1, probabilities are marginal per step, not joint. |
filters | object | Hard constraints on candidate items. |
Bare strings are accepted in history as shorthand for {"action": "interact", "item_id": ...},
which is what /generate takes. Use the object form when the action type
carries signal, because a view and a return are very different evidence about the same item.
Response
{
"predictions": [
{"action": "purchase", "item_id": "sku_884", "probability": 0.41},
{"action": "view", "item_id": "sku_402", "probability": 0.17},
{"action": "churn", "item_id": null, "probability": 0.06}
],
"model": "jean-rec-1",
"version": "1.0.0"
}
Probabilities are over the modeled action space and sum to 1 across the full distribution, not
across the truncated top_k you get back. Do not renormalize the slice and treat it as a
complete picture.
item_id: null is meaningful. Actions like churn, session end, or return are predictions about
the person rather than about any item, and they are often the ones worth alerting on.
Timestamps carry signal
ts is optional and worth sending. Three views a minute apart and three views a month apart are
different states, and the model is trained on the gaps as well as the order.
Timestamps must be non-decreasing. An out-of-order history is accepted rather than rejected, but it is silently sorted, and if the disorder came from a bug in your event pipeline the sorted version is not the sequence that actually happened.