# Workflow: Embed the Creator widget — snippet, configuration, JS API, and order sync

- **Audience:** API integrator / LLM agent building a storefront that embeds the product designer
- **Base URL (snippet endpoint):** https://api.shirtplatform.com/webservices/rest
- **Auth:** HTTP Basic on `/auth`, then `x-auth-token` header on the snippet request
  (see [workflow-authenticate.md](workflow-authenticate.md))
- **Preconditions:**
  - You are authenticated as an authorized user (`ROLE_AUTHORIZED_USER`) and know the `{accountId}`
    and `{shopId}` of the shop (see [workflow-manage-account.md](workflow-manage-account.md)).
  - You know the `productId` (and optionally color/size) you want the widget to open with — resolve
    it via [workflow-manage-products.md](workflow-manage-products.md).
  - You control a host web page where you can inject HTML and define global JavaScript functions.
- **Outcome:** The Creator widget is embedded in your page, configured, and driven from your code.
  When a customer finishes a design and adds it, the widget persists the ordered products and hands
  their ids to your page via a callback, ready to be placed in your basket / checkout.

> **Legacy but functional.** The snippet-based embedding in this workflow is a **legacy** integration
> path. It remains fully functional and supported for existing integrations. It is **not** the only
> way to embed the widget — other integration methods exist and are documented separately through
> **shirtplatform support**. If you are starting a brand-new integration, confirm the preferred
> embedding method with support before committing to this path.

> **Where the pieces live.** The `creator/snippet` endpoint in Step 1 is part of this REST API (jee)
> and is a **thin proxy** to the Creator widget service (CWS). The widget itself — its preloader
> script, design engine, fonts and images, and the endpoints the widget posts orders to — is hosted
> by **CWS**, not by this REST API. After Step 1, the flow is **client-side**: you embed HTML and
> talk to the widget through its JavaScript API. The durable, in-depth description of that
> client-side surface is the
> [Creator widget JavaScript API reference](../reference/creator-widget-js-api.md).

---

## Steps

### Step 1 — Fetch the embedding snippet

- **Request:** `GET /accounts/{accountId}/shops/{shopId}/creator/snippet`
  ([reference](resource_Creator.html))
- **Query params (all optional; the important ones):**

  | Param | Meaning |
  |---|---|
  | `productId` | Product loaded when the widget starts |
  | `assignedColorId` / `assignedSizeId` | Color / size selected at start |
  | `amount` | Pre-filled quantity |
  | `sharedProductId` | UUID of a shared design to load at start (must be a valid UUID) |
  | `orderedProductId` | Reload an existing ordered product into the widget at start |
  | `editOrderedProductId` | Reload an existing ordered product **for editing**; it is removed once the edited item is re-added. The server appends a tamper-proof HMAC signature for this id |
  | `templateProductId` | Design template loaded at start |
  | `creatorDesignMode` | `SHOP` (customer personalisation, default) or `TEMPLATE` (design-template authoring) |
  | `width` / `height` | Widget content size as a CSS length — percent or pixels (default `100%`) |
  | `langId` / `countryId` | Localization, and the country used for pricing/tax |
  | `priceInfoLabelType` / `showPriceDetails` | Price label variant and whether to show the breakdown |
  | `addToBasketCallback` | Global JS function name called with the persisted ordered-product ids after add-to-basket |
  | `productChangeCallback` / `creatorStartCallback` | Global JS function names for the product-change and widget-ready events |

  **Callback params name a global JavaScript function.** The name must be **alphanumeric** — a
  non-alphanumeric name causes a runtime error (error 2155).

  > **Every query parameter is optional; most can be set later from JavaScript.** Only the path
  > params `accountId` and `shopId` are required (they route to the shop). Every query parameter has
  > a server-side default, so a bare `GET .../creator/snippet` is valid and you can embed a minimal
  > snippet and configure everything else at runtime. The start/design params (`productId`,
  > `assignedColorId`, `assignedSizeId`, `amount`, `sharedProductId`, `orderedProductId`,
  > `templateProductId`, `creatorDesignMode`, `priceInfoLabelType`) and the callbacks
  > (`addToBasketCallback`, `productChangeCallback`, `creatorStartCallback`) each have an equivalent
  > in the Creator JS API — set them via `config.start` / `config.notify` in
  > `creatorApiInitializeCallback(configure)` (Step 3) or through the `Creator` / `CurrentDesign`
  > methods (Step 4, e.g. `Creator.loadProduct(...)`, `loadSharedProduct(...)`,
  > `loadDesignedOrderedProduct(...)`, `CurrentDesign.changeAmount(...)`,
  > `Creator.setPriceInfoLabelType(...)`, `CurrentDesign.setAddToBasketCallback(...)`). A few
  > presentation/locale params — `langId`, `countryId`, `width`, `height`, `showPriceDetails` — are
  > snippet-time only and have no clean JS-API setter (the mount container is sized by the host via
  > CSS).

  > **Legacy `.server-one` routing suffix on the session token (transitional — being removed).**
  > The token returned by `/auth` can currently carry a routing suffix after a `.`, e.g.
  > `431c143a-…-8071537a15f3.server-one`. When you feed a session id to the Creator — the snippet's
  > `sid` / order-session id, or `orderSessionId` in the client-side order sync — use the **bare UUID
  > only** (strip everything from the `.` onward); the verbatim value makes the Creator fail with
  > **HTTP `500`**. The `x-auth-token` used on the jee REST API itself is unaffected. This suffix is a
  > leftover from an older multi-server setup and is being removed at source, after which no stripping
  > is needed — strip defensively until then.

