Catalog
Products
The product row itself — sku, kind, parent_id, the scoped attribute document, the grid and the batch resolver.
Data model
Attributes, groups, options, families, family attributes, variants and measurement families. The catalog's shape is data, not schema.
Categories
The tree, membership, and rule-driven categories with preview and recompute.
References
Brands, manufacturers and any other domain a product points at by attribute value.
Assets
Asset families and assets, and the three ways an asset binds to bytes.
Associations
Association types and product associations, including quantified relations.
Completeness
Measure a product against what its family requires, and read the field list per family.
Import and export
Profiles, uploads, exports and the bulk-job poll — how catalog data moves in volume.
The catalog is the products app: 16 entities and 92 capability routes, all under https://api.revenexx.com/v1/products — plus the shared io app under /v1/io for bulk import and export.
The one thing to understand first
A product row carries only what every product has: sku, kind, family_id, enabled, tax_class. Everything the merchant modelled — names, descriptions, weights, colours, technical data — lives in a single attribute_values jsonb document, keyed by attribute code.
That means the catalog's shape is data, not schema. Adding a "load capacity in kg" property to a product family is a row in attributes and a row in family_attributes, not a migration. A client that hard-codes column names will not survive a merchant modelling their own catalog; a client that reads GET /v1/products/attribute-schema will.
Routes at a glance
| Area | Base path |
|---|---|
| Products | /v1/products |
| Grid and batch | /v1/products/grid, /v1/products/batch, /v1/products/labels |
| Attributes and families | /v1/products/attributes, /attribute_groups, /attribute_options, /families, /family_attributes, /family_variants, /measurement_families |
| Categories | /v1/products/categories, /v1/products/product_categories |
| References | /v1/products/reference_entities, /reference_entity_records |
| Manufacturers | /v1/products/manufacturers — see Manufacturers |
| Assets | /v1/products/asset_families, /v1/products/assets |
| Associations | /v1/products/association_types, /v1/products/product_associations |
| Completeness | POST /v1/products/{id}/completeness, GET /v1/products/attribute-schema |
| Vocabularies | GET /v1/products/vocabularies, /vocabularies/{name} |
| Bulk | /v1/io/profiles, /v1/io/uploads, /v1/io/imports, /v1/io/exports, /v1/io/bulk-jobs |
Every one of them is browsable and callable in the API Explorer.
Manufacturers
A manufacturer is the company a product is made by, kept once and pointed at by every product it makes (products.manufacturer_id). Besides what a brand page shows, it holds what the EU General Product Safety Regulation (GPSR) requires an offer to name. POST /v1/products/manufacturers creates one, and the other routes work on one manufacturer by the id that GET /v1/products/manufacturers returns; restoring one from the trash is covered below:
| Method | Path | What it does |
|---|---|---|
POST | /v1/products/manufacturers | Creates a manufacturer. code, name and country are required; country must be an ISO 3166-1 alpha-2 code in capitals, else 400 (invalid_country). An address that is not a valid platform address answers 400 (invalid_address). A code already taken answers 409. |
GET | /v1/products/manufacturers/{id} | Reads one manufacturer, the whole row as stored. |
PUT | /v1/products/manufacturers/{id} | Partial patch: changes only the named columns. A country that is null or malformed answers 400 (invalid_country), and so does an invalid address (invalid_address). A code already taken answers 409. |
DELETE | /v1/products/manufacturers/{id} | Moves it to the trash; called on one already there, deletes it for good. Deleting for good is refused with 409 while a switched-on product still made by the manufacturer holds it; any other product is unlinked. A storefront contact can move it to the trash but not delete it for good (403). See Trash and restore. |
GET | /v1/products/manufacturers/{id}/gpsr | Lists which GPSR data the manufacturer has and which it is missing: the legal name, a postal address with country and an e-mail address, and for a manufacturer outside the European Economic Area (EEA) the responsible person in the EEA with address and e-mail. Writes nothing. |
PUT | /v1/products/manufacturers/{id}/logo | Sets the logo to an existing asset of this catalog (asset_id; the asset needs a delivery path or external URL already, and the logo links to its code), or to a delivery path or https URL (path). asset_id wins when both are sent. |
DELETE | /v1/products/manufacturers/{id}/logo | Clears the logo. The asset or the stored file it pointed at is left alone. |
GET | /v1/products/manufacturers/{id}/products | Lists the products linked to the manufacturer, paged. A product that names the manufacturer only in the older free-text attribute is not listed until POST /v1/products/manufacturers/migrate links it. |
Trash and restore
Deleting a manufacturer sends it to the trash. A second delete of the same manufacturer deletes it for good, and so does emptying the trash. The platform also deletes trashed records that outlive the tenant's trash retention (90 days unless the tenant set another), except one that something still blocks.
The first delete fires manufacturer.trashed and a restore manufacturer.restored. manufacturer.deleted fires only once the record is deleted for good. See Deletes and the trash.
- Restore.
POST /v1/products/manufacturers/{id}/restorebrings the manufacturer back from the trash. Nothing else goes to the trash with a manufacturer, so nothing else comes back with it. Everything that pointed at the manufacturer acts again as it did, because nothing was changed when it went. Restoring needs the same right as deleting. The answer lists every record that came back inrestored. - Refused with
409.not_in_trashwhen the manufacturer is not in the trash.parent_in_trashwhen the record it belongs to is in the trash in another group;details.restorenames the call that brings that one back first. - Refused with
404when no manufacturer of this tenant has that id. A manufacturer of another tenant gets the same404, not a403. - Empty the trash.
POST /v1/products/manufacturers/trash/emptydeletes the trashed manufacturers for good, oldest first, up to 200 per call, each through the same checks as a secondDELETE. - A record a blocker holds is listed in
blockedwith its reason and stays in the trash; the rest of the call goes on. deletedlists what this call removed for good.more: truemeans the call stopped at its limit and the trash may hold more: call it again.- A storefront contact gets
403: emptying the trash is back-office work.
GET /v1/products/manufacturers also filters on active. active is true unless the entry was retired (false). A list returns both unless you filter, so use ?active=true for a picker. Records that already carry a retired entry keep it; a write cannot newly assign one (409 entry_inactive).
Reading and filtering the trash. GET /v1/products/manufacturers leaves trashed manufacturers out unless the call asks with trashed: only returns the trash alone, include returns the live and the trashed manufacturers together. Each manufacturer carries the fields below, and each one is also an exact-match filter on the list call.
| Field | What it holds |
|---|---|
deleted_at | When the manufacturer went to the trash; null while it is live. |
deleted_by | Who moved it there: an e-mail, or system for a scheduled job. A name for the trash view, not an identity to check. |
deleted_by_id | The platform subject of that person, the stable id a privacy request pseudonymises. Null for a scheduled job. |
purge_at | When the daily purge deletes it for good: deleted_at plus the tenant's trash retention (90 days unless the tenant set another). |
trash_batch | The trash action it went with. A restore brings back exactly the records that carry the same value. |
purge_blocked_reason | Why the daily purge could not delete it for good; null when nothing held it. |
The platform sets these fields when a manufacturer is deleted and clears them when it is restored, never through an update, so a client does not normally send them in a write.
In this group
- Products — the row, the variant hierarchy, the attribute document, the grid.
- Data model — attributes, groups, options, families, variants, measurement families.
- Categories — the tree, membership, rules.
- References — brands, manufacturers and other reference domains.
- Assets — asset families, assets, and where the bytes live.
- Associations — cross-sells, accessories, quantified relations.
- Completeness — how complete is this product, and against what.
- Import and export — profiles, jobs, files.