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 hit carries catalog fields as top-level keys. Which ones arrive is decided by three things, in order:
- What your credentials may see. A browser token never receives
private:fields. - What the surface returns by default. Configured per surface.
- What you asked for with
return_fields.
return_fields
Section titled “return_fields”An array of field names in the request body:
curl -X POST 'https://api.eu1.luigisbox.ai/discovery/v1/search?channel_id=lbn_4hj9tv&surface_id=lbs_search_main' \ -H 'Authorization: Bearer <token>' \ -H 'X-Lbx-Visitor-Id: 8f14e45f-…' \ -H 'Content-Type: application/json' \ -d '{ "type": "product", "query": "shirt", "return_fields": ["@title", "price", "image_url", "url"] }'| Form | Meaning |
|---|---|
price | One field, by exact name |
params.* | Every field under a nested object |
* | Everything visible to your credentials |
* must stand alone. Combining it with other names is a 422 — * already includes them.
Limits: up to 100 fields per request, and 512 characters per name.
@id and @type are always present on a hit, whether or not you list them.
Ask for what you render
Section titled “Ask for what you render”A product card usually needs a handful of fields. Requesting them explicitly makes the response smaller:
const CARD_FIELDS = ['@title', 'price', 'list_price', 'image_url', 'url', 'availability'];
const body = { type: 'product', query, return_fields: CARD_FIELDS };Different placements want different projections. An autocomplete row needs a title, a thumbnail and a price; a results-page card needs more; a product page needs everything. Keep one list per placement rather than one list for the whole integration.
Field visibility
Section titled “Field visibility”Field visibility follows from the field name and from the credential you authenticated with; it cannot be overridden per request.
| Field name | Example | Browser token | Server token |
|---|---|---|---|
| Plain | color, price | Visible | Visible |
@ registered | @id, @title, @category | Visible | Visible |
lbx: derived | lbx:group_primary | Visible | Visible |
private: | private:margin | Never | Visible |
Two consequences:
- Anything a shopper must not read belongs in
private:. Discovery requests and responses are visible in browser developer tools. A cost, a margin, a supplier code or an internal note in a plain field is public data. - A server-side integration can see
private:fields, so it decides what reaches the page. If your backend renders search results, setreturn_fieldsto the fields you intend to display. Passing the whole hit through to your template exposes every field it carries.
Asking for a private: field with a browser token is not an error; the field is absent
from the response.
See How to structure your data for the writing side of this.
Nested fields
Section titled “Nested fields”An attribute holding an object is addressed by dot-path:
{ "@id": "product/sku-1001", "params": { "material": "cotton", "fit": "regular" }}Address it either one field at a time or as a whole group:
{ "return_fields": ["params.material"] } // just that one{ "return_fields": ["params.*"] } // the whole groupThe same dot-path works in filters and in facet fields.
Finding out what exists
Section titled “Finding out what exists”Catalog metadata lists every attribute an object type carries, with its value shape:
curl -G 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/types/product/attributes' \ --data-urlencode 'query=price' \ -H 'Authorization: Bearer <token>'See Catalog metadata.
See also
Section titled “See also”- Catalog object model — namespaces and what they mean
- Catalog metadata — which fields a catalog holds
- Filters — the same field names, in filters
- Discovery overview
Was this page helpful?
Thanks.