The Bluestone Integration is a comprehensive event-driven system that synchronizes product, category, and attribute data from Bluestone PIM to Adobe Commerce. This integration uses Adobe I/O Events and App Builder runtime actions to ensure reliable, scalable data synchronization with advanced validation, retry mechanisms, and concurrency control.
The integration follows a multi-stage process designed for reliability and data consistency:
- Sync Trigger: Bluestone completes a sync operation and sends a webhook notification
- Event Processing: App Builder ingestion webhook validates and publishes sync events
- Difference Detection: Sync consumer fetches differences and publishes entity-specific events
- Data Enrichment: Publisher fetches full entity data from Bluestone and enriches events
- Entity Processing: Specialized consumers validate and process attributes, categories, and products individually
- Asset Synchronization: Product processing triggers media synchronization events for asset management
When: Bluestone completes a sync operation
What happens:
- Bluestone sends a signed webhook to the App Builder ingestion endpoint
- Webhook signature is verified using
BLUESTONE_PRIMARY_SECRET - Request data is validated and structured
SYNC_DONEevent is published to Adobe I/O Events
Key Components:
- Security: HMAC SHA256 signature verification
- Validation: Request structure and required field validation
- Event Publishing: Publishes to Adobe I/O Events for downstream processing
When: SYNC_DONE event is received from I/O Events
What happens:
- Validates sync event structure
- Fetches sync details and entity differences from Bluestone API
- Processes three entity types in parallel: attributes, categories, and products
- Publishes separate events for each changed entity
Key Operations:
const [attributeDifferences, categoryDifferences, productDifferences] = await Promise.all([
getSyncDifferencesForAttributes(bluestoneClient, event.syncId),
getSyncDifferencesForCategories(bluestoneClient, event.syncId),
getSyncDifferencesForProducts(bluestoneClient, event.syncId),
]);When: Entity synchronization events are received
What happens:
- Fetches complete entity data from Bluestone API based on entity type
- Generates MD5 hash for change detection and duplicate prevention
- Creates enriched
EntityDataReadyEventwith full entity payload - Publishes to appropriate consumer based on entity type
Hash Generation:
hash: entityData ? Md5.hashStr(JSON.stringify(entityData)) : "";Processing: Immediate synchronization with Adobe Commerce
Validation Chain:
- Removal Validator: Checks if attribute is marked for deletion
- Hash Validator: Compares entity hash to detect actual changes
What happens:
- Maps Bluestone attributes to Adobe Commerce format using strategy pattern
- Creates/updates/removes attributes directly via Adobe Commerce REST API
- Assigns attributes to configured attribute group (
COMMERCE_ATTRIBUTE_GROUP_ID) - Stores mapping between Bluestone and Commerce attribute IDs
Attribute Type Mapping:
boolean- Maps tobackend_type: "int",frontend_input: "boolean"decimal- Maps tobackend_type: "decimal",frontend_input: "text"integer- Maps tobackend_type: "int",frontend_input: "text"single_select- Maps tobackend_type: "int",frontend_input: "select"multi_select- Maps tobackend_type: "int",frontend_input: "multiselect"date- Maps tobackend_type: "datetime",frontend_input: "date"time- Maps tobackend_type: "datetime",frontend_input: "text"date_time- Maps tobackend_type: "datetime",frontend_input: "datetime"text- Maps tobackend_type: "varchar",frontend_input: "text"formatted_text- Maps tobackend_type: "varchar",frontend_input: "text"
Processing: Immediate synchronization with dependency validation
Validation Chain:
- Removal Validator: Checks if category is marked for deletion
- Hash Validator: Compares entity hash to detect changes
- Parent Category Validator: Ensures parent categories exist in Adobe Commerce
What happens:
- Validates parent category existence before processing
- Maps Bluestone categories to Adobe Commerce format
- Creates/updates/removes categories directly via Adobe Commerce REST API
- Handles hierarchical category relationships
Dependency Handling: If parent category is missing, publishes event to request parent category sync:
await publishEntityToSynchronizeEvent({
syncId: params.data.syncId,
context: params.data.context,
entityId: missingParentCategoryId,
entityType: SyncEntityType.CATEGORY,
diffType: SyncDifferenceType.ADD,
});Processing: Two-stage validation and individual event-driven processing
Stage 1: Validation (actions-src/product/action/validate/)
Validation Chain:
- Removal Validator: Checks if product is marked for deletion
- Hash Validator: Compares entity hash to detect changes
- Attribute Validator: Ensures all required attributes exist in Adobe Commerce
- Attribute Option Validator: Validates select attribute options exist
- Category Validator: Ensures all assigned categories exist in Adobe Commerce
- Configurable Product Validator: For variant groups, validates child products exist
What happens after validation:
- If validation passes, publishes
PRODUCT_PROCESSevent to Adobe I/O Events - If validation fails, publishes dependency sync events and returns 599 for retry
Stage 2: Processing (actions-src/product/action/process/)
When: PRODUCT_PROCESS event is received from I/O Events
What happens:
- Processes products individually, one by one (no batching)
- Maps products using builder pattern for attributes, categories, and general properties
- Creates/updates/removes product directly via Adobe Commerce REST API
- Executes post-processing for configurable product setup and media synchronization
- Stores mapping between Bluestone and Commerce product IDs
Product Type Handling:
- Simple Products: Direct mapping and storage with configurable attribute tracking
- Configurable Products: Sets up variant relationships and configurable product options
- Variant Products: Links to parent configurable products with variant-specific data
Processing: Individual media synchronization triggered by product processing
Validation Chain:
- Removal Validator: Checks if asset is marked for deletion
- Hash Validator: Compares entity hash to detect changes
- Asset Validator: Validates media URL, content type, and required fields
What happens:
- Downloads media from Bluestone download URI
- Converts media to base64 format for Adobe Commerce
- Creates/updates/removes product media via Adobe Commerce media gallery API
- Supports image types (JPEG, PNG, GIF, BMP, WebP, SVG)
- Video support planned for future implementation
- Stores mapping between Bluestone media and Commerce asset IDs
Media Processing Flow:
// Triggered during product post-processing
const mediaDiff = this.calculateMediaDifferences(bluestoneProduct, commerceProduct, assetMappings);
await this.publishMediaEvents(event, mediaDiff);Purpose: Prevents processing of unchanged entities
Implementation: MD5 hash of entity JSON stored in Adobe I/O State
Benefits:
- Reduces unnecessary API calls to Adobe Commerce
- Prevents duplicate processing of same data
- Provides audit trail of changes
const hash = Md5.hashStr(JSON.stringify(entityData));
const existingHash = await getHash(entityType, entityId);
if (hash === existingHash) {
return { type: ValidationResultType.SKIP, message: "No changes detected" };
}Purpose: Handles validation failures gracefully with dependency resolution
How it works:
- When validation fails (e.g., missing attributes/categories), returns HTTP 599
- Adobe I/O Events automatically retries actions that return 599
- System publishes events to sync missing dependencies
- Uses validation guard to prevent duplicate dependency requests during retries
Implementation:
// Mark dependency events as published to prevent duplicates
await markDependencyEventsAsPublished(params.data);
await this.handleFailure(validationResult, params);
return errorResponseWithObject(HttpStatus.TO_BE_RETRIED, validationResult);Validation Guard:
- Stores state in Adobe I/O State with 1-minute TTL
- Prevents publishing multiple dependency events during retry cycles
- Key format:
dependency-events-{syncId}-{entityId}
Purpose: Prevents parallel processing of the same entities
Implementation: Distributed locking using Adobe I/O State
Features:
- 5-minute default lock TTL
- Automatic lock expiration handling
- Retry mechanism with backoff (5 attempts, 1-second delay)
- Graceful lock release in finally blocks
Lock Key Format: lock-{entityType}-{entityId}
const lockId = await EntityLockManager.acquireLockWithRetry(
event.entityType,
event.entityId,
300 // 5 minutes TTL
);
if (!lockId) {
return errorResponseWithObject(HttpStatus.TO_BE_RETRIED, {
message: "Entity is being processed by another instance",
reason: "Concurrent processing prevention",
});
}Purpose: Maintains relationships between Bluestone and Adobe Commerce entities
Storage: Adobe I/O Files (persistent storage)
Structure: JSON files organized by entity type
Benefits:
- Enables entity updates and relationship management
- Supports configurable product variant linking
- Provides data consistency across sync operations
Mapping Structure:
{
bluestoneId: "bluestone-entity-id",
commerceId: 123,
commerceCode: "entity-code",
data: [] // Additional mapping data (e.g., attribute options)
}Components:
- Adobe I/O Events: Event backbone for all inter-action communication
- Provider System: Separates internal and external event sources
- Event Types: Specialized events for each entity type and operation
Event Flow:
Webhook → SYNC_DONE → EntityToSynchronize → EntityDataReady → Processing
The integration requires several environment variables for proper operation:
COMMERCE_ATTRIBUTE_GROUP_ID=1305Purpose: Specifies which Adobe Commerce attribute group newly created attributes should be assigned to
Important Limitation: All attributes are assigned to the default attribute set (ID: 4) and this specific group
Usage: Used in syncAttribute() when creating new attributes
BLUESTONE_CONFIGURABLE_ATTRIBUTE_GROUP_ID=684bde0f29b93b012e765ff3Purpose: Identifies which Bluestone attribute group contains configurable product attributes
Usage:
- Filters out configurable attributes from variant group products during attribute building
- Identifies configurable attributes for simple product storage strategy
- Used in validation to determine product configurability
ADOBE_COMMERCE_MAPPING_LANGUAGES='[
{"commerceId": 0, "commerceCode": "all", "externalId": "en"},
{"commerceId": 6, "commerceCode": "german_store_view", "externalId": "l3682"}
]'Purpose: Maps Bluestone context IDs to Adobe Commerce store views
Format: JSON array of mapping objects
Properties:
commerceId: Adobe Commerce store ID (0 for default/all stores)commerceCode: Adobe Commerce store codeexternalId: Bluestone context identifier
Usage:
- Determines correct store view for attribute labels and values
- Enables multi-store/multi-language product synchronization
- Used in attribute mapping and product localization
The full synchronization feature enables comprehensive entity synchronization from Bluestone PIM to Adobe Commerce, allowing you to trigger synchronization for all entities of a specific type (attributes, categories, or products). This feature internally uses pagination to efficiently handle large datasets while providing a simple, clean API interface.
The full sync action (actions-src/full-sync/trigger/) provides a web-exposed endpoint that supports two modes of operation:
When entityIds parameter is not provided or empty:
- Paginated Entity Fetching: Internally queries Bluestone Public API with pagination to retrieve entities efficiently
- Automatic Page Processing: Processes all pages of entities (100 items per page)
- Generates Sync Events: Creates
EntityToSynchronizeEventfor each entity found - Leverages Existing Pipeline: Uses the same event-driven processing pipeline as regular syncs
When entityIds parameter is provided with specific entity IDs:
- Direct Event Publishing: Bypasses Bluestone API fetching entirely
- Targeted Synchronization: Creates
EntityToSynchronizeEventonly for the specified entity IDs - Performance Optimization: Faster processing as it skips API calls to fetch entity lists
- Leverages Existing Pipeline: Uses the same event-driven processing pipeline as regular syncs
Endpoint Pattern: POST /full-sync/trigger
Supported Entity Types:
attribute- Synchronizes product attributes usingGET /attributes?pageNo=0&itemsOnPage=100category- Synchronizes categories usingGET /categories/scan?pageNo=0&itemsOnPage=100product- Synchronizes products usingPOST /products/list?pageNo=0&itemsOnPage=100
Request Parameters:
entityType(required): Type of entities to synchronize (attribute,category, orproduct)context(optional): Bluestone context/language (defaults to "default")syncId(optional): Custom sync identifier (auto-generated if not provided)entityIds(optional): Array of specific entity IDs to synchronize. When provided, bypasses Bluestone API fetching and directly synchronizes the specified entities
Response Format:
For full synchronization (all entities):
{
"message": "Full sync processed successfully for {entityType}",
"entityType": "attribute|category|product",
"context": "production",
"syncId": "full-sync-uuid",
"entitiesPublished": 100
}For selective synchronization (specific entities):
{
"message": "Full sync processed successfully for {entityType}",
"entityType": "attribute|category|product",
"context": "production",
"syncId": "full-sync-uuid",
"entitiesPublished": 3
}Note: When using entityIds, the entitiesPublished count reflects the number of specific entities requested, not the total count from Bluestone API.
Best for:
- Initial data migration from Bluestone to Adobe Commerce
- Periodic full data reconciliation
- Disaster recovery scenarios
- When you need to ensure all entities are synchronized
Benefits:
- Ensures complete data consistency
- Automatically handles pagination
- Discovers all available entities from Bluestone
Best for:
- Targeted entity updates after specific changes
- Performance-critical scenarios with large catalogs
- Debugging specific entity synchronization issues
- Re-synchronizing entities that previously failed
Benefits:
- Faster execution (no API calls to fetch entity lists)
- Reduced resource usage
- More precise control over synchronization scope
- Lower impact on Bluestone API rate limits
Synchronize all products from Bluestone:
curl -X POST "https://your-app-builder-namespace.adobeioruntime.net/api/v1/web/full-sync/trigger" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entityType": "product",
"context": "en"
}'Synchronize all attributes with a custom sync ID:
curl -X POST "https://your-app-builder-namespace.adobeioruntime.net/api/v1/web/full-sync/trigger" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entityType": "attribute",
"context": "en",
"syncId": "custom-sync-123"
}'Synchronize specific products by their IDs:
curl -X POST "https://your-app-builder-namespace.adobeioruntime.net/api/v1/web/full-sync/trigger" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entityType": "product",
"context": "en",
"entityIds": ["prod-123", "prod-456", "prod-789"]
}'Synchronize specific categories:
curl -X POST "https://your-app-builder-namespace.adobeioruntime.net/api/v1/web/full-sync/trigger" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entityType": "category",
"context": "production",
"entityIds": ["cat-001", "cat-002"],
"syncId": "selective-cat-sync"
}'The full sync feature integrates with specific Bluestone API endpoints:
Attributes:
- Endpoint:
GET /attributes - Query Parameters:
pageNo=0&itemsOnPage=100 - Context: Sent as header parameter
Categories:
- Endpoint:
GET /categories/scan - Query Parameters:
pageNo=0&itemsOnPage=100 - Context: Sent as header parameter
Products:
- Endpoint:
POST /products/list - Query Parameters:
pageNo=0&itemsOnPage=100 - Body: Empty object
{} - Context: Sent as header parameter
All endpoints return structured responses with totalCount and results[] fields.
Success Response:
{
"statusCode": 200,
"body": {
"message": "Full sync triggered successfully for attribute",
"entityType": "attribute",
"context": "production",
"syncId": "full-sync-550e8400-e29b-41d4-a716-446655440000",
"entitiesPublished": 100,
"totalCount": 2500
}
}Error Responses:
{
"statusCode": 400,
"body": {
"error": "Invalid entity type. Must be one of: attribute, category, product, asset"
}
}{
"statusCode": 500,
"body": {
"error": "Unsupported entity type: asset"
}
}