Origo Help

Product feeds

Give another system a current, filtered view of Product data in JSON or CSV.

Last reviewed:

What Product feeds are

A Product feed is a read-only list of current Product records. Use it when a shop, search service, integration, spreadsheet, or agent must regularly read catalogue data without creating an Export Job. A feed does not save a file or change Products. Each request creates a fresh response from the filters in its URL or tool input.

Use a feed for repeat reads from a stable address. Use an Export Job when a person needs a stored result and job history. Use activation when Origo must publish through a configured destination connection.

Open and authenticate a feed

  1. Sign in to your Origo tenant.
  2. In the left navigation, find Tools.
  3. Select Feeds.
  4. Choose common filters, then copy or open the generated Product feed URL.
  5. Add other parameters from this guide when the URL builder does not show them.

Admins, editors, and viewers can read Product feeds. A signed-in browser can use its current session. An external system must send an Origo API key in the request header: Authorization: Bearer {api-key}. Do not put the API key in the URL.

An admin or editor can create a personal API key under Access Management → API Keys. A personal key inherits its owner's current role. Only an admin can create an organisation key. An admin can give that key a fixed Viewer role for an external feed consumer. The key must remain active.

Two routes, one feed. Use GET /feeds/:channel when the channel is part of the address. Use GET /api/feeds/products when filters are query parameters. Both routes need authentication.

Choose JSON, CSV, selected rows, or image URLs

Set format=json for structured data. Set format=csv for a table that a spreadsheet or import tool can read. The /api/feeds/products route defaults to CSV. The /feeds/:channel route defaults to JSON. State the format in saved URLs so the result is clear.

Omit projection, fields, attributes, and attributeCodes for rich rows. Omitting fields and attributes preserves the existing rich feed shape. Rich rows contain the Product fields, translated values, Product attributes, associations, and other feed data. Rich JSON includes images and files. Therefore, an exact rich Product read with format=json&productId={product-id} includes its selected images. Rich CSV does not include images or files. It stores complex metadata and associations as JSON text inside CSV cells.

Add projection=sparse when you only need an ID, Product number, and translated name. Sparse rows skip attributes, associations, images, files, and rich variant checks. projection=sparse rejects fields and attributes. Do not use projection=full. Omit the parameter for rich rows.

Use comma-separated fields and attributes for an exact compact row. There are six core fields: id, brands, name, productNumber, status, and type. Choose up to six fields and up to 50 Product attribute codes, in the order you want returned. attributes=slug selects the existing Product EAV attribute and returns it as attribute:slug; it does not add a Product slug field. Selected Product EAV attributes must be active, coded, Product-applicable, non-link/multiLink, and channel-compatible: global, or scoped to the selected Channel; without a Channel, global only. Selected rows contain no unrequested fields, served-locale companions, metadata, associations, images, or files.

Prefer repeated attributeCodes parameters for exact codes: attributeCodes=finish%2Ccolour&attributeCodes=slug selects finish,colour and slug, in that order. URL-encode each value once; literal commas, percent signs, plus signs, quotes, Unicode, and meaningful whitespace are preserved. Empty, whitespace-only, duplicate, unknown, or more than 50 codes are rejected. Legacy attributes=a,b still splits on commas and trims each token. Do not combine attributes and attributeCodes. Both selectors are rejected with sparse or images projection. MCP accepts attributeCodes as a native string array, for example ["finish,colour", "slug"].

When selected, brands is an ordered array of { id, name } objects from active direct Brand assignments. Each name uses the feed locale, then the configured base locale when needed, with no served-locale companion. CSV serializes that array as JSON text.

Use projection=images only for an exact Product image feed. projection=images requires format=json, a nonblank productId, and isActive=true because returned public media URLs must be servable. It rejects CSV, brandId, fields, and attributes. Its normal JSON envelope's data is an ordered list of original image URLs—never Product rows, documents, image records, or metadata. Page 1 returns every URL for the one Product; an absent Product or a later page returns data: [], total: 0, and hasMore: false.

Filter the Product rows

All supplied row filters apply together. A Product must match each supplied brandId, productId, Channel, status, isActive, and textFilter value. The locale value controls the returned language instead of selecting rows.

brandId and productId together are valid for normal full or sparse feeds and use AND filtering. Image projection is the exception: it requires the exact Product ID alone and rejects brandId.

  • brandId={brand-id} matches one Brand ID. Brand filtering uses active, direct Product-Brand assignments only. A Brand inherited from a parent Product does not match. Deleted Brands and deleted assignments do not match.
  • productId={product-id} matches one immutable Product ID exactly. It does not match a Product number or part of an ID.
  • channelId={channel-id} returns Products linked to that Channel. On the canonical route, put the Channel ID or code in /feeds/{channel} instead.
  • locale={locale} selects an enabled content locale, such as en-US or nl-NL. It does not exclude a Product when Origo must use locale fallback. Without it, Origo uses the Channel's first locale, or the catalogue base locale when no Channel is selected.
  • status={status} accepts draft, prepared, reviewed, notReady, or ready. An unsupported value does not apply a status filter.
  • isActive=true returns active Products. This is also the default. isActive=false returns inactive Products. Use an explicit empty value, isActive=, to include both active states.
  • textFilter={text} finds a partial match in the base Product name, Product number, or Product type. It does not search a translated name returned for the selected locale. The text filter is not an exact Product lookup.

