# Product ## Overview A Product is the central entity in Apiera, representing a sellable item with its associated data, relationships, and lifecycle state. Products can be simple standalone items or part of a variant structure. ## Basics ### Product types **Simple** — A standalone product with no variants. **Variant parent** — A parent product that groups variants together. Variant parents define which attributes are used for variation (e.g., Color, Size) but are not sellable themselves. **Variant** — A specific variation of a parent product. Each variant represents a unique combination of attribute terms from the parent's variant attributes. ### Core relationships Products connect to several related entities: **Family** — Defines which attributes and categories apply to the product and their requirement levels. The family acts as a template that ensures consistent data structure across similar products. **SKU** — Links to inventory and logistics data including dimensions and weight. Simple products and variants connect to SKUs; variant parents typically do not. **Brand** — Optional brand association for filtering and organization. **Assets** — Images, documents, and videos attached to the product with ordering and a featured flag. **Contents** — Localized versions of name, description, and short description. **Metadata** — Custom key-value pairs for integration-specific data. **Categories and Tags** — Classification and flexible labeling. **Relations** — Cross-references to other products for alternatives, upsells, accessories, replacements, compatibility, and spare parts. ### Variants and attribute terms Variant parents declare which attributes are used for variation by associating them with `isVariant: true`. Variants don't connect to attributes directly—instead, they connect to specific attribute terms from those variant attributes. For example, a T-Shirt variant parent might have Color and Size as variant attributes. A specific variant connects to the terms "Red" and "Large" to represent that combination. ## Publishing Products start in draft status and must be explicitly published to become visible in channels. Publishing triggers validation and sync to connected systems. ### Publishing validation Before a product can be published, the system validates: **Referenced resources must be published** — Any Family or SKU linked to the product must already be in published status. **Family requirements must be satisfied** — The product's Family defines requirement levels for each attribute: | Level | Meaning | | --- | --- | | `must` | Attribute is required—product cannot publish without it | | `should` | Attribute is recommended but not blocking | | `may` | Attribute is optional | | `mustNot` | Attribute must not be present | A product with missing `must` attributes or present `mustNot` attributes will fail validation. ### Status values | Status | Description | | --- | --- | | `draft` | Initial state, not visible anywhere | | `published` | Active and synced to channels | | `unpublished` | Temporarily hidden, can be republished | | `archived` | Long-term storage, excluded from normal queries | | `removed` | Soft-deleted, flagged for permanent deletion | ## Lifecycle Products move between statuses through explicit transitions rather than direct status updates. This ensures business rules are enforced consistently. ### Transitions | Transition | Valid from | Results in | | --- | --- | --- | | `draft` | published, unpublished, archived, removed | draft | | `publish` | draft, unpublished | published | | `unpublish` | published | unpublished | | `archive` | draft, published, unpublished | archived | | `unarchive` | archived | unpublished | | `remove` | draft, published, unpublished, archived | removed | | `restore` | removed | unpublished | ### Archiving vs removal **Archived** products are moved to long-term storage. Use this for discontinued products, seasonal items, or anything you want to retain for historical reference but exclude from day-to-day operations. **Removed** products are soft-deleted. This excludes the product from all standard reads while preserving the data for compliance or recovery purposes. Both archived and removed products are excluded from the standard list queries and hydration results. Use explicit filters ( `isArchived[eq]=true`, `isRemoved[eq]=true`) when you need to access them. ### Cascading effects Changes to related entities can trigger automatic product transitions: **SKU unpublished or removed** — Products linked to that SKU are automatically unpublished. **SKU deleted** — Products linked to that SKU are reverted to draft. **Family deactivated or removed** — Products in that family are automatically unpublished. **Family deleted** — Products in that family are reverted to draft. These cascading transitions ensure products never remain published with invalid or unavailable dependencies. ## Localization Your organization defines supported locales, with one marked as default (`isDefault: true`). Product content (name, description, shortDescription) is stored per locale through content entries. When you update these fields directly on a product via POST or PATCH, you're actually updating the content for the default locale. For additional locales, create content entries through the product contents endpoints. Each content entry is tied to a specific locale and contains that locale's version of the name, description, and short description. If the default locale changes, existing content remains intact—it's associated with the locale itself, not with being "the default." When retrieving products, localized content can be included through hydration. Your application decides which locale to display based on user preference or channel configuration. ## Hydration List and get endpoints support `include[]` parameters to embed related data in a single request, reducing round-trips for common read patterns. Available includes: assets, attributes, attributeTerms, categories, tags, contents, metadata, relations. **Visibility rules apply during hydration:** - Product relations only include products that are published - Soft-deleted items are excluded from all hydrated collections ## Error codes ### Publishing errors | Code | Description | | --- | --- | | `PRODUCT_INVALID_TRANSITION` | Lifecycle transition not allowed from current state | | `PRODUCT_SKU_NOT_PUBLISHED` | Cannot publish—linked SKU is not published | | `PRODUCT_FAMILY_NOT_ACTIVE` | Cannot publish—linked Family is not active | | `MISSING_REQUIRED_ATTRIBUTE` | Family requires an attribute that isn't set | | `MISSING_REQUIRED_CATEGORY` | Family requires a category that isn't assigned | | `PRODUCT_FORBIDDEN_ATTRIBUTE` | Product has an attribute marked `mustNot` in family | | `PRODUCT_FORBIDDEN_CATEGORY` | Product has a category marked `mustNot` in family | ### Structure errors | Code | Description | | --- | --- | | `PRODUCT_FAMILY_REQUIRED` | Product must have a family assigned | | `PRODUCT_SKU_REQUIRED` | Simple products and variants require a SKU | | `PRODUCT_SKU_FORBIDDEN` | Variant parents cannot have a SKU | | `PRODUCT_PARENT_REQUIRED` | Variant products must reference a parent | | `PRODUCT_NOT_VARIANT_PARENT` | Referenced parent is not a variant parent type | | `MISSING_PARENT_REFERENCE` | Variant is missing its parent reference | | `UNEXPECTED_PARENT_REFERENCE` | Simple or variant parent cannot have a parent reference | ### State errors | Code | Description | | --- | --- | | `PRODUCT_NOT_FOUND` | Product does not exist | | `PRODUCT_ARCHIVED` | Cannot modify an archived product | | `PRODUCT_REMOVED` | Cannot modify a removed product | | `PRODUCT_MUST_UNPUBLISH_TO_CHANGE_FAMILY` | Unpublish before changing family | | `PRODUCT_MUST_UNPUBLISH_TO_CHANGE_SKU` | Unpublish before changing SKU | ### Field validation errors | Code | Description | | --- | --- | | `PRODUCT_NAME_EMPTY` | Name cannot be empty | | `PRODUCT_NAME_TOO_SHORT` | Name is below minimum length | | `PRODUCT_NAME_TOO_LONG` | Name exceeds maximum length | | `PRODUCT_DESCRIPTION_EMPTY` | Description cannot be empty | | `PRODUCT_DESCRIPTION_TOO_SHORT` | Description is below minimum length | | `PRODUCT_DESCRIPTION_TOO_LONG` | Description exceeds maximum length | | `PRODUCT_SHORT_DESCRIPTION_EMPTY` | Short description cannot be empty | | `PRODUCT_SHORT_DESCRIPTION_TOO_SHORT` | Short description is below minimum length | | `PRODUCT_SHORT_DESCRIPTION_TOO_LONG` | Short description exceeds maximum length | | `PRODUCT_METADATA_KEY_EMPTY` | Metadata key cannot be empty | | `PRODUCT_METADATA_KEY_TOO_SHORT` | Metadata key is below minimum length | | `PRODUCT_METADATA_KEY_TOO_LONG` | Metadata key exceeds maximum length | | `PRODUCT_METADATA_VALUE_EMPTY` | Metadata value cannot be empty | | `PRODUCT_METADATA_VALUE_TOO_SHORT` | Metadata value is below minimum length | | `PRODUCT_METADATA_VALUE_TOO_LONG` | Metadata value exceeds maximum length |