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.
const url = 'https://api.eu1.luigisbox.ai/platform/v1/catalogs/example/surfaces';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"input_type":"example","intent":"search","output_types":["product","category","brand","query","article"],"slug":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.eu1.luigisbox.ai/platform/v1/catalogs/example/surfaces \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "input_type": "example", "intent": "search", "output_types": [ "product", "category", "brand", "query", "article" ], "slug": "example" }'Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Request Body required
Section titled “Request Body required ”object
The kind of discovery this Surface performs — it fixes which Discovery API endpoint serves the Surface and what input a request must supply (search a query, recommender anchor objects, collection a scope). It is the contract, not the algorithm: a search Surface may retrieve lexically, semantically or both. Immutable — it is the middle slot of the surface id lbs_<intent>_<slug>, so changing it means a new Surface.
Catalog object types this surface may answer with. Non-empty; duplicates collapse and input order is preserved. Acts as an allowlist: a request asking for a type absent from this list is rejected rather than answered with fewer results. It is a property of the surface, not of its kind — a recommender declares whatever it recommends, so a category recommender carries category.
object
The kind of discovery this Surface performs — it fixes which Discovery API endpoint serves the Surface and what input a request must supply (search a query, recommender anchor objects, collection a scope). It is the contract, not the algorithm: a search Surface may retrieve lexically, semantically or both. Immutable — it is the middle slot of the surface id lbs_<intent>_<slug>, so changing it means a new Surface.
Catalog object types this surface may answer with. Non-empty; duplicates collapse and input order is preserved. Acts as an allowlist: a request asking for a type absent from this list is rejected rather than answered with fewer results. It is a property of the surface, not of its kind — a recommender declares whatever it recommends, so a category recommender carries category.
object
Catalog object type of the anchor objects this surface is queried with — what a recommender request names in anchor_ids. Required for recommender surfaces and rejected for every other kind, which take no anchor.
The kind of discovery this Surface performs — it fixes which Discovery API endpoint serves the Surface and what input a request must supply (search a query, recommender anchor objects, collection a scope). It is the contract, not the algorithm: a search Surface may retrieve lexically, semantically or both. Immutable — it is the middle slot of the surface id lbs_<intent>_<slug>, so changing it means a new Surface.
Catalog object types this surface may answer with. Non-empty; duplicates collapse and input order is preserved. Acts as an allowlist: a request asking for a type absent from this list is rejected rather than answered with fewer results. It is a property of the surface, not of its kind — a recommender declares whatever it recommends, so a category recommender carries category.
Responses
Section titled “ Responses ”Successful Response
object
The kind of discovery this Surface performs — it fixes which Discovery API endpoint serves the Surface and what input a request must supply (search a query, recommender anchor objects, collection a scope). It is the contract, not the algorithm: a search Surface may retrieve lexically, semantically or both. Immutable — it is the middle slot of the surface id lbs_<intent>_<slug>, so changing it means a new Surface.
Catalog object types this surface may answer with. Non-empty; duplicates collapse and input order is preserved. Acts as an allowlist: a request asking for a type absent from this list is rejected rather than answered with fewer results. It is a property of the surface, not of its kind — a recommender declares whatever it recommends, so a category recommender carries category.
The surface-dimension tags this surface belongs to, ordered by name, each carrying both its id and its name — the id is what the tag_id filter takes, the name is what a person reads, and neither needs a further request. Read-only here: membership is changed through POST /platform/v1/tags, or PATCH /platform/v1/tags/{tag_id} with add_members / remove_members, which carry {catalog_id, surface_id} pairs. A surface belongs to at most 20 tags.
A tag as another entity’s response reports it: the id to act on, and the name to show.
Both, because each answers a different question and neither substitutes for the other. The id is what every write and filter takes, so acting on the tag needs no lookup; the name is what a person reads, so displaying it needs none either. A bare id would force a second request for something the server already had in hand.
Not the full :class:Tag: an entity’s tag list is a reference, not a copy — repeating the
members and audit columns of a tag on every surface that belongs to it would grow without
bound and go stale between the two.
A tag a caller sends stays a bare id (CampaignCreate.surface_tags and its siblings). A
request field cannot take this shape without making the write response impossible to send
back unchanged, so the rule is: send an id, receive an id and a name.
object
The tag’s id — what tag_id filters and the tag writes take.
Tag name as namespace:value, lowercased on write (intent:SEARCH is stored as intent:search). The intent, language and recommender namespaces are platform-managed: writing one requires platform:reserved-tags:write and deleting one requires platform:reserved-tags:delete.
Example
{ "intent": "search"}Missing or invalid credentials
Canonical error body — every non-2xx response uses this shape.
object
Machine-readable error context; empty object when there is nothing to add.
object
Stable machine code naming why a well-formed request was refused: snake_case, prefixed by its domain — e.g. filter_unknown_field or cursor_mismatch. Safe to branch on; reason is not. Absent when the status code says all there is to say.
Every field-level problem found in the request, when validation is what failed. Absent when the rejection is not about a specific value.
One field-level reason a request was rejected.
object
Path to the offending value from the request root, e.g. ["body", "filters", 0, "operator"].
What is wrong with the value at loc.
Stable machine code for the problem, e.g. missing or string_too_short.
Human-readable, actionable error message.
Example generated
{ "exception_details": { "error_code": "example", "validation_errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ] }, "reason": "example", "request_id": "example"}Authenticated but not permitted
Canonical error body — every non-2xx response uses this shape.
object
Machine-readable error context; empty object when there is nothing to add.
object
Stable machine code naming why a well-formed request was refused: snake_case, prefixed by its domain — e.g. filter_unknown_field or cursor_mismatch. Safe to branch on; reason is not. Absent when the status code says all there is to say.
Every field-level problem found in the request, when validation is what failed. Absent when the rejection is not about a specific value.
One field-level reason a request was rejected.
object
Path to the offending value from the request root, e.g. ["body", "filters", 0, "operator"].
What is wrong with the value at loc.
Stable machine code for the problem, e.g. missing or string_too_short.
Human-readable, actionable error message.
Example generated
{ "exception_details": { "error_code": "example", "validation_errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ] }, "reason": "example", "request_id": "example"}State conflict
Canonical error body — every non-2xx response uses this shape.
object
Machine-readable error context; empty object when there is nothing to add.
object
Stable machine code naming why a well-formed request was refused: snake_case, prefixed by its domain — e.g. filter_unknown_field or cursor_mismatch. Safe to branch on; reason is not. Absent when the status code says all there is to say.
Every field-level problem found in the request, when validation is what failed. Absent when the rejection is not about a specific value.
One field-level reason a request was rejected.
object
Path to the offending value from the request root, e.g. ["body", "filters", 0, "operator"].
What is wrong with the value at loc.
Stable machine code for the problem, e.g. missing or string_too_short.
Human-readable, actionable error message.
Example generated
{ "exception_details": { "error_code": "example", "validation_errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ] }, "reason": "example", "request_id": "example"}Request validation failed
Canonical error body — every non-2xx response uses this shape.
object
Machine-readable error context; empty object when there is nothing to add.
object
Stable machine code naming why a well-formed request was refused: snake_case, prefixed by its domain — e.g. filter_unknown_field or cursor_mismatch. Safe to branch on; reason is not. Absent when the status code says all there is to say.
Every field-level problem found in the request, when validation is what failed. Absent when the rejection is not about a specific value.
One field-level reason a request was rejected.
object
Path to the offending value from the request root, e.g. ["body", "filters", 0, "operator"].
What is wrong with the value at loc.
Stable machine code for the problem, e.g. missing or string_too_short.
Human-readable, actionable error message.
Example generated
{ "exception_details": { "error_code": "example", "validation_errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ] }, "reason": "example", "request_id": "example"}Was this page helpful?
Thanks.