Product Attribute Values Guide
Overview
Product Attribute Values are the concrete data points that bind an attribute definition to a specific product. Where the Product Attributes guide explains how to create and configure attribute definitions (the schema), this guide focuses on the values stored against those definitions - querying system-wide statistics, exporting a product's full attribute profile, and comparing attribute values between two products side by side.
Attribute values live inside the Product aggregate. They are written through the standard POST /products and PUT /products/{id} endpoints covered in the Product Attributes guide. This guide covers the three read-oriented endpoints that operate on the attribute-value layer directly: statistics, export, and comparison.
Value Types
All 12 attribute types supported by the attribute definition system produce values in the attribute-value layer. Each type has its own storage representation and display formatting:
| Type | Stored As | getFormattedValue() Example | getDisplayValue() Example |
|---|---|---|---|
TEXT | String | "100% Cotton" | "100% Cotton" |
NUMBER | String (numeric) | "300 threads/inch" | "300" |
BOOLEAN | String ("1"/"0") | "Yes" | "Yes" |
DATE | String (ISO 8601) | "January 15, 2024" | "2024-01-15" |
SELECT | String | "Red" | "Red" |
MULTISELECT | JSON array string | "Machine Wash, Tumble Dry" | "Machine Wash, Tumble Dry" |
COLOR | Hex string | "#FF5733" | "#FF5733" |
IMAGE | URL string | "https://cdn.example.com/img.jpg" | "https://cdn.example.com/img.jpg" |
URL | URL string | "https://youtube.com/watch?v=abc" | "https://youtube.com/watch?v=abc" |
EMAIL | String | "contact@manufacturer.com" | "contact@manufacturer.com" |
PHONE | String | "+1-555-0123" | "+1-555-0123" |
JSON | JSON string | Formatted object | Raw JSON string |
Values are always stored as strings internally. getFormattedValue() applies type-aware formatting for display (e.g., appending units to NUMBER types, joining MULTISELECT arrays with commas). getDisplayValue() returns a plain frontend-friendly string without additional decoration.
API Endpoints
All endpoints are under the base path /api/v1/operations.
1. Get Attribute Value Statistics
Retrieve system-wide aggregate statistics across all attribute values stored in the tenant's product catalog.
Endpoint: GET /api/v1/operations/product-attribute-values/statistics
Authentication: Required (Bearer token)
Response (200 OK):
{
"success": true,
"message": "Attribute value statistics retrieved successfully",
"data": {
"total_values": 8423,
"products_with_attributes": 645,
"average_attributes_per_product": 13.1,
"by_type": {
"TEXT": 2341,
"SELECT": 1876,
"NUMBER": 1203,
"BOOLEAN": 987,
"MULTISELECT": 754,
"DATE": 412,
"COLOR": 389,
"URL": 201,
"IMAGE": 148,
"EMAIL": 67,
"PHONE": 31,
"JSON": 14
}
},
"meta": {}
}Response Fields:
| Field | Description |
|---|---|
total_values | Total attribute-value records across all products |
products_with_attributes | Number of distinct products that have at least one attribute value |
average_attributes_per_product | Mean number of attribute values per product (includes only products that have at least one value) |
by_type | Count of stored values broken down by attribute type |
Usage Note
This endpoint aggregates across all products in the tenant. It is well-suited for catalog health dashboards and data completeness monitoring, not for per-product detail. To inspect values on a specific product, retrieve the product via GET /api/v1/operations/products/{id}.
2. Export Product Attribute Values
Export all attribute values for a single product as either CSV or JSON. Useful for integrations, audits, and data migrations.
Endpoint: GET /api/v1/operations/products/{id}/attribute-values/export
Authentication: Required (Bearer token)
Path Parameters:
id(ULID, required) - The product's ULID identifier
Query Parameters:
format(string, required) - Export format:csvorjson
Example Requests:
# Export as CSV
GET /api/v1/operations/products/01hwxyz123abc456def789ghi0/attribute-values/export?format=csv
# Export as JSON
GET /api/v1/operations/products/01hwxyz123abc456def789ghi0/attribute-values/export?format=jsonResponse - JSON format (200 OK):
{
"success": true,
"message": "Attribute values exported successfully",
"data": {
"product_id": "01hwxyz123abc456def789ghi0",
"product_name": "Classic Cotton T-Shirt",
"exported_at": "2026-03-11T09:00:00Z",
"format": "json",
"values": [
{
"attribute_code": "color",
"attribute_name": "Color",
"attribute_type": "SELECT",
"value": "Navy",
"formatted_value": "Navy",
"display_value": "Navy"
},
{
"attribute_code": "size",
"attribute_name": "Size",
"attribute_type": "SELECT",
"value": "L",
"formatted_value": "L",
"display_value": "L"
},
{
"attribute_code": "thread_count",
"attribute_name": "Thread Count",
"attribute_type": "NUMBER",
"value": "300",
"formatted_value": "300 threads/inch",
"display_value": "300"
},
{
"attribute_code": "organic_certified",
"attribute_name": "Organic Certified",
"attribute_type": "BOOLEAN",
"value": "1",
"formatted_value": "Yes",
"display_value": "Yes"
}
],
"total": 4
},
"meta": {}
}Response - CSV format:
For format=csv, the response body is a plain CSV file with Content-Type: text/csv and a Content-Disposition: attachment header. Columns are: attribute_code, attribute_name, attribute_type, value, formatted_value, display_value.
attribute_code,attribute_name,attribute_type,value,formatted_value,display_value
color,Color,SELECT,Navy,Navy,Navy
size,Size,SELECT,L,L,L
thread_count,Thread Count,NUMBER,300,300 threads/inch,300
organic_certified,Organic Certified,BOOLEAN,1,Yes,Yes3. Compare Attribute Values Between Products
Compare attribute values for two products side by side. Optionally filter to only the attributes that differ between them.
Endpoint: POST /api/v1/operations/products/compare-attributes
Authentication: Required (Bearer token)
Request Body:
{
"product_id_1": "01hwxyz123abc456def789ghi0",
"product_id_2": "01hwxyz123abc456def789ghi1",
"attribute_ids": [
"01hwattr000000000000000001",
"01hwattr000000000000000002",
"01hwattr000000000000000003"
],
"include_only_differences": false
}Request Fields:
| Field | Type | Required | Description |
|---|---|---|---|
product_id_1 | ULID | Yes | First product to compare |
product_id_2 | ULID | Yes | Second product to compare |
attribute_ids | array | No | Limit comparison to specific attribute ULIDs. Omit to compare all shared attributes |
include_only_differences | boolean | No | When true, only attributes where the two products differ are returned (default: false) |
Response (200 OK):
{
"success": true,
"message": "Product attributes compared successfully",
"data": {
"product_1": {
"id": "01hwxyz123abc456def789ghi0",
"name": "Classic Cotton T-Shirt - Navy L"
},
"product_2": {
"id": "01hwxyz123abc456def789ghi1",
"name": "Classic Cotton T-Shirt - Red M"
},
"comparison": [
{
"attribute_code": "color",
"attribute_name": "Color",
"attribute_type": "SELECT",
"product_1_value": "Navy",
"product_2_value": "Red",
"is_different": true
},
{
"attribute_code": "size",
"attribute_name": "Size",
"attribute_type": "SELECT",
"product_1_value": "L",
"product_2_value": "M",
"is_different": true
},
{
"attribute_code": "material",
"attribute_name": "Material",
"attribute_type": "TEXT",
"product_1_value": "100% Cotton",
"product_2_value": "100% Cotton",
"is_different": false
},
{
"attribute_code": "thread_count",
"attribute_name": "Thread Count",
"attribute_type": "NUMBER",
"product_1_value": "300",
"product_2_value": "300",
"is_different": false
}
],
"summary": {
"total_compared": 4,
"differences": 2,
"matches": 2
}
},
"meta": {}
}Business Scenarios
Scenario 1: Catalog Data Completeness Audit
Context: A catalog manager wants to understand how thoroughly the product catalog has been enriched with attribute data before launching a new storefront.
Workflow:
- Pull statistics to get the overall picture
- Calculate completeness against expected attribute count
- Target products below the average for enrichment
# 1. Get system-wide statistics
GET /api/v1/operations/product-attribute-values/statistics
# Response shows average_attributes_per_product: 13.1
# Internal target: every product should have at least 8 attributes
# 2. Identify products that have fewer attributes than average
# (via standard products list filtered by your own logic or a reporting tool)
# 3. Export a specific under-enriched product for offline review
GET /api/v1/operations/products/01hwxyz123abc456def789ghi0/attribute-values/export?format=csvScenario 2: Product Variant Verification
Context: A product team has created two variants of the same base product (e.g., a T-Shirt in two colour/size combinations) and needs to confirm only the intended attributes differ.
Workflow:
- Run the comparison endpoint between the two variants
- Use
include_only_differences: trueto focus on divergences - Review unexpected matches or differences and correct them via product update
POST /api/v1/operations/products/compare-attributes
{
"product_id_1": "01hwxyz123abc456def789ghi0",
"product_id_2": "01hwxyz123abc456def789ghi1",
"include_only_differences": true
}The response summary.differences count should equal only the number of attributes that legitimately differ between variants (e.g., color and size). If additional unexpected differences appear, update those products to align shared attribute values.
Scenario 3: Integration Data Handoff
Context: An e-commerce platform integration requires product attribute data in a structured format for catalogue synchronisation.
Workflow:
- For each product in scope, call the JSON export endpoint
- Transform the
valuesarray into the integration's expected schema - Push formatted data to the downstream platform
# Export all attribute values for a product as structured JSON
GET /api/v1/operations/products/01hwxyz123abc456def789ghi0/attribute-values/export?format=json
# The response `data.values` array is stable and type-annotated,
# making it straightforward to map to external schemas.Best Practices
1. Prefer JSON Export for Programmatic Consumption
When building integrations or feeding attribute data into downstream systems, use format=json. The typed attribute_type field lets your code branch on type without needing to query the attribute definition separately. Reserve format=csv for human-readable exports and spreadsheet workflows.
2. Use include_only_differences for Variant QA
When maintaining a product catalog with many variants, the comparison endpoint with include_only_differences: true is a fast sanity check. Running it after bulk product imports can surface accidental data divergences before they reach the storefront.
3. Monitor the by_type Distribution in Statistics
A healthy catalog typically has TEXT, SELECT, and NUMBER values as its largest groups. A very high proportion of JSON values may indicate that structured data is being stuffed into JSON attributes rather than decomposed into typed fields. Revisit your attribute schema if this ratio looks unusual.
4. Write Values Through the Products API
Attribute values are managed as part of the Product aggregate - there is no standalone "create attribute value" endpoint. Always set or update values via POST /api/v1/operations/products (on create) or PUT /api/v1/operations/products/{id} (on update), using the attributes map. This ensures aggregate consistency, validation, and audit trail correctness.
Integration Points
With Product Attributes
The values described in this guide are instances of the attribute definitions managed in the Product Attributes guide. Before a value can be stored for an attribute, that attribute definition must exist. Changes to an attribute's options (e.g., adding a new SELECT value) are reflected immediately in subsequent value writes.
With Product Variants
Attribute values are the mechanism that distinguishes product variants. A variant set shares a base product but differs on one or more dimension attributes (color, size, material). The comparison endpoint is particularly valuable when verifying variant setup. Refer to the Product Variants guide for the full variant creation workflow.
With Inventory and Pricing
Attribute values feed filtering and segmentation rules in inventory management and pricing strategies. For example, a pricing rule may apply a surcharge to all products where material = "Leather", relying on the attribute value being correctly populated. Refer to the Pricing Strategy guide and Inventory Management guide.
Troubleshooting
Export Returns Empty values Array
Symptom: The export endpoint returns a 200 OK response but data.values is an empty array and data.total is 0.
Cause: The product exists but has no attribute values assigned to it yet.
Solution: Assign attribute values to the product via the Products API before exporting:
PUT /api/v1/operations/products/01hwxyz123abc456def789ghi0
{
"attributes": {
"color": "Navy",
"size": "L",
"material": "100% Cotton"
}
}Comparison Returns null for One Product's Value
Symptom: A comparison row shows "product_1_value": "Red" but "product_2_value": null.
Cause: The second product does not have a value stored for that attribute, even though the attribute definition exists.
Solution: Check the second product's attribute values and populate any missing ones:
GET /api/v1/operations/products/01hwxyz123abc456def789ghi1/attribute-values/export?format=jsonReview the response to identify which attributes are absent, then update the product with the missing values.
Related Documentation
- Product Attributes Guide - Defining and managing attribute templates
- Product Variants Guide - Using attributes to generate variant sets
- Product Lifecycle Guide - End-to-end product management workflow
- Pricing Strategy Guide - Attribute-driven pricing rules