- **Request example:**

    ```http
    GET /accounts/15/shops/86/creator/snippet?productId=1234&addToBasketCallback=onAddToBasket&creatorStartCallback=onCreatorReady HTTP/1.1
    x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647
    ```

- **Response 200:** the embedding payload — the **snippet HTML** to inject plus the **preloader
  script URL**. (The body is proxied verbatim from CWS; treat it as an opaque embedding payload
  rather than a modelled DTO.) The snippet is exactly two things: a **mount `<div>`** and an async
  **`<script>`** pointing at the CWS preloader with all Step-1 parameters packed into it.
- **Errors:** `400` — a supplied parameter is invalid (e.g. `sharedProductId` is not a valid UUID).
  The standard auth `401` applies as everywhere.
- **Idempotency:** safe/idempotent (read). Fetch a fresh snippet whenever the start parameters change.

### Step 2 — Embed the snippet in your page

Inject the returned HTML into a **sized** container — the widget renders into the mount div and sizes
itself to it, so the container must have a width and height.

```html
<div id="topLevelSystemManager" style="position:relative;width:100%;height:100%;"></div>
<script async="true" type="text/javascript"
        src="https://api.shirtplatform.com/creator/rest/accounts/15/shops/86/creator/preloader;data=..."></script>
```

- The mount div id is `topLevelSystemManager<widgetId>`. With the plain snippet the widget id is
  **empty**, so the JavaScript namespace is `shirtplatform.creator.api.*`.
- To run **several widgets** on one page, mount each with a distinct id (e.g. `"Main"` → div
  `topLevelSystemManagerMain`, namespace `shirtplatform.creatorMain.api.*`). The id parametrises
  everything so multiple widgets coexist.
- There are **no config data-attributes** on the div — configuration comes from the Step-1 query
  params (baked into the `;data=` payload) plus the optional client-side hook in Step 3.

### Step 3 — Configure at runtime (optional)

Beyond the Step-1 query params, define a global function named **`creatorApiInitializeCallback`**. The
widget calls it **before** it initializes, passing a `configure` function you invoke with a config
object.

```javascript
function creatorApiInitializeCallback(configure) {
  configure({
    start:    { productId: 1234, creatorDesignMode: "SHOP" },
    notify:   { addToBasketCallback: "onAddToBasket", creatorStartCallback: "onCreatorReady" },
    features: { enableMotives: true, enableProductChange: true },
    theme:    { backgroundColor: "#ffffff" },
    resourceBundleOverrides: [ { bundleName: "creator", overrides: [ { key: "...", value: "..." } ] } ]
  });
}
```

Config sections: `start` (starting product/design state), `notify` (callback function names),
`features` (feature toggles such as `enableMotives`, `enableProductChange`, `enableShareAndSave`),
`theme` (colors), and `resourceBundleOverrides` (i18n string overrides). See the
[JS API reference §2](../reference/creator-widget-js-api.md) for the full key list.

### Step 4 — Drive the widget through its JavaScript API

The API becomes usable **after** the widget fires `creatorStartCallback`. The API object is
`shirtplatform.creator<widgetId>.api.<Class>` (with an empty id, `shirtplatform.creator.api.<Class>`).

| Class | Purpose | Representative methods |
|---|---|---|
| `Creator` | Load products/designs, open categories, price options | `loadProduct(productId, assignedColorId)`, `loadSharedProduct(uuid)`, `loadDesignedOrderedProduct(orderedProductId, uuid)`, `loadDesignedProduct(base64Design)`, `setDefaultProduct(...)`, `openProductCategory(id)`, `configure(config)` |
| `CurrentDesign` | Manipulate the current design and trigger the order | `changeProduct(productId, assignedColorId)`, `changeAmount(assignedSizeId, amount)`, `addToBasket(assignedSizeId, amount)`, `addMotive(id)`, `addTextMotive(text, fontId)`, `getTotalPrice()`, `setAddToBasketCallback(fn)` |
| `DesignedSharedProduct` | Save the current design as a shareable product | `saveCurrentDesign(resultFn, faultFn)`, `setSharedDesignUrl(url)` |
| `DesignedTemplateProduct` | Author/store design templates (`TEMPLATE` mode) | `saveCurrentDesign(...)`, `storeCurrentDesign(...)`, `overrideSellingPriceValue(price)`, `enableAssignedColor(id)` |
| `Discounts` | Quantity-based discount rules in the price display | `setQuantityRules(map)`, `setExclusionList(skus)`, `setCurrentBasketQuantity(n)`, `setMaxDiscount(n)` |

