---
title: "Opening products for editing | Customer&#x27;s Canvas Hub"
canonical: "https://customerscanvas.com/docs/hub/dev-center/scenarios/online-store/opening-products-for-editing/"
---

# Opening products for editing

> When you organize your products in Customer's Canvas, you can use them in your app through the BackOffice API. Let's look at how you can open a product for editing and render the personalization result using Customer's Canvas tools.

To open products for editing, you need a product ID and the corresponding workflow ID. Then, depending on the workflow type, you will need to use the appropriate editor. After completing the personalization and checkout process, you can create a project using the order data.

To use the API, you first need to [request an access token](https://customerscanvas.com/docs/hub/dev-center/api/auth.md#requesting-an-access-token-for-the-client-credentials-flow), which needs to be added to every request.

## Getting the product ID

To get product identifiers, you can search for products in your tenant by their names, SKUs, tags, or custom fields using the endpoint [`GET /api/storefront/v1/products`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/products/GetAllProducts). For example, let's get a list of _cards_.

**cURL**

```bash
curl -X \
  GET "https://api.customerscanvashub.com/api/storefront/v1/products?search=card&tenantId=12345" \
  -H  "accept: text/plain" \
  -H  "Authorization: Bearer <TOKEN>"
```

**HTTP**

```
GET https://api.customerscanvashub.com/api/storefront/v1/products?search=card&tenantId=12345
```

**C#**

```cs
var tenantId = 12345; // Set your tenant ID here
var name = "card"; // Set a name mask ID here
var allProducts = await productsApiClient.GetAllProductsAsync(search: name, tenantId: tenantId);
```

**TS**

```ts
var tenantId = 12345; // Set your tenant ID here
var name = "card"; // Set a name mask ID here
var allProducts = _productsApiClient.getAllProducts(null, null, null, name, tenantId);
```

**PHP**

API client not available

The response of this endpoint will contain an `items` array with objects called [`ProductDto`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#model/ProductDto). Among the properties of this object, you can find the product `id`, `personalizationWorkflowId`, and `processingPipelineId`.

## Getting the workflow

Using the product ID, you can get such workflow details as the type and definition with the endpoint [`/api/storefront/v1/product-references/{reference}/personalization-workflow`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/products/GetPersonalizationWorkflow).

**cURL**

```bash
curl -X \
  GET "https://api.customerscanvashub.com/api/storefront/v1/products/417/personalization-workflow" \
  -H  "accept: text/plain" \
  -H  "Authorization: Bearer <TOKEN>"
```

**HTTP**

```
GET https://api.customerscanvashub.com/api/storefront/v1/products/417/personalization-workflow
```

**C#**

```cs
var productId = 417; // Set your product ID here
var workflow = await productsApiClient.GetPersonalizationWorkflowAsync(productId);
```

**TS**

```ts
var productId = 417; // Set your product ID here
var workflow = _productsApiClient.getPersonalizationWorkflow(productId);
```

**PHP**

API client not available

In the response of the endpoint, there is a `workflowType` property with a string value: `UIFramework`, `SimpleEditor`, `DesignEditor`, or `HandyEditor`.

The workflow type allows you to run the appropriate editor. For example, let's learn how to open a product in the Simple Editor.

When you are using the editors deployed in a Customer's Canvas tenant, you can retrieve links to them through the API.

## Getting the Simple Editor link

The endpoint [`GET /api/storefront/v1/tenant-info/applications`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/tenantinfo/GetApplicationsInfo) allows you to get links to the editors deployed in your tenant.

**cURL**

```bash
curl -X \
  GET "https://api.customerscanvashub.com/api/storefront/v1/tenant-info/applications?tenantId=12345" \
  -H  "accept: text/plain" \
  -H  "Authorization: Bearer <TOKEN>"
```

**HTTP**

```
GET https://api.customerscanvashub.com/api/storefront/v1/tenant-info/applications?tenantId=12345
```

**C#**

```cs
var tenantId = 12345; // Set a tenant ID
var applicationsInfo = await tenantInfoApiClient.GetApplicationsInfoAsync(tenantId);
```

**TS**

```ts
var tenantId = 12345; // Set a tenant ID
var applicationsInfo = _tenantInfoApiClient.getApplicationsInfo(tenantId);
```

**PHP**

```php
$tenantId = 12345; // Set a tenant ID
$applicationsInfo = $tenantInfoApiClient->tenantInfoGetApplicationsInfo($tenantId);
```

In the response, find the `simpleEditorUrl`.

```json
{
  "uiFrameworkUrl": "https://staticjs-aurigma.azureedge.net/ui-framework/stable",
  "simpleEditorUrl": "https://staticjs-aurigma.azureedge.net/simple-editor/stable",
  "workflowElementsUrl": "https://staticjs-aurigma.azureedge.net/libs/us/workflow-elements",
  ...
}
```

## Opening the Simple Editor

Now that you know the URL that links to the editor, let's open it.

1. Add the script and styles to a page.

    ```ts
    // Simple Editor styles
    const editorStylesUrl = simpleEditorUrl + '/styles.css';
    const editorStylesElement = document.createElement('link');
    editorStylesElement.href = editorStylesUrl;
    editorStylesElement.rel = 'stylesheet';
    document.head.appendChild(editorStylesElement);

    // Simple Editor script
    const editorScriptUrl = simpleEditorUrl + '/editor.js';
    const editorScriptElement = document.createElement('script');
    editorScriptElement.src = editorScriptUrl;
    document.head.appendChild(editorScriptElement);
    ```

2. Add an editor container.

    ```html
    <main class="main">
      <au-simple-editor></au-simple-editor>
    </main>
    ```

3. Initialize the editor on page load.

    ```ts
    editorScriptElement.onload = () => {
        const simpleEditor = document.getElementsByTagName('au-simple-editor').item(0);
        simpleEditor?.init({
            integration: {
                tenantId: <yourTenantId>,
                user: {
                    id: <userId>,
                    token: <userToken>
                },
                storefrontId: <yourStorefrontId>,
                cchubApiGatewayUrl: "https://api.customerscanvashub.com"
            },
            product: {
                productId: <productId>
            },
            settings: {<workflowContent>},
        });
    };
    ```

Here, you must pass a token generated for a user. The endpoint [`POST /api/storefront/v1/storefront-users`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/storefrontusers/Create) adds users to your application, and [`GET /api/storefront/v1/storefront-users/token`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/storefrontusers/GetToken) generates tokens for them, as described in the [Registering customers](https://customerscanvas.com/docs/hub/dev-center/api/storefront/register-customers.md) topic.

In the `settings`, pass the workflow `content`.

For more details, you can refer to the [Simple Editor workflow](https://customerscanvas.com/docs/hub/dev-center/frontend-integration/workflow-elements/simple-editor/initialization.md) topic.

## Data for creating projects

When the user finishes editing the product, the `addtocart` event is triggered. To process the result, handle this event as follows:

```js
simpleEditor.addEventListener("addtocart", event => {
    const cartItem = event.detail;
    console.log(cartItem);
});
```

The event returns an object containing details about the personalized cart item:

```js
{
  key: string;      // Unique identifier for this line item, matching the `stateId`
  quantity: number; // Number of units ordered for this line item
  originalProductId: string; // Original product ID before any customization or editing
  sku: string;               // Stock Keeping Unit (SKU) used for inventory tracking
  productVariantId: number;  // ID of the specific product variant (e.g., size, color)
  productId: number;         // ID of the base PIM product
  productVersionId: number;  // ID of the PIM product version, tracking any change
  productLinkId: number; // ID linking this line item to a specific product in the storefront
  properties: {
    _stateId: string[]; // Array of state file identifiers, representing saved designs
    _userId: string; // Unique identifier of the customer who edited and owns these state files
    _hidden: {
      images: string[]; // Array of URLs pointing to preview images of the personalized design
    };
  };
}
```

### Creating a project from cart data

You can use the `cartItem` data to create a project using the endpoint [`POST /api/storefront/v1/projects/with-single-item`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/projects/CreateWithSingleItem). Here's an example:

**cURL**

```bash
curl -X \
POST "https://api.customerscanvashub.com/api/storefront/v1/projects/with-single-item?storefrontId=12" \
-H  "accept: text/plain" \
-H  "Content-Type: application/json" \
-H  "Authorization: Bearer <TOKEN>" \
-d '{
  "ownerId": $cartItem.properties._userId,
  "item": {
    "productReference": $cartItem.originalProductId,
    "designIds": $cartItem.properties._stateId,
    "sku": $cartItem.sku,
    "quantity": $cartItem.quantity
  }
}'
```

**HTTP**

```http
POST https://api.customerscanvashub.com/api/storefront/v1/projects/with-single-item?storefrontId=12
Content-Type: application/json
{
  "ownerId": "$cartItem.properties._userId",
  "item": {
    "productReference": "$cartItem.originalProductId",
    "designIds": "$cartItem.properties._stateId",
    "sku": "$cartItem.sku",
    "quantity": $cartItem.quantity
  }
}
```

**C#**

```cs
// Set a real storefront ID
var storefrontId = 12;
// Set a product reference, owner ID, and design IDs from cartItem
var body = $$"""
{
    "ownerId": "{{cartItem.properties._userId}}",
    "item": {
        "productReference": "{{cartItem.originalProductId}}",
        "designIds": "{{cartItem.properties._stateId}}",
        "sku": "{{cartItem.sku}}",
        "quantity": {{cartItem.quantity}}
    }
}
""";
var project = await projectsApiClient.CreateWithSingleItemAsync(storefrontId, null, body);
```

**TS**

```ts
// Set a real storefront ID
const storefrontId = 12;
// Set a product reference, owner ID, and design IDs from cartItem
const body = {
    ownerId: cartItem.properties._userId,
    item: {
        productReference: cartItem.originalProductId,
        designIds: cartItem.properties._stateId,
        sku: cartItem.sku,
        quantity: cartItem.quantity
    }
};
const project = _projectsApiClient.createWithSingleItem(storefrontId, null, JSON.stringify(body));
```

**PHP**

```php
// Set a real storefront ID
$storefrontId = 12;
// Set a product reference, owner ID, and design IDs from cartItem
$body = '{
    "ownerId": "' . $cartItem->properties->_userId . '",
    "item": {
        "productReference": "' . $cartItem->originalProductId . '",
        "designIds": "' . implode(',', $cartItem->properties->_stateId) . '",
        "sku": "' . $cartItem->sku . '",
        "quantity": ' . $cartItem->quantity . '
    }
}';
$project = $projectsApiClient->projectsCreate($storefrontId, null, $body);
```

### Reopening the editor with personalized data

To allow users to return to editing a previously personalized product, you can reinitialize the editor using the `cartItem` data. This is useful for scenarios where users want to make further changes after adding the product to the cart or reorder the product later.

Use the following initialization configuration for the editor:

```javascript
simpleEditor.init({
    configVersion: 2,
    input: {
      productId: cartItem.productId,            // ID of the base product
      productLinkId: cartItem.productLinkId,    // Link ID from the storefront
      productVersionId: cartItem.productVersionId, // Version ID of the product
      sku: cartItem.sku,                        // SKU of the product
      designId: cartItem.properties._stateId[0] // Use the first design ID from the state array
    },
    integration: {
      tenantId: <yourTenantId>,
      user: {
        id: cartItem.properties._userId,      // User ID from cartItem
        token: <userToken>                    // User token (retrieve or regenerate if needed)
      },
      storefrontId: <yourStorefrontId>,
      cchubApiGatewayUrl: "https://api.customerscanvashub.com"
    },
    // Additional settings or workflow content can be included here
});
```

Key Points:
- The `designId` is taken from the `_stateId` array in `cartItem.properties`. Use the first element if multiple designs exist.
- Ensure the `user.token` is valid. If the token has expired, generate a new one using the [`GET /api/storefront/v1/storefront-users/token`](https://customerscanvas.com/docs/hub/dev-center/api/storefront.md#tag/storefrontusers/GetToken) endpoint.
- This approach allows users to resume editing exactly where they left off, with all previous personalization intact.
