Pre-launch API. The concepts described here are settled, but the API shape is not: request and response fields, parameters and defaults can still change. Build against it, and talk to your Luigi's Box contact before you put an integration into production.
A recommender takes anchors — the products the current context is about — and returns items related to them. A surface for pages with nothing to anchor on answers with the most popular products.
POST /discovery/v1/recommender serves every placement: the product page strip, the cart
cross-sell, the homepage carousel, the abandoned-basket email.
Request
Section titled “Request”curl -X POST 'https://api.eu1.luigisbox.ai/discovery/v1/recommender?channel_id=lbn_4hj9tv&surface_id=lbs_recommender_similar' \ -H 'Authorization: Bearer <token>' \ -H 'X-Lbx-Visitor-Id: 8f14e45f-ea0f-4b5c-9a1d-2b3c4d5e6f70' \ -H 'Content-Type: application/json' \ -d '{ "type": "product", "touchpoint": "pdp", "anchor_ids": ["product/sku-1001"], "size": 8 }'| Query parameter | Required | Notes |
|---|---|---|
channel_id | Yes | Serving destination |
surface_id | Yes | Must be a recommender surface |
| Body field | Required | Default | Notes |
|---|---|---|---|
type | Yes | — | Usually product |
touchpoint | No | none | Where the recommendations appear. Any of the touchpoints — a recommender serves every one |
anchor_ids | No | none | Up to 50 object identities the recommendation is based on |
exclude_ids | No | none | Up to 50 object identities to keep out of the slate |
size | No | 10 | 1–100 |
filters | No | none | Filter tree |
return_fields | No | surface default | Up to 100 fields — see Selecting fields |
user_id / personalize | No | anonymous / true | Personalization |
Anchors are full typed identities, exactly as they appear in @id, in one array:
{ "anchor_ids": ["product/sku-1001", "product/sku-2087"] }A bare value with no type — "sku-1001" — is rejected with a 422, and so is an anchor
whose type is not the one the surface is configured to take.
There is no sort and no cursor: a recommender returns one fixed-size slate.
Response
Section titled “Response”{ "hits": [ { "@id": "product/sku-2087", "@type": "product", "@title": "Blue Linen Shirt", "price": 44.9 } ]}Recommendations are a fixed-size slate, not a browsable result set, so the response carries no
cursor and no count: there is no page two of a carousel, there are no facets over one, and the
slate is hits — its length is the count. There is no request_key either: the slate is not
cached, so neither /facets nor /variants can
address it.
Choosing the surfaces
Section titled “Choosing the surfaces”Which model runs, what it considers related, and how it treats the anchors are all the surface’s configuration — not request fields. A surface is called from every page that shows the same recommendations, and a place that needs its own tuning or business rules has a surface of its own:
| Recommender | Anchors you send | Called from | Surface, by example |
|---|---|---|---|
| Similar items | The product being viewed | Product page | lbs_recommender_similar |
| Bought together | The product being viewed | Product page | lbs_recommender_xsell_pdp |
| Bought together | Every product in the cart | Cart | lbs_recommender_xsell_basket |
| Bought together | The product just added | The add-to-cart popup | lbs_recommender_xsell_basket_popup |
| Popular products | None | Homepage, landing pages, category or brand strips | lbs_recommender_popular |
The three bought-together surfaces read the same model. They are separate so that each place carries its own tuning and its own campaigns, which target surfaces, not touchpoints.
A recommendation never returns its anchors. By default it also leaves out the other variants of each anchor (the same product in another colour or size), so a shopper on a product page is not shown the product they already look at. A surface can turn this off.
Each request names its touchpoint, which is recorded with it, so calls from different
pages can be told apart. filters narrow one request without a surface of its own: three
similar-items strips over three categories are one surface called three times. Retuning a
surface retunes it everywhere it is called.
Recommending with no anchors
Section titled “Recommending with no anchors”A recommender for pages with nothing to anchor on, such as the homepage and landing pages,
is a surface of its own: lbs_recommender_popular answers with the most popular products.
Send no anchor_ids, and narrow it with filters where a strip shows one category or brand.
Products with no recorded popularity are left out, so a new catalog’s slate can be shorter
than size, or empty.
curl -X POST 'https://api.eu1.luigisbox.ai/discovery/v1/recommender?channel_id=lbn_4hj9tv&surface_id=lbs_recommender_popular' \ -H 'Authorization: Bearer <token>' \ -H 'X-Lbx-Visitor-Id: 8f14e45f-ea0f-4b5c-9a1d-2b3c4d5e6f70' \ -H 'Content-Type: application/json' \ -d '{ "type": "product", "touchpoint": "homepage", "size": 12 }'Filtering recommendations
Section titled “Filtering recommendations”A surface can limit how many recommendations share a brand, category, or another attribute. Several limits apply together. Products without a value for an attribute do not consume that attribute’s limit. A product with several category values counts once toward each category’s limit.
With strict limits, a response can contain fewer products than the requested
size. A surface can instead allow expansion: it selects products within the
limits first, then fills empty slots with skipped eligible products in rank order.
Expansion can exceed the group limits. Filters and variant grouping still apply.
Active pins within the requested slate count toward the limits first and keep
their positions after variant grouping, moving up only if the slate ends before
their slot. Pins alone can exceed the limits. Pins outside the requested slate
and fully decayed soft pins are selected in rank order like other products.
filters applies to recommendations as on the other endpoints. Two common uses:
// Never recommend what cannot be bought{ "availability": { "eq": 1 } }
// Never recommend across a boundary that would confuse the shopper{ "gender": { "in": ["women", "unisex"] } }On a bought-together surface, filters drop the model’s recommendations that do not match,
and matching popular products fill the rest, so under a narrow filter the slate is mostly
popular products.
Excluding objects the shopper has already seen
Section titled “Excluding objects the shopper has already seen”exclude_ids names objects the slate must not contain — what is already in the cart, or what
another widget higher up the page is showing. Pass identities in the same form as anchor_ids,
up to 50.
{ "type": "product", "touchpoint": "basket", "anchor_ids": ["product/9c8f2a"], "exclude_ids": ["product/3d41b7", "product/7e05c2"], "size": 10}The objects are removed as the surface retrieves, not trimmed from the finished slate, so
excluding costs you no slots: the surface still serves size recommendations as long as it has
that many others to serve. The anchors themselves are always excluded and need not be repeated
here.
Send the field only when you have something to exclude; an empty array is the same as omitting it.
exclude_ids is not the same as an @id filter
Section titled “exclude_ids is not the same as an @id filter”A filter can name the same objects:
{ "filters": { "@id": { "not_in": ["product/3d41b7"] } } }The two differ in what may override them. exclude_ids binds every object in the slate. A filter
is one of the caller’s own selections, and a pin from a
business-rules campaign is allowed to place a product
the caller’s filters excluded — so a campaign pinning product/3d41b7 puts it back in the slate,
and exclude_ids is what keeps it out.
Reach for exclude_ids when an object must not appear whatever a campaign says, and for filters
when you are narrowing the pool a recommendation is drawn from.
It suppresses the objects you name, not their other variants: under variant collapsing a different colour of an excluded object can still represent its group. And it cannot create inventory — excluding a large share of a small catalog leaves the slate short for the ordinary reason, that there is nothing else to serve.
Reporting
Section titled “Reporting”The slate is recorded when the request is served, including which surface answered and which anchors you sent. Report what the shopper does with it — clicks, cart additions, purchases. See Sending events.
See also
Section titled “See also”Was this page helpful?
Thanks.