Data model
Adding a property to a product on revenexx is not a migration. It is a row in attributes and a row in family_attributes. Six entities describe the whole shape of a tenant's catalog, and every one of them is ordinary tenant data a merchant can change.
| Entity | Base path | Answers |
|---|---|---|
attribute_groups | /v1/products/attribute_groups | Which section of a form a field appears in |
attributes | /v1/products/attributes | What properties exist at all |
attribute_options | /v1/products/attribute_options | The permitted values of a select |
families | /v1/products/families | Which set of attributes a product has |
family_attributes | /v1/products/family_attributes | The link, plus per-family required and order |
family_variants | /v1/products/family_variants | How a family splits into variants |
measurement_families | /v1/products/measurement_families | The units a measure attribute offers |
Attributes
curl "https://api.revenexx.com/v1/products/attributes?limit=100" \
-H "X-Revenexx-Tenant: <TENANT_SLUG>" \
-H "X-Revenexx-Api-Key: rvxk_..."
| Field | Meaning |
|---|---|
code | Stable identifier, and the key the value is stored under inside attribute_values. Also how a category rule addresses it, as attribute:<code>. |
type | Which editor the value asks for — text, select, metric, price, asset_collection, reference_entity, … |
localizable | One value per locale, under locale_specific.<locale>.<code>. |
scopable | One value per channel, under channel_specific.<channel>.<code>. Both flags together means channel_locale_specific. |
entity_type | Which kind of record carries it: product, reference_entity, asset, category. |
entity_ref | Narrows entity_type to one reference entity or asset family, by code. Null for a plain product attribute. |
group_id | The attribute_groups row it is filed under — the form section. Null renders after every named section. |
position | Order inside the group. A family may override it. |
labels | The field label per language tag. Falls back to English, then to the code. |
validation | Limits, as a flat object. The seven keys a client can act on: min, max, min_length, max_length, pattern, min_items, max_items. |
config | Type-specific settings. The app reads units (a measure's unit list) and reference_entity (which entity a reference attribute draws options from). |
is_filterable | Offer this attribute as a filter in a product list. GET /v1/products/grid reports exactly these in its filters array. |
usable_in_grid | Show it as a column in the grid. GET /v1/products/grid returns a column definition and a per-row value for exactly these. |
is_unique | Declares the value identifies the product — an EAN, a manufacturer part number. Metadata only: no database index enforces it, because the value lives inside jsonb. |
type and entity_type deliberately carry no fixed value list. A tenant or integrator can add a type; GET /v1/products/attribute-schema maps an unknown one onto a text field rather than refusing to answer.
Attribute groups
A group is a section of the product form, not just a label. code is what a resolved field carries as its group, labels is the heading a person sees, and position orders the sections ascending.
Attribute options
The permitted values of a select or multi-select.
{
"attribute_id": "…",
"code": "matte_black",
"labels": { "en": "Matte black", "de": "Mattschwarz" },
"position": 20,
"swatch": { "hex": "#1b1b1b" }
}
code is what gets stored in the product's attribute_values — never the label. Two tenants may label the same code differently. Deleting the attribute deletes its options with it. Options that tie on position keep whatever order the database returned, so give every option a position if the order matters.
Families
A family answers which attributes does a product of this kind have.
| Field | Meaning |
|---|---|
code | Stable identifier, and what GET /v1/products/attribute-schema?family_code= resolves. |
labels | What the family is called, per language tag. |
label_attribute | Which attribute code carries the display name of a product in this family. Null falls back to the default_label_attribute setting, then to the conventional name. |
image_attribute | Which attribute code carries the main image — what a grid thumbnail and a picker read. |
A product's name being per-family is the reason POST /v1/products/labels exists: no plain read can answer what a product is called.
Family attributes
One row per (family, attribute). This is the link that makes an attribute part of a family's form.
| Field | Meaning |
|---|---|
is_required | The attribute has to carry a value for a product of this family to count as complete. POST /v1/products/{id}/completeness measures exactly these and nothing else. |
position | The family's own ordering, overriding the attribute's default. |
required_channels | Narrows is_required to named channels. |
required_channels: null or [] means required everywhere, not nowhere. That is how every required link in the wild is stored. Reading an empty list as "nowhere" reports a fully configured family as demanding nothing.Deleting either side deletes the link.
Family variants
How a family splits — not which product splits. A family may carry several structures, and a product names the one it follows through family_variant_id.
axes names the attribute codes the split happens on, and two shapes are in the wild; both are read:
{ "code": "shoes_by_colour_size", "axes": ["colour", "size"] }
{
"code": "shoes_by_colour_size",
"axes": [
{ "level": 1, "axes": ["colour"] },
{ "level": 2, "axes": ["size"] }
]
}
An attribute named as an axis is read-only on the model and set on each variant.
Measurement families
The unit set a measure attribute offers.
{
"code": "weight",
"standard_unit": "KILOGRAM",
"units": [
{ "code": "KILOGRAM", "symbol": "kg", "convert_factor": 1 },
{ "code": "GRAM", "symbol": "g", "convert_factor": 0.001 }
],
"labels": { "en": "Weight" }
}
convert_factor multiplies a value into standard_unit, so a gram is 0.001 kilograms. Every value is converted to the standard unit before it is compared or sorted. symbol is what a form prints next to the number.
Read the shape in one call
Six entities is five reads and a join. Do not do that — GET /v1/products/attribute-schema answers one ready-to-render field list, ordered by group then by the family's own ordering, with the storage path and fallback order per field. See Completeness.
Where to go next
- Products — the row these definitions shape.
- Completeness —
attribute-schemaand the completeness measure. - References — where a
reference_entityattribute draws its values from. - Assets — asset families and their attributes.