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.
Three read-only endpoints report what a catalog holds: its object types, the attributes each type carries with their value types, and the distinct values of an attribute. Check them before debugging an empty filter.
All three need a token for the https://api.<region>.luigisbox.ai/catalog audience, and a
grant to read the catalog’s metadata.
Object types
Section titled “Object types”curl -G 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/types' \ -H 'Authorization: Bearer <token>'Every object type the catalog has actually received content for:
{ "items": [ { "name": "brand" }, { "name": "category" }, { "name": "product" } ], "page": 1, "size": 20, "total": 3}name is the value in @type, and the value the type parameter takes on
discovery requests.
If a type you expected is absent, no content of it has been indexed. Where a feed supplies that type, check its run history.
total: 0 means nothing of any type is indexed. An unknown catalog_id answers the same
way: this endpoint reads a catalog’s content and does not resolve its identity. To tell the
two apart, read the catalogs you can see from
get_entitlements.
Attributes and their types
Section titled “Attributes and their types”curl -G 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/types/product/attributes' \ --data-urlencode 'query=price' \ --data-urlencode 'size=50' \ -H 'Authorization: Bearer <token>'Each attribute comes back with the shape of its values:
{ "items": [ { "name": "list_price", "type": { "shape": "number" } }, { "name": "price", "type": { "shape": "number" } }, { "name": "price_history", "type": { "shape": "array", "element": "number" } } ], "page": 1, "size": 50, "total": 3}| Field | Meaning |
|---|---|
name | The attribute name, exactly as you use it in filters, sorts and return_fields. Nested attributes appear as dot-paths, e.g. params.color. |
type.shape | string, number, boolean, object or array |
type.element | For an array, the shape of its items, when known |
query matches the attribute name, case-insensitively, on a substring.
Why types matter more than they look
Section titled “Why types matter more than they look”A field’s type decides what the field can do:
| If a field is | You get | You do not get |
|---|---|---|
number | Range filters (price < 50), a range facet, numeric sorting | |
string | Equality and membership filters, a terms facet | Range filters, numeric sorting |
A price reported as string is why price < 50 returns nothing, why the price facet
renders as a list of values, and why sorting by price puts 9.90 before 10.00.
The type is fixed by the first value the field ever receives in the catalog, and later
conflicting values are rejected rather than coerced. One early feed run sending
"price": "29.90" types the field as text permanently.
The fix is at the mapping, not the query — add | to_f, then
reset the feed’s fingerprints so
every record is resent. Ask Luigi’s Box support if the field needs to be re-typed
outright.
Distinct values
Section titled “Distinct values”curl -G 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/types/product/attributes/color/values' \ --data-urlencode 'query=bl' \ -H 'Authorization: Bearer <token>'The values present in the catalog, most common first:
{ "items": [ { "value": "blue" }, { "value": "black" } ], "page": 1, "size": 20, "total": 2}Values come back typed to the attribute’s own shape — numbers as numbers, booleans as booleans, not as strings.
- At most 1,000 distinct values are considered, ranked by how many objects carry them.
totalis capped there, so a high-cardinality field reports the 1,000 most common rather than everything. queryworks on text attributes only. It is a case-insensitive substring match.- A non-scalar attribute has no pickable values and returns an empty page. An unknown
attribute returns
404.
A filter or rule builder can read this endpoint to populate a value picker.
Using it to debug
Section titled “Using it to debug”| Symptom | Check |
|---|---|
| A filter returns nothing | Is the field there? Is its shape what you assumed? Is the value spelled that way? |
| A range filter returns nothing | shape is string |
| A facet renders as a list instead of a slider | Same — shape is string |
| Sorting looks alphabetical | Same |
| A field is missing from hits | Is it in the attribute list at all? If not, it never arrived. If it is, check return_fields and whether it is private: |
A filter.unknown_field error | The field is not in this catalog under that name |
A script that lists every attribute and its shape:
BASE = "https://api.eu1.luigisbox.ai/catalog/v1"
types = client.get(f"{BASE}/{catalog_id}/types").json()["items"]for object_type in types: attributes = client.get( f"{BASE}/{catalog_id}/types/{object_type['name']}/attributes", params={"size": 200}, ).json()["items"] print(object_type["name"], len(attributes), "attributes") for attribute in attributes: print(" ", attribute["name"], attribute["type"]["shape"])Run it after the first successful feed run to find mistyped fields before they reach a filter.
See also
Section titled “See also”- Filters — where these names and types are used
- Facets — why a facet’s type follows the field’s
- Field mapping — fixing a type at the source
- Feed troubleshooting
Was this page helpful?
Thanks.