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.
Source data carries its own names and shapes: name instead of @title, price_with_vat
as a string instead of price as a number, availability as "in stock" instead of 1.
A mapping is a small declarative document that says which source field becomes which catalog field, and what to do to the value on the way. Nothing about your export or your payloads has to change.
Mapping sits in front of both ways in: content arriving from a feed and content pushed over the Content API are mapped the same way, by object type.
Mappings are usually written with your Luigi’s Box implementation contact during onboarding. This page is for reading the one you have, and for changing it yourself over the feed management API.
A mapping is a JSON object of source → target:
{ "name": "@title", "product_id": "@id", "price_with_vat": "price | to_f", "stock_status": "availability | translate('in stock', 1, 'out of stock', 0) | to_i"}- The key selects a field on the incoming record. Dot-paths reach into nested
structures;
*matches a group of names. - The value is a target spec: an optional target field name, then any number of
|-chained transforms.
Fields you do not mention pass through unchanged, so a mapping only needs to describe what differs.
Renaming
Section titled “Renaming”The target spec is the new name:
{ "name": "@title", "product_id": "@id", "link": "url", "img": "image_url"}Transforming
Section titled “Transforming”Chain transforms after a |. They run left to right.
{ "price_with_vat": "price | to_f", "description": "description | decode_html_entities", "link": "url | strip_all_parameters"}To transform a field in place, without renaming it, omit the target name and start with the pipe:
{ "price": "| to_f", "title": "| decode_html_entities"}Applied to a list, a transform runs on each element.
Available transforms
Section titled “Available transforms”Type conversion. A field’s first value fixes its type for the whole catalog, and a price stored as text cannot be range-filtered.
| Transform | Effect |
|---|---|
to_f | To a number. 0.0 if the value is missing or unparseable. |
to_i | To a whole number, truncating decimals. 0 on failure. |
to_s | To text. Empty string for a missing value. |
to_bool | To true/false. Accepts 1/0, y/n, yes/no, t/f, true/false. |
to_date | To an ISO date, YYYY-MM-DD. |
to_time | To an ISO 8601 timestamp. |
json_parse | Parse a JSON string into real structure. |
Text.
| Transform | Effect |
|---|---|
replace('find', 'with') | Replace every occurrence |
prefix('text') / append('text') | Add text at the start or end |
capitalize | First character upper, rest lower |
split_by_separator('/') | Split into a list, trimming each part |
decode_html_entities | Decode entities and strip HTML tags |
strip_all_parameters | Drop the query string from a URL |
translate('a', 1, 'b', 2) | Map values through a lookup table; unmatched values pass through |
Lists.
| Transform | Effect |
|---|---|
to_array | Wrap a single value in a list |
first / last | Keep only the first or last element |
drop_last | Drop the last element |
flatten | Flatten one level of nesting |
uniq | Remove duplicates, keeping order |
unpack_array | Unwrap a one-element list to the value itself |
values | Take a nested object’s values as a list |
Numbers.
| Transform | Effect |
|---|---|
min / max | The smallest or largest of the value, optionally against a second value |
prefix is how you build typed identities from a bare key:
{ "product_id": "@id | prefix('product/')" }A source product_id of sku-1001 becomes @id: "product/sku-1001" — the form
identity requires.
Referencing another field
Section titled “Referencing another field”A transform argument beginning with @ reads another field from the same record:
{ "sale_price": "price | min(@list_price)" }If the referenced field is absent, the transform is skipped rather than failing the record.
Writing to several fields
Section titled “Writing to several fields”Give a list of target specs to write one source field to several places — including back to its own name, which is how you keep a field while also deriving from it:
{ "name": ["@title", "name"], "category_path": ["@category | split_by_separator(' > ') | last", "category_path"]}Nested sources
Section titled “Nested sources”Dot-paths reach into structure:
{ "attributes.color": "color", "shipping.price": "shipping_price | to_f"}A . as the target name spreads an object’s keys into the record itself, which flattens a
nested block:
{ "params": "." }Applied to a record:
// before{ "params": { "material": "cotton", "fit": "regular" } }
// after{ "material": "cotton", "fit": "regular" }Wildcards
Section titled “Wildcards”* matches a group of source names, and \1 in the target inserts what it matched:
{ "custom_*": "\\1" }custom_color becomes color, custom_fit becomes fit. Useful for feeds that prefix
every extra attribute.
Defaults
Section titled “Defaults”An @defaults block fills in fields the record does not have. It runs before the rest of
the mapping, and it never overwrites a value that is already present:
{ "@defaults": { "availability": 1, "currency": "EUR" }, "price_with_vat": "price | to_f"}Values here can reference other fields with @, and a reference to an absent field is
skipped.
Try it before you save
Section titled “Try it before you save”POST /catalog/v1/{catalog_id}/mappings/validate applies a mapping to a sample record and
returns the result. Nothing is stored.
curl -X POST 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/mappings/validate' \ -H 'Authorization: Bearer <token>' \ -H 'Content-Type: application/json' \ -d '{ "mapping": { "name": "@title", "product_id": "@id | prefix(\"product/\")", "price_with_vat": "price | to_f", "stock_status": "availability | translate(\"in stock\", 1, \"out of stock\", 0) | to_i" }, "sample": { "product_id": "sku-1001", "name": "Blue Cotton T-Shirt", "price_with_vat": "29.90", "stock_status": "in stock" } }'The response is the mapped record:
{ "result": { "@id": "product/sku-1001", "@title": "Blue Cotton T-Shirt", "price": 29.9, "availability": 1 }}Use one record copied verbatim from your real feed as the sample. A hand-written example can differ from the export in exactly the detail the mapping has to handle.
Managing mappings
Section titled “Managing mappings”| Operation | Endpoint |
|---|---|
| List | GET /catalog/v1/{catalog_id}/mappings |
| Create | POST /catalog/v1/{catalog_id}/mappings |
| Read | GET /catalog/v1/{catalog_id}/mappings/{mapping_id} |
| Update | PATCH /catalog/v1/{catalog_id}/mappings/{mapping_id} |
| Delete | DELETE /catalog/v1/{catalog_id}/mappings/{mapping_id} |
A mapping belongs to a catalog and an object type (catalog_type), and a feed points at
one by mapping_id. See Feed management API.
Changing a mapping affects records processed after the change. To re-apply it to your whole catalog, reset the feed’s fingerprints and resynchronize — see Forcing a full resend.
See also
Section titled “See also”- Catalog object model — what you are mapping to
- Feeds overview — source fields and catalog fields
- Feed management API — attaching a mapping to a feed
- Catalog metadata — checking the types you produced
- Feed troubleshooting
Was this page helpful?
Thanks.