`loadDesignedProduct` takes a **base64url-encoded `CreatorSE.Design`** JSON — the same design shape
used by the server-side design flow (see [workflow-create-design.md](workflow-create-design.md)).

### Step 5 — Receive the persisted ordered-product ids

When the customer adds a design (via the widget's add button or `CurrentDesign.addToBasket(...)`), the
widget builds the ordered products, **persists them**, and then calls your `addToBasketCallback` with
their ids. Reference those ids in your shop's own basket / checkout.

#### Getting the order / ordered-product ids

You do **not** get an "order id" handed back. After add-to-basket the widget persists the ordered
products to CWS (`POST .../creator/orderedProducts/storeAll`, keyed by the `orderSessionId`) and then
calls your global `addToBasketCallback` function.

```javascript
function onCreatorReady() {
  // API is ready — e.g. shirtplatform.creator.api.Creator.loadProduct(1234);
}

function onAddToBasket(orderedItemIds, orderedItems) {
  // orderedItemIds: the persisted ordered-product ids to add to your basket
  // orderedItems:   the matching item objects (product, color, size, amount, price)
}
```

- **`addToBasketCallback(orderedItemIds, orderedItems)`** — the first argument is an array of the
  newly-persisted **ordered-product ids**; reference these in your shop basket / checkout. The second
  argument is an array of the corresponding item objects (product, color, size, amount, price).
- **Setting the callback name** — either the `addToBasketCallback` query param on the Step-1 snippet
  endpoint, or via `creatorApiInitializeCallback(configure)` → `notify.addToBasketCallback` (Step 3).
  The name must be **alphanumeric**.
- **The whole order is the CWS `Order` keyed by your `orderSessionId`.** The `orderSessionId` you
  supplied when embedding the snippet is your handle to the entire order session; the widget hands you
  only the per-item ordered-product ids, never an order id.
- **A shared `orderSessionId` is the server-side "basket".** Reuse the **same** `orderSessionId`
  across successive add-to-basket actions and the items accumulate into **one** order, which is exactly
  the current session order documented in
  [workflow-session-order.md](workflow-session-order.md) — read it back server-side with
  `GET .../orders/session`. This is the platform's server-side basket path: there is deliberately no
  separate cart API. The **persistent shopper-facing basket** (guest vs. logged-in, a drawer/mini-cart,
  cross-device merge) is your storefront's responsibility — build it shop-side from the ordered-product
  ids you receive here, and materialize it into the order when the customer proceeds.
- **The widget persists the ordered products itself (via CWS) and hands you their ids.** It does
  **not** call this REST API's `orders/usingCreatorSE` (`ProductionOrderDeferredCse`) flow — that is a
  separate, server-side step you would drive yourself; the widget only produces the ids you consume in
  `addToBasketCallback`. See [workflow-manage-orders.md](workflow-manage-orders.md).
- Other events fired to host-page global functions: `productChangeCallback(productId)`,
  `priceChangeCallback(price)`, `designChangeCallback(designedProducts)`,
  `creatorFullScreenToggleCallback(state)`.
- There is **no `postMessage` bus** — the widget renders in-page (not an iframe) and communicates
  purely through named global callbacks and the `shirtplatform.creator*.api` object.

---

## Error handling and retries

- **Step 1 `400`** — a malformed parameter (most commonly a `sharedProductId` that is not a valid
  UUID). Fix the parameter and re-fetch.
- **The standard auth `401`** (invalid/expired token) applies to the Step-1 request as everywhere.
- **Client-side error 2155** — a callback query parameter (or `notify` config value) whose function
  name is not alphanumeric. Use plain alphanumeric global function names.
- **Re-fetching the snippet is safe** (it is a read). Change any start parameter and request a fresh
  snippet; there is nothing to clean up server-side.

## Not covered here

- **Other embedding methods.** This workflow documents the snippet-based path only. Other integration
  methods exist and are documented separately through **shirtplatform support** — this workflow does
  not describe or link them.
- **The CWS-internal order persistence** (how the widget stores ordered products) is not part of this
  REST API and is out of scope; you only consume the ids handed to `addToBasketCallback`.

## Related references

- [Creator widget JavaScript API reference](../reference/creator-widget-js-api.md) — the durable,
  in-depth description of the snippet, preloader, configuration channels, full JS API surface, and
  order-sync flow.
- [Embed the Creator Widget quick-start](guides.html#qs-creator-widget) — the human-oriented version
  of this workflow.

## Related workflows

- [workflow-authenticate.md](workflow-authenticate.md) — obtain the `x-auth-token` for Step 1.
- [workflow-manage-products.md](workflow-manage-products.md) — resolve the `productId` the widget
  opens with.
- [workflow-create-design.md](workflow-create-design.md) — the `CreatorSE.Design` payload shape that
  `Creator.loadDesignedProduct(...)` consumes.
- [workflow-manage-orders.md](workflow-manage-orders.md) — compose ordered-product ids into a
  downstream order, if your integration does that server-side.
- [workflow-session-order.md](workflow-session-order.md) — the current session order: the server-side
  order-in-progress a shared `orderSessionId` accumulates into (the platform's "basket" path), read
  back with `GET .../orders/session`.