Deleted Products never appear. Filters also apply before paging. For example, a Product with the requested Brand but a different status does not appear.

Read all pages

page is one-based. Omit it for page 1, or use a positive whole number. Each page contains at most 1,000 rows in stable base Product name and ID order. Translated names can appear out of alphabetic order in the returned locale.

JSON includes page and hasMore. While hasMore is true, request the next page. CSV puts the same values in the X-Feed-Page and X-Feed-Has-More response headers. Do not use the current row count as the continuation rule. A full page can still be the last page.

Keep all filters unchanged when you move from one page to the next. Change only the page value.

Copy a URL example

Replace each value in braces. Use the tenant origin where you sign in, without a trailing slash. Percent-encode each query value before you add it. For example, use red%20%26%20blue for red & blue. The Tools → Feeds builder does this automatically.

Active Products as sparse JSON

{tenant-origin}/api/feeds/products?format=json&projection=sparse

Recommended Brand selected feed

{tenant-origin}/api/feeds/products?format=json&brandId={brand-id}&fields=id,brands,name&attributeCodes=slug

One Product's image URLs

{tenant-origin}/api/feeds/products?format=json&projection=images&productId={product-id}&isActive=true

Ready Products that contain text

{tenant-origin}/api/feeds/products?format=csv&status=ready&textFilter={search-text}&page=1

Both active and inactive Products

{tenant-origin}/api/feeds/products?format=json&isActive=&page=1

Canonical Channel route

{tenant-origin}/feeds/{channel-id-or-code}?format=json&projection=sparse&locale=en-US&page=1

Recognise sparse output

Sparse JSON uses the normal feed envelope. total is the number of rows on this page, not the total across all pages. productNumber can be null.

{
  "data": [
    {
      "id": "{product-id}",
      "productNumber": "CHAIR-001",
      "name": "Lounge chair"
    }
  ],
  "total": 1,
  "locale": "en-US",
  "page": 1,
  "hasMore": false
}

A deprecated locale alias can add a warnings list. Use the canonicalLocale in that warning before the stated sunset date.

Sparse CSV always has exactly these three columns:

id,productNumber,name
{product-id},CHAIR-001,Lounge chair

Resolve errors and empty results

Feed validation and domain errors include a short code and a readable error message. Authentication responses differ. An unauthenticated feed request returns {"error":"Unauthorized"} without a code. A browser request for the canonical route can redirect to sign-in. A suspended browser session receives 403. The compatibility route returns JSON with ACCOUNT_BANNED. The canonical route returns plain text Forbidden. A personal API key whose owner is suspended is rejected with 401. An organisation key does not depend on its creator's current account status. It remains usable while the key itself is active. Correct the request or access before retrying.

  • 401: sign in, or send a valid Bearer API key.
  • VALIDATION_ERROR: use json or csv; use only projection=sparse or projection=images; do not send blank, duplicate, unknown, or over-limit field/attribute selectors; and follow the image projection requirements.
  • INVALID_PAGE: use page 1 or a larger positive whole number.
  • INVALID_LOCALE: use an enabled locale available to the Channel.
  • LOCALE_ALIAS_EXPIRED: replace the old locale with the returned canonical locale.
  • VARIANT_SETUP_INVALID: a rich feed found an invalid ready variant family. Correct that setup, or use sparse rows when rich data is not needed.
  • NOT_FOUND: the Channel in /feeds/{channel} does not exist or was deleted.

No matching products is not an error. JSON returns an empty data list with total: 0 and hasMore: false. CSV returns its header row and X-Feed-Has-More: false. An unknown Brand or Product ID gives an empty result. The compatibility route also gives an empty result for an unknown channelId; the canonical Channel route gives NOT_FOUND instead.

Use the MCP equivalent

An authenticated MCP client can call read_product_feed. Use the same named inputs: format, projection, brandId, productId, fields, attributes, channelId, locale, status, isActive, textFilter, and page. The tool defaults to JSON and active Products.

{
  "projection": "sparse",
  "brandId": "{brand-id}",
  "channelId": "{channel-id}",
  "locale": "en-US",
  "page": 1
}

For JSON, the tool returns the same feed envelope as HTTP. For CSV, its first content item is the CSV body. Its second content item contains page and hasMore. Request the next page while hasMore is true.

MCP uses the same fields, attributes, and projection=images rules, limits, validation, and output shapes.