Skip to content

    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.

    Feed management API

    View source

    Feeds are normally configured with your Luigi’s Box implementation contact. When you want to manage them yourself — a new market, a URL rotation, a scripted resynchronization — the catalog configuration API does the same job.

    Everything here needs a token for the https://api.<region>.luigisbox.ai/catalog audience, and a grant covering the operation — feeds, mappings, syncs and metadata are granted separately, and reading is separate from writing. See Server-to-server tokens.

    ResourceWhat it is
    FeedOne URL, one object type, its format and its parsing options
    MappingHow source fields become catalog fields — see Field mapping. Shared with the Content API.
    SynchronizationOne run: download, parse, send. Recorded whether it succeeds or not.

    One catalog holds several feeds — products, categories, brands, articles — each pointing at a mapping.

    Terminal window
    curl -X POST 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/sources/feeds' \
    -H 'Authorization: Bearer <token>' \
    -H 'Content-Type: application/json' \
    -d '{
    "url": "https://example.com/feeds/products.xml.gz",
    "catalog_type": "product",
    "format": "xml",
    "item_tag": "product",
    "identity_field": "product_id",
    "mapping_id": 17,
    "active": true
    }'

    The response is the created feed, including its feed_id and version.

    FieldRequiredPurpose
    urlYesWhere to fetch the feed. HTTPS, no interactive login.
    catalog_typeYesThe object type in this file: product, category, brand, article
    formatNoxml, json, json_lines, csv. Detected when omitted.
    item_tagNoXML element that wraps one record, e.g. product
    json_pathNoPath to the record array in a JSON feed, e.g. products
    csv_delimiter / csv_has_headerNoCSV parsing options
    identity_fieldNoSource field holding the record’s identity
    mapping_idNoThe mapping to apply
    group_id_field / group_primary_fieldNoSource fields for variant grouping
    delete_thresholdNoFraction of the catalog a run may remove, 0.01.0
    activeNoDefaults to true. false registers without scheduling.
    positionNoOrdering among the catalog’s feeds
    transport_optionsNoExtra options for fetching, such as authentication headers

    Format, item tag and JSON path are detected from the file when you leave them out. Set them explicitly for a production feed: detection is a convenience, not a contract.

    Terminal window
    # One feed
    curl 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/sources/feeds/41' \
    -H 'Authorization: Bearer <token>'
    # All of a catalog's feeds
    curl -G 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/sources/feeds' \
    --data-urlencode 'page=1' --data-urlencode 'size=20' \
    -H 'Authorization: Bearer <token>'

    Updates are PATCH, and they carry the version you last read as expected_version:

    Terminal window
    curl -X PATCH 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/sources/feeds/41' \
    -H 'Authorization: Bearer <token>' \
    -H 'Content-Type: application/json' \
    -d '{
    "url": "https://example.com/feeds/products-v2.xml.gz",
    "expected_version": 7
    }'

    If the feed changed since you read it, the version no longer matches and the update is rejected instead of overwriting the other change. Re-read the feed and reapply your change.

    Omitted fields are left unchanged; a field sent as null is cleared. See Partial updates.

    DELETE deactivates a feed. It stops being fetched; the catalog content it produced stays where it is. To remove the content too, delete the objects — see Content API.

    Feeds are checked automatically. Trigger one by hand when you have just changed a mapping, or want to pull a fresh export immediately:

    Terminal window
    curl -X POST 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/sync' \
    -H 'Authorization: Bearer <token>'

    The response identifies the run:

    { "run_id": "9f2c4b71-3e8a-4d05-b6c1-7a3d9e2f8041" }

    This covers the whole catalog — every active feed on it.

    Between runs, Luigi’s Box remembers which records it has already seen, so an unchanged record is not re-sent. A mapping change therefore does not reshape records that did not change.

    Reset the memory to force everything through again:

    Terminal window
    curl -X POST 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/sources/feeds/41/fingerprints/reset' \
    -H 'Authorization: Bearer <token>'

    Then synchronize. The next run re-sends every record in the feed.

    Do this after changing a mapping, after adding a field you want backfilled, or when a catalog and a feed have drifted apart. Do not do it routinely — it is a full reindex of that feed’s content.

    The fingerprints=false query parameter on /sync has the same effect for one run without clearing the stored state.

    Terminal window
    curl 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/sources/feeds/41/status' \
    -H 'Authorization: Bearer <token>'

    The latest run, plus what was detected and remembered about the feed:

    {
    "feed_id": 41,
    "locked": false,
    "latest_run": {
    "id": 5182,
    "status": "succeeded",
    "trigger": "schedule",
    "started_at": "2026-03-14T02:00:04Z",
    "finished_at": "2026-03-14T02:04:31Z",
    "items_sent": 207993,
    "items_skipped": 0,
    "items_no_identity": 0,
    "error_message": null
    },
    "state": {
    "detected_format": "xml",
    "detected_item_tag": "product",
    "total_items": 207993,
    "last_run_at": "2026-03-14T02:00:04Z"
    }
    }

    locked: true means a run is in progress. state reports what was detected and remembered about the feed; use it to confirm that format detection agrees with your configuration.

    Terminal window
    curl -G 'https://api.eu1.luigisbox.ai/catalog/v1/lbc_8w3k2p/sources/feeds/41/syncs' \
    --data-urlencode 'size=20' \
    -H 'Authorization: Bearer <token>'
    statusMeaning
    runningIn progress
    succeededCompleted
    failedStopped — read error_message and status_reason
    skippedNothing to do; the feed had not changed since the last run

    A long stretch of skipped runs means your ETag or Last-Modified headers work and the unchanged file is not downloaded. A long stretch of skipped when the file has changed means those headers are wrong — see Serving your feed.

    The counters on each run:

    CounterWatch for
    items_sentA sudden drop — an incomplete export
    items_skippedAnything non-zero — records rejected during parsing
    items_no_identityAnything non-zero — records with no value in identity_field

    Mappings live under the same catalog:

    GET /catalog/v1/{catalog_id}/mappings
    POST /catalog/v1/{catalog_id}/mappings
    POST /catalog/v1/{catalog_id}/mappings/validate
    GET /catalog/v1/{catalog_id}/mappings/{mapping_id}
    PATCH /catalog/v1/{catalog_id}/mappings/{mapping_id}
    DELETE /catalog/v1/{catalog_id}/mappings/{mapping_id}

    Always dry-run a change through /validate before saving it. See Field mapping.