> ## Documentation Index
> Fetch the complete documentation index at: https://docs.frontic.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Xentral

<div style={{ display: "flex", gap: "1.75rem", alignItems: "flex-start", marginTop: "0.5rem", marginBottom: "1.75rem" }}>
  <img src="https://mintcdn.com/frontic/xG0tT-c_zeEiwfrd/images/connectors/xentral.svg?fit=max&auto=format&n=xG0tT-c_zeEiwfrd&q=85&s=fbbe145955b261bfa07a532ecbcfa4c6" alt="Xentral" style={{ height: "56px", width: "auto", flexShrink: 0, marginTop: "0.25rem" }} width="50" height="49" data-path="images/connectors/xentral.svg" />

  <div>
    The Xentral connector syncs your ERP's product catalog and category tree (also known as item tree or Article tree or Artikelbaum) into Frontic. Products are normalized with texts, prices, media, stock levels, and properties pre-loaded per record — so your Data Sync receives a complete, structured payload.
  </div>
</div>

<div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: "0.75rem", marginBottom: "2rem" }}>
  <div style={{ padding: "0.75rem 1rem", border: "1px solid var(--card-border, rgba(0,0,0,0.08))", borderRadius: "0.625rem" }}>
    <div style={{ display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.75rem", textTransform: "uppercase", letterSpacing: "0.04em", opacity: 0.6, marginBottom: "0.25rem" }}>
      <Icon icon="key" iconType="solid" /> Auth
    </div>

    <div style={{ fontSize: "0.875rem", fontWeight: 500 }}>Personal Access Token</div>
  </div>

  <div style={{ padding: "0.75rem 1rem", border: "1px solid var(--card-border, rgba(0,0,0,0.08))", borderRadius: "0.625rem" }}>
    <div style={{ display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.75rem", textTransform: "uppercase", letterSpacing: "0.04em", opacity: 0.6, marginBottom: "0.25rem" }}>
      <Icon icon="arrows-rotate" iconType="solid" /> Update method
    </div>

    <div style={{ fontSize: "0.875rem", fontWeight: 500 }}>Polling</div>
  </div>

  <div style={{ padding: "0.75rem 1rem", border: "1px solid var(--card-border, rgba(0,0,0,0.08))", borderRadius: "0.625rem" }}>
    <div style={{ display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.75rem", textTransform: "uppercase", letterSpacing: "0.04em", opacity: 0.6, marginBottom: "0.25rem" }}>
      <Icon icon="boxes-stacked" iconType="solid" /> Resources
    </div>

    <div style={{ fontSize: "0.875rem", fontWeight: 500 }}>Products, Categories</div>
  </div>
</div>

## What you get

<CardGroup cols={2}>
  <Card title="Products" icon="boxes-stacked">
    Matrix products as parent records, variants as children — with texts, prices, media, stock, and properties pre-loaded per record.
  </Card>

  <Card title="Categories" icon="folder-tree">
    Power category pages, attach category context to product records, and drive navigation.
  </Card>
</CardGroup>

## Connection settings

<ParamField path="Xentral ID" type="string" required>
  Your Xentral instance subdomain — the part before `.xentral.biz`. For `my-company.xentral.biz`, enter `my-company`.
</ParamField>

<ParamField path="Access Token" type="string" required>
  A Xentral API personal access token with read-only Product permissions. Generate one in Xentral under **Account Settings → Developer Settings → Personal Access Tokens**. Stored encrypted-at-rest.
</ParamField>

The settings panel shows a **Connection Status** indicator. When the connection is broken it surfaces the reason returned by the Xentral API — so you can tell whether the token is invalid, expired, or the Xentral instance is unreachable. Update credentials here and re-test after the issue is fixed.

## Channels

A Xentral channel in Frontic has a selection of currencies available. Translations are populated from the translations Xentral exposes per locale.

<ParamField path="Channel Name" type="string" required>
  A label for the channel in Frontic.
</ParamField>

<ParamField path="Available Translations" type="multiselect" required>
  Locale keys this channel covers. Populated from Xentral's locales.
</ParamField>

<ParamField path="Fallback Translation" type="select" required>
  The translation used when a value is missing in another locale.
</ParamField>

<ParamField path="Currencies" type="multiselect" required>
  Currencies the connector pulls in. Product prices are pre-filtered to these currencies before they reach the Data Sync — only the sales prices valid today for the chosen currencies are included.
</ParamField>

## Data Feeds

The Xentral connector exposes two feed types:

| Feed           | What it pulls                                                                                                 |
| -------------- | ------------------------------------------------------------------------------------------------------------- |
| **Products**   | All products and variants with texts, prices, media, stock levels, properties, and cross-sellings pre-loaded. |
| **Categories** | The full product category tree, parent links preserved.                                                       |

The standard **Settings → Updates → Schema** setup wizard applies — see [Data Feeds in the overview](/connectors/overview#data-feeds). For Xentral specifically:

* **Updates step** — Polling is supported. On the first run (or after a manual refresh), all records are fetched regardless of timestamp.
* **Manual refresh** — every Xentral feed exposes a **Refresh** action that re-runs the feed against the source in full. Use it when something changed on the Xentral side that didn't reach Frontic during a scheduled poll, or to recover after a polling gap.

If you're using prices limited by a date range, make sure to update the product feed at least daily to ensure correct price availability.

### Product Feed

For your products, you can optionally choose to prefer prices for a specific Xentral group, falling back to the default price. Otherwise, a default price will be used.

<ParamField path="Price Group" type="select" required>
  The Xentral group to be used for price selection, if available.
</ParamField>

## What the data looks like

### Variants

Xentral distinguishes between **matrix products** (configurable products with variants) and **simple products** (no variant axis). The connector handles both:

* **Matrix products** — the matrix product record becomes the parent, each variant becomes a separate record with `parentId` pointing back to the matrix product.
* **Simple products** — emitted as a self-parented record using the same source ID on both sides. See [Product Models](/commerce-concepts/product-models) for how this shape composes at the API layer.

### Currency-resolved prices

For products, the connector pre-filters sales prices to the currencies declared on the channel. Only prices valid on the current date that apply to all customers (no customer-specific or customer-group-specific pricing) are included. Map them into the [Price composite](/reference/storage-field-types#composites) in the Value Composer — no per-region price-picking logic needed.

### Translations

Product texts are fetched per locale. The connector resolves the localized text values (name, description, and other translatable fields from Xentral's API) for every locale on the channel.

<Warning>
  The Xentral API does not expose translations for categories and some of the product data (like properties). We're providing everything we can get via the Xentral API.
</Warning>

### Attributes split into options and properties

The connector's attribute extractor separates variant-defining options from descriptive properties and stamps them onto the feed record under the reserved `$`-prefix namespace:

* **`$options`** — the `selectedOptions` from variant records, normalized into a flat list per record. Drives variant selectors (size, colour, etc.).
* **`$properties`** — product property values with their property name, value, and unit. Descriptive attributes that don't drive variant selection.

Map either list into your storage with the [Option composite](/reference/storage-field-types#composites) in the Value Composer, rather than deriving them from Xentral's raw structures.

### Additional data pre-loaded

Each product record also carries:

* **`$medias`** — product media items (images, documents).
* **`$stocks`** — stock levels per warehouse location.
* **`$crossSellings`** — cross-selling product references.

### Category relations

The connector adds a flat list of category IDs onto each product record under `$rel.categoryIds`, derived from the product's `categories` association. Category-link blocks and syncs that need only the IDs can map this directly in the Value Composer.

### Auto-delete reconciliation

When a feed runs in full (manual refresh), the connector diffs Xentral's current record set against what Frontic holds and emits **deletes** for products or categories that have disappeared on the Xentral side. Your storage doesn't accumulate orphan records when items are removed in Xentral.

## Good to know

* **Read-only.** The Xentral connector pulls from Xentral; it doesn't push back. Catalog edits happen in Xentral.
* **Incremental polling.** Scheduled polls fetch only products updated since the last successful poll — keeping regular syncs fast on large catalogs. Categories are always fetched in full on each poll.
* **Reserved `$`-prefix keys.** The connector emits `$options`, `$properties`, `$medias`, `$stocks`, and `$crossSellings` on every product record. Don't use `$`-prefixed keys for your own custom attributes — Frontic reserves that namespace for connector-side normalization.

## Related

<CardGroup cols={2}>
  <Card title="Product Models" icon="boxes-stacked" href="/commerce-concepts/product-models">
    How Xentral's matrix products and variants compose at the API layer.
  </Card>

  <Card title="Akeneo" icon="database" href="/connectors/akeneo">
    Same `$options` / `$properties` attribute split.
  </Card>
</CardGroup>
