Quick Start Guide

Introduction

The Shirtplatform API is a REST service for browsing the product and motive catalog, managing shop resources, and submitting orders for print-on-demand fulfillment.

Environments
EnvironmentBase URLPurpose
Pilot https://pilot.shirtplatform.com/webservices/rest/ Integration testing — use this environment to develop and test your integration before going live.
Production https://api.shirtplatform.com/webservices/rest/ Live environment — real orders, real fulfillment.

Authentication

Private resources are secured with the HTTP Basic Auth mechanism. Use your account login and password to obtain a session token.

bash
curl -i --user userLogin:userPassword https://api.shirtplatform.com/webservices/rest/auth

If the credentials are correct, the server responds with 200 OK and returns a session token in the x-auth-token response header:

http
HTTP/1.1 200 OK
x-auth-token: f81d4fae-7dec-11d0-a765-00a0c91e6bf6
Set-Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6; Path=/context-root; Secure; HttpOnly

Save the token — include it as the x-auth-token header in every subsequent request. If the credentials are incorrect, the server returns 401 Unauthorized.

HTTP Session

The API supports two mechanisms for maintaining a session. The authentication response provides both — choose whichever suits your client:

MechanismRequest header to send
Token header x-auth-token: <token>
Cookie Cookie: SESSION=<token>
http — using token header
GET /webservices/rest/accounts/15/shops HTTP/1.1
Host: api.shirtplatform.com
x-auth-token: f81d4fae-7dec-11d0-a765-00a0c91e6bf6
http — using cookie
GET /webservices/rest/accounts/15/shops HTTP/1.1
Host: api.shirtplatform.com
Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6

To log out, send a DELETE to the Authentication resource. The server will invalidate the session and clear both the token and the cookie.

Authorization

The session token identifies the caller. Access to each resource is then controlled by the caller's assigned role:

User roles
Role Read Access Write Access
ROLE_AUTHORIZED_USER Shared Account resources Limited — Shared Shop resources
ROLE_SHOP_ADMIN Shared Account resources Full — Own Shop resources
ROLE_ACCOUNT_ADMIN Own Account resources Full — Own Account resources
Role hierarchy

ROLE_ACCOUNT_ADMIN > ROLE_SHOP_ADMIN > ROLE_AUTHORIZED_USER

Higher roles inherit all permissions of the roles below them.

Media Type

The API supports both XML and JSON. Set the appropriate request headers to choose a format:

FormatContent-TypeAccept
XML application/xml application/xml
JSON application/json application/json
JSON format notes

The API uses Jettison Mapped Convention for JSON serialization, which differs from standard Jackson JSON:

  • XML attributes become @fieldName keys (e.g. @rel, @href)
  • The top-level object is wrapped in a root key (wrapRootValue=true)
  • Single-element arrays may be serialized as a plain object instead of [...]

Error Responses

All error responses use a consistent JSON or XML envelope with two fields:

json
{
  "exception": {
    "message": "Shop not found",
    "internalErrorMessage": "Shop with ID 999 does not exist"
  }
}
xml
<exception>
  <message>Shop not found</message>
  <internalErrorMessage>
    Shop with ID 999 does not exist
  </internalErrorMessage>
</exception>
FieldDescription
message Human-readable summary of the error.
internalErrorMessage Additional detail — root cause, constraint name, or validation message. May be absent on some errors.
HTTP status codes
StatusWhen
400 Bad Request Request data failed validation (missing required field, invalid value).
401 Unauthorized No valid session token provided or the session has expired.
403 Forbidden Authenticated but not authorized to access this resource.
404 Not Found The requested resource does not exist or does not belong to your account.
405 Method Not Allowed HTTP method not supported on this endpoint.
409 Conflict Request conflicts with current state — duplicate entry, constraint violation, or invalid state transition.
500 Internal Server Error Unexpected server-side error. Contact support if this persists.

Linking & Resource Expansion

Why use linking

The API embeds fully qualified URLs for related resources using Atom links. This aids discoverability — new resources can be consumed by following embedded links without changes to client code. If an endpoint URL changes, the new URL is returned automatically.

Pagination is a practical example. Instead of constructing next-page URLs manually, clients follow the next link embedded in the response:

xml
<pagedData xmlns:atom="http://www.w3.org/2005/Atom">
  <shop>
    <id>223</id>
    <name>Love</name>
    <atom:link rel="self" href="https://api.shirtplatform.com/webservices/rest/accounts/16/shops/223"/>
    <atom:link rel="logoPreview" href="https://api.shirtplatform.com/webservices/rest/public/shops/223/logo"/>
  </shop>
  <shop>
    <id>224</id>
    <name>JGA</name>
    <atom:link rel="self" href="https://api.shirtplatform.com/webservices/rest/accounts/16/shops/224"/>
  </shop>
  <atom:link rel="next" href="https://api.shirtplatform.com/webservices/rest/accounts/16/shops?page=1&size=2" type="application/xml"/>
  <totalElements>46</totalElements>
</pagedData>
Links in JSON

In JSON (Jettison format), Atom link attributes appear with the @ prefix:

json
{
  "pagedData": {
    "shop": [
      {
        "id": 223,
        "name": "Love",
        "atom.link": [
          { "@rel": "self", "@href": "https://api.shirtplatform.com/webservices/rest/accounts/16/shops/223" },
          { "@rel": "logoPreview", "@href": "https://api.shirtplatform.com/webservices/rest/public/shops/223/logo" }
        ]
      }
    ],
    "atom.link": {
      "@rel": "next",
      "@href": "https://api.shirtplatform.com/webservices/rest/accounts/16/shops?page=1&size=2"
    },
    "totalElements": 46
  }
}
Link rel values

The following rel values appear across the API:

relDescription
Navigation
selfCanonical URL of this resource.
nextNext page in a paginated collection.
expandedExpanded variant of this resource (full object tree).
Account collections
shopsShops belonging to the account.
countriesCountries available on the account.
shippingModulesShipping modules configured on the account.
Shop collections
productsProducts available in the shop.
ordersOrders placed in the shop.
userMotivesUser-uploaded motives in the shop.
webhooksWebhook subscriptions for the shop.
orderCsvImportsCSV order import jobs for the shop.
Order relations
orderedProductsOrdered products within an order.
Product relations
productsExpandedExpanded product list.
assignedColorsColors assigned to a product.
assignedSizesSizes assigned to a product.
assignedViewsViews (sides/areas) assigned to a product.
Motive relations
motivesMotives associated with the resource.
localizationsLocalized content for the resource.
tagsTags assigned to a motive.
technologiesPrint technologies for a motive.
Media
imageSource image of the resource.
previewPreview image of the resource.
Shop configuration
propertiesConfiguration properties of a shop.
providersProviders for a shipping module.
configCreatorCreator configuration for a shop.
Pagination parameters

All collection endpoints that return pagedData support the following query parameters:

ParameterDefaultDescription
page 0 Zero-based page index. First page is 0.
size 10 Number of items per page.

The response includes totalElements (total number of items across all pages) and atom:link rel="next" / rel="prev" links for navigating between pages. Use the links instead of constructing URLs manually.

Resource expansion

Some resources have an expanded variant that returns related objects inline, reducing the number of API calls. Use the expanded endpoint when you know you will need the additional data.

http — basic vs expanded
GET /webservices/rest/accounts/15/shops/86/products/41782          → basic info + links
GET /webservices/rest/accounts/15/shops/86/products/expanded/41782 → full object tree

The basic response includes Atom links to related collections (assignedSizes, assignedColors, assignedViews, etc.). The expanded response embeds those collections inline.

Make an Order (Deferred)

The deferred order is the recommended way to place an order. In a single POST to orders/usingCreatorSE you submit the whole order — customer, shipping, and every item — as one CreatorSE.OrderDeferred payload. The platform validates it, stores it in one transaction, and hands it to the asynchronous order-preparing pipeline; the response carries the new order id.

Why the deferred order is preferred
  • One atomic call. The order header, customer, address, shipping and all items are persisted in a single transaction — it either all lands or none of it does. The incremental approach creates a bare order and then makes a separate call per item, which can fail partway and leave a half-built order to reconcile.
  • No HTTP-session coupling. The whole order travels in the request body, so nothing depends on a session-bound order or on threading an orderId through a build-then-commit sequence.
  • Any mix of item types in one payload. Custom designs, ready-made templates, and passthrough warehouse items ride together in three separate collections (designs, templates, passthroughItems).
  • Asynchronous processing. The endpoint returns 200 as soon as the payload is validated and persisted; design rendering and order composition run out of band, so your request does not block on that pipeline.
  • No manual finalization. Once the order-preparing pipeline has processed the submission, the order is automatically committed and placed into production — you do not call commitOrder or sendToProduction. (The incremental path requires both of those calls by hand after adding items.)
Prerequisites
  • Account and Shop (obtain accountId and shopId via the Auth and Shop resources)
  • Country — obtain via the Country resource (contains currency and VAT settings); it is required on the order
  • For each design item: a productId and its assignedColor.id / assignedSize.id from the Product resource, plus any motive.id placed on it
Submit the order

Make a single POST request. This example carries all three item collections — a custom design whose composition shows all three element types (a motive with a dynamic layer, a DDF production file, and a decoration), a template, and a passthrough item:

json — CreatorSE.OrderDeferred
POST /webservices/rest/accounts/15/shops/86/orders/usingCreatorSE HTTP/1.1
Accept: application/json
Content-Type: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647

{
  "creatorse_productionOrderDeferred": {
    "uniqueId": "ext-order-777",
    "financialStatus": "PAID",
    "customer": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@emailservice.com",
      "phone": "+44208269323",
      "billingAddress": {
        "street": "Golborne Road",
        "streetNo": "45",
        "city": "London",
        "zip": "WC2N 5DU",
        "countryCode": "UK"
      },
      "shippingAddress": {
        "street": "Golborne Road",
        "streetNo": "45",
        "city": "London",
        "zip": "WC2N 5DU",
        "countryCode": "UK"
      }
    },
    "country": {"id": 27, "code": "UK"},
    "orderShipping": {
      "title": "Standard shipping",
      "carrier": {"id": 418}
    },
    "designs": {
      "creatorse_design": [{
        "productId": 41559,
        "amount": 10,
        "assignedColor": {"id": 227227},
        "assignedSize": {"id": 133414},
        "sku": "TSHIRT-BLK-M",
        "compositions": {
          "creatorse_composition": [{
            "productArea": {"id": 88},
            "elements": [
              {
                "creatorse_designElementMotive": {
                  "motive": {"id": 12345},
                  "position": {"left": 10, "right": 10, "top": 10, "bottom": 10},
                  "layers": {
                    "creatorse_designElementLayer": [
                      {"name": "name-line", "text": "John", "rgbColor": "#FF0000"}
                    ]
                  }
                }
              },
              {
                "creatorse_designElementDdf": {
                  "previewResource": {"url": "https://cdn.example.com/preview/back.png"},
                  "productionResource": {"url": "https://cdn.example.com/print/back.pdf", "filename": "back.pdf"},
                  "position": {"left": 15, "right": 15, "top": 20, "bottom": 20}
                }
              },
              {
                "creatorse_designElementDecoration": {
                  "sku": "STICKER-WOVEN-001",
                  "placement": "chest-left"
                }
              }
            ]
          }]
        }
      }]
    },
    "templates": {
      "creatorse_designedTemplateProduct": [{
        "templateProductId": 90210,
        "amount": 2,
        "assignedColor": {"id": 227228},
        "assignedSize": {"id": 133415}
      }]
    },
    "passthroughItems": {
      "creatorse_passthroughItem": [{
        "sku": "SUP-MUG-78432",
        "name": "Ceramic mug 330 ml",
        "quantity": 2,
        "brand": "MugWorld",
        "color": "white",
        "referenceId": "PO-2026-001"
      }]
    }
  }
}

On success the endpoint returns 200 with a CreatorSE.OrderSubmited carrying the generated order id (and your uniqueId). A malformed envelope — a missing country or customer address, or a DesignElementDdf whose productionResource.filename has no file extension — is rejected with a real 400. An unknown or foreign accountId / shopId is 401.

What goes in each collection
CollectionItem typeUse for
designsCreatorSE.DesignCustom designs assembled from compositions and elements — and plain base products (a design with a productId and variant but empty compositions).
templatesCreatorSE.DesignedTemplateProductReady-made, designer-prepared template products, referenced by templateProductId (or templateProductSku).
passthroughItemsCreatorSE.PassthroughItemSimple warehouse products that pass through production untouched (no printing/decoration). Max 100 per order; never supplier-validated even when validateSuppliers is true.
Design element types

Each composition inside a design holds an elements array. The array is heterogeneous — every entry names its concrete element type as its key:

  • DesignElementMotive — places a motive (artwork/image) referenced by id from the library, or supplied inline via url / attachment. Its optional layers replace text or colour on named SVG layers of the motive.
  • DesignElementDdf — a production-ready design file: a previewResource and a productionResource (whose filename must include an extension).
  • DesignElementDecoration — a decoration (sticker/label) named by its sku and optional placement.

For how to build a design — product areas, positioning motives, and previewing before ordering — see Design with CreatorSE and the machine-readable workflow-create-design.md. The design object is identical to the one used per item in the incremental flow.

Further reading

How to Make an Order

Prerequisites
  • Account and Shop (obtain accountId and shopId via the Auth and Shop resources)
  • Product — choose from the catalog via the Product resource
  • Country — obtain via the Country resource (contains currency and VAT settings)
Step 1 — Create the order

Make a POST request to the Order resource with the customer and shipping details:

json
POST /webservices/rest/accounts/15/shops/86/orders HTTP/1.1
Accept: application/json
Content-Type: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647

{
  "productionOrder": {
    "country": {"id": 27},
    "orderShipping": {
      "title": "Shipping title",
      "carrier": {"id": 418}
    },
    "customer": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@emailservice.com",
      "phone": "+44208269323",
      "billingAddress": {
        "street": "Golborne Road",
        "streetNo": "45",
        "city": "London",
        "zip": "WC2N 5DU",
        "countryCode": "UK"
      },
      "shippingAddress": {
        "street": "Golborne Road",
        "streetNo": "45",
        "city": "London",
        "zip": "WC2N 5DU",
        "countryCode": "UK"
      }
    }
  }
}
Step 2 — Add an ordered product

Using the id from the created order, add a product with a design using the CreatorSE endpoint:

json
POST /webservices/rest/accounts/15/shops/86/orders/177/orderedProducts/usingCreatorSE HTTP/1.1
Accept: application/json
Content-Type: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647

{
  "creatorse_design": {
    "productId": 41559,
    "amount": 10,
    "assignedColor": {"id": 227227},
    "assignedSize": {"id": 133414},
    "compositions": {
      "creatorse_composition": [{
        "productArea": {
          "assignedView": {
            "view": {"position": "FRONT"}
          }
        },
        "elements": {
          "creatorse_element": [{
            "motive": {"id": 12345}
          }]
        }
      }]
    }
  }
}

This path is not auto-finalized. Unlike the deferred order — which the pipeline commits and sends to production for you — an incrementally built order stays a draft until you finalize it yourself with the two calls below.

Step 3 — Commit the order

Once every item has been added, commit the order with a PUT commitOrder request to the Order resource. This stamps the order's financial status (financialStatus query param, default PENDING); it does not yet start production. Returns 204.

http
PUT /webservices/rest/accounts/15/shops/86/orders/177/commitOrder?financialStatus=PAID HTTP/1.1
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647
Step 4 — Send the order to production

Finally, hand the committed order to the production and fulfilment pipeline with a PUT sendToProduction request. No body is needed — the hand-off is derived from data already on the order. Returns 204.

http
PUT /webservices/rest/accounts/15/shops/86/orders/177/sendToProduction HTTP/1.1
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647

Order Statuses

Orders have two independent status fields: financialStatus (payment) and fulfilmentStatus (production/shipping). Both appear on the ProductionOrder object returned by the Order resource.

Financial status

Tracks the payment lifecycle of an order.

ValueDescriptionNotes
PENDINGPayment not yet confirmedInitial state on order creation
AUTHORIZEDPayment authorized but not yet captured
PARTIALLY_PAIDPartial payment received
PAIDFull payment confirmedTriggers the production pipeline
PARTIALLY_REFUNDEDPartial refund issued
REFUNDEDFull refund issued
VOIDEDTransaction voided

Note: transitions are forward-only — once an order reaches PAID it cannot return to PENDING.

Fulfilment status

Tracks the production and shipping lifecycle of an order.

ValueDescriptionNotes
WAITING_FOR_RESOURCESProcessing high-quality motive filesSet automatically after PAID
PREPARED_TO_PRODUCEAll resources ready, awaiting production pickup
NOT_EDITABLEOrder picked up by production — locked for editing
FINISHEDOrder shippedIrreversible. Triggers orders/fulfilled webhook
RECLAMATIONReclamation request received
CANCELLATION_WAITINGCancellation requested, awaiting confirmation
CANCELLEDOrder cancelledIrreversible. Triggers orders/cancelled webhook
ERROR_HQ_MOTIVESFailed to process high-quality motive filesContact support
Lifecycle overview

The diagram below shows the standard order lifecycle and the cancellation flow:

order lifecycle
                        financialStatus                              fulfilmentStatus
                        ───────────────                              ────────────────

                        PENDING                                      WAITING_FOR_RESOURCES
                           │                                                │
                           ▼                                                ▼
                        AUTHORIZED                                   PREPARED_TO_PRODUCE
                           │                                                │
                           ▼                                                ▼
                         PAID ─────────────────────────────────►     NOT_EDITABLE
                                                                        │           │
                                                                        ▼           ▼
                                                                    FINISHED   CANCELLATION_WAITING
                                                                                    │
                                                                                    ▼
                                                                               CANCELLED


Happy path:   PENDING ──► PAID ──► WAITING_FOR_RESOURCES ──► PREPARED_TO_PRODUCE ──► NOT_EDITABLE ──► FINISHED

Cancellation: ... ──► NOT_EDITABLE ──► CANCELLATION_WAITING ──► CANCELLED
Webhook correlation

Status transitions fire webhook events to subscribed endpoints. See the Webhooks section for setup details.

StatusWebhook event
FINISHEDorders/fulfilled
CANCELLEDorders/cancelled
Any status changeorders/updated
Polling vs. webhooks

While you can poll the Order resource and check financialStatus / fulfilmentStatus, we strongly recommend using webhooks instead. Webhooks deliver status changes in real time, reduce unnecessary API calls, and are not subject to rate limiting that affects high-frequency polling.

Design with CreatorSE

CreatorSE (Creator Server Engine) is a server-side design tool for placing motives on products. Use it when creating ordered products via the usingCreatorSE endpoint on the OrderedProduct resource.

Layout details

By default, CreatorSE places the first motive on the Product Area's hotspot if one is defined. You can override the position and size of a motive using the Position data type.

  • To control horizontal position and width: set both left and right
  • To control vertical position and height: set both top and bottom
  • Default unit is millimeters; percentage of area width/height is also supported

Layout details

Position example

The following example places a motive with a 10 mm margin on all sides — meaning the motive fills the print area with a 10 mm border on each edge:

json — creatorse_element with explicit position
{
  "creatorse_element": {
    "motive": {"id": 12345},
    "position": {
      "left": 10,
      "right": 10,
      "top": 10,
      "bottom": 10
    }
  }
}

To position using percentages instead of millimeters, append % to the value (e.g. "left": "10%"). To center the motive on the print area, use "horizontalCenter": 0 and/or "verticalCenter": 0 instead.

Embed the Creator Widget

The Creator widget is Shirtplatform's in-browser product designer. A shop embeds it so end customers can personalise a product — pick colors and sizes, place motives and text — and add the finished design to the basket. The widget renders directly in your page (same DOM, not an iframe) and is driven from your page through a JavaScript API.

Step 1: Fetch the embedding snippet

Call the Creator resource to obtain the snippet. All start-up state (the starting product, colors, callbacks, feature toggles, theme) is passed as query parameters and baked into the returned snippet.

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

Common query parameters (see the resource reference for the full list):

ParameterPurpose
productIdProduct loaded when the widget starts
assignedColorId / assignedSizeIdColor / size selected at start
amountPre-filled quantity
sharedProductIdUUID of a shared design to load at start
orderedProductId / editOrderedProductIdReload an existing ordered product (the edit* form re-opens it for editing and removes it when re-added)
templateProductIdDesign template loaded at start
creatorDesignModeSHOP (customer personalisation, default) or TEMPLATE (design-template authoring)
width / heightWidget content size as a CSS length (percent or pixels)
addToBasketCallbackGlobal JS function name called with the persisted ordered-product ids after the customer adds an item
productChangeCallback / creatorStartCallbackGlobal JS function names for the product-change and widget-ready events

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

Step 2: Embed the snippet

The returned payload contains the HTML to inject and the preloader script URL. The snippet is exactly two things: a mount <div> the widget renders into, and an async <script> that loads the preloader with all start-up parameters packed into it. Inject the HTML into a sized container on your page — the widget sizes itself to the mount element, so give it width and height.

html — the embedded snippet
<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.*).

Step 3: Configure at runtime (optional)

Beyond the query parameters, you can configure the widget client-side before it initializes. Define a global function named creatorApiInitializeCallback; the widget calls it with a configure function you invoke with a config object.

javascript — pre-init configuration hook
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: "..." } ] } ]
  });
}

The config object has five sections: start (starting product/design state), notify (callback function names), features (feature toggles), theme (colors), and resourceBundleOverrides (i18n string overrides).

Step 4: Drive the widget through its JavaScript API

Once the widget fires creatorStartCallback, the API object is available at shirtplatform.creator<widgetId>.api.<Class>. The main classes:

ClassPurposeKey methods
Creator Load products and designs, open categories, set price/label options loadProduct(productId, assignedColorId), loadSharedProduct(uuid), loadDesignedOrderedProduct(orderedProductId, uuid), loadDesignedProduct(base64Design), setDefaultProduct(...), openProductCategory(id), configure(config)
CurrentDesign Manipulate the design in view 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 and store design templates (in TEMPLATE mode) saveCurrentDesign(...), storeCurrentDesign(...), overrideSellingPriceValue(price), enableAssignedColor(id)
Discounts Apply quantity-based discount rules in the widget's price display setQuantityRules(map), setExclusionList(skus), setCurrentBasketQuantity(n), setMaxDiscount(n)
Step 5: Receive the ordered items

When the customer adds a design, the widget builds the ordered products, persists them, and calls your addToBasketCallback with the resulting ids. Reference those ids in your shop's basket / checkout.

javascript — host callbacks
function onCreatorReady() {
  // API is now usable, e.g. shirtplatform.creator.api.Creator.loadProduct(1234);
}

function onAddToBasket(orderedItemIds, orderedItems) {
  // orderedItemIds: the persisted ordered-product ids to add to your basket
}

Other events the widget fires to host-page global functions: productChangeCallback(productId), priceChangeCallback(price), designChangeCallback(designedProducts), and creatorFullScreenToggleCallback(state). There is no postMessage bus — the widget communicates purely through these named global callbacks and the shirtplatform.creator*.api object.

Product Catalog Guide

Overview

A Product is a configurable item template (e.g. "Gildan 5000 T-shirt"). It defines available colors, sizes, views (front/back), and print areas. Products belong to a Shop and are always accessed under the accountId + shopId path.

When placing an order, you reference the product's assignedColor.id and assignedSize.id — not the raw color or size IDs. These assigned IDs come from the product's own configuration and are specific to that product.

Step 1 — List products

Use a GET request to the Product resource to browse the catalog. The endpoint supports pagination via page and size query parameters:

http
GET /webservices/rest/accounts/15/shops/86/products?page=0&size=10 HTTP/1.1
Accept: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647

The response contains a paged list (PagedData) with a product array. Atom atom.link entries provide navigation to the next and previous pages.

Step 2 — Get product detail (expanded)

Use GET .../products/expanded/{productId} to retrieve the product with all sub-resources inlined. This is the preferred call when you need to pick a color and size for an order, because it returns colors, sizes, SKUs, print areas, prices, and localizations in a single response:

http
GET /webservices/rest/accounts/15/shops/86/products/expanded/41559 HTTP/1.1
Accept: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647

The response contains a product object with nested assignedColors, assignedSizes, and productSkus collections, among other sub-resources.

Step 3 — Identify SKU for an order

A ProductSku represents the intersection of an assignedColor and an assignedSize for a product. Each SKU has a stockId — the ID of the underlying stock item (the physical blank). Here is what a typical SKU looks like in the expanded product response:

json
{
  "productSku": {
    "id": 98701,
    "stockId": 4201,
    "available": true,
    "assignedColor": {"id": 227227},
    "assignedSize": {"id": 133414}
  }
}

When using CreatorSE to place an order, you need productId, assignedColor.id, and assignedSize.id from the expanded product response. See the How to Make an Order guide for the full ordering workflow.

Shop Motive Catalog

The shop motive catalog is the collection of artwork managed by the integrator for a given shop. Motives in this catalog are displayed in the Creator tool so that customers can pick a design, and they are referenced by ID when placing orders via CreatorSE. Each motive belongs to a Shop, has a type, and can be enriched with print technology constraints, localizations, tags, and categories.

For integrator-uploaded bitmap artwork the type is HIGH_RESOLUTION_BITMAP. This is distinct from the User Motive Library, which is a private per-customer artwork store — see the comparison at the end of this section.

Step 1 — Create the motive record

Make a POST request to the Motive resource with a minimal MotivePrime body containing the name and type. The response contains the new motive's id.

http
POST /webservices/rest/accounts/15/shops/86/motives HTTP/1.1
Accept: application/json
Content-Type: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647

{"motive": {"name": "My design", "type": "HIGH_RESOLUTION_BITMAP"}}
Step 2 — Upload the bitmap image

Make a POST request to .../motives/{motiveId}/bitmap as multipart/form-data with the image file attached. Supported formats: JPEG, PNG.

bash
curl -X POST \
  "https://pilot.shirtplatform.com/webservices/rest/accounts/15/shops/86/motives/67890/bitmap" \
  -H "x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647" \
  -F "file=@/path/to/design.png"
Step 3 — Assign a print technology

Make a POST request to .../motives/{motiveId}/technologies with a MotivePrintTechnologyPrime body referencing the print technology ID. The print technology ID comes from the product's assigned print technology configuration — use the same technology that the target product expects.

http
POST /webservices/rest/accounts/15/shops/86/motives/67890/technologies HTTP/1.1
Accept: application/json
Content-Type: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647

{
  "motivePrintTechnology": {
    "printTechnology": {"id": 3}
  }
}
Step 4 — Use the motive in an order

The motive is now ready to be referenced in a CreatorSE order by its id. See the Design with CreatorSE guide for full layout details.

json — creatorse_element referencing the uploaded motive
{
  "creatorse_element": {
    "motive": {"id": 67890}
  }
}
Additional management endpoints
  • GET .../motives — list all motives in the shop (paginated)
  • GET .../motives/{motiveId} — get motive detail
  • PUT .../motives/{motiveId} — update motive name or type
  • DELETE .../motives/{motiveId} — delete motive
  • {motiveId}/localizations — manage translated name/description
  • {motiveId}/tags/{tagId} (PUT) — assign a tag
  • {motiveId}/assignedCategories (POST) — assign a category
Shop Motive Catalog vs. User Motive Library
Shop Motive CatalogUser Motive Library
Managed by Integrator / shop operator End customer
Scope Shared across all customers in the shop Private per customer session or account
Visible in Creator Yes — customers browse and pick from this catalog Yes — customers see their own uploaded artwork
API resource Motive UserMotive
Lifetime Permanent — until explicitly deleted Session (default) or permanent (with Customer Key)

User Motive Library

The User Motive Library is a private artwork store for each end customer. Customers upload their own images here and reuse them across their orders. This is distinct from the Shop Motive Catalog, which is managed by the integrator and shared across all customers in the shop.

There are two library types:

TypeLifetimeAccess
Session library Until x-auth-token expires Default — no extra setup required
Permanent library Indefinite Requires a Customer Key at login
Using the permanent library
  1. Obtain a Customer Key by making a GET uuid request to the public Nonce resource (no authentication required).
  2. Log in with a POST to the Authentication resource, passing your Customer Key in the x-customer-key request header. Using the same key always grants access to the same permanent library.
Uploading a motive
  • HTML / form-based clients: use the createFromMultipartForm POST method on the UserMotive resource
  • API clients: use the createFromData POST method, providing an image URL or base64-encoded file content

The returned MotivePrime contains the motive id, which is then used in CreatorSE orders exactly like any catalog motive.

Filters

Shirtplatform uses a stored filter system for querying list endpoints. Instead of passing filter criteria as query string parameters, you first create a filter object on the server and then reference it by its filterId on any paginated endpoint. This two-step approach lets you build complex queries with multiple conditions, nested sub-filters, and sort orders — all reusable across requests.

Top-level filter types

These filter types are used directly as the filterId target on paginated list endpoints. Use the root element name as the JSON root key when creating the filter.

Filter root elementData typeExample endpoint
productFilterFilter.ProductGET /accounts/{accountId}/shops/{shopId}/products
productionOrderFilterFilter.OrderGET /accounts/{accountId}/shops/{shopId}/orders
motiveFilterFilter.MotiveGET /accounts/{accountId}/shops/{shopId}/creator/motives
sharedProductFilterFilter.SharedProductGET /accounts/{accountId}/shops/{shopId}/sharedProducts
orderedProductFilterFilter.OrderedProductGET /accounts/{accountId}/shops/{shopId}/orders/{orderId}/orderedProducts
orderedProductCustomAttributeFilterFilter.OrderedProductCustomAttributeGET /accounts/{accountId}/shops/{shopId}/orders/{orderId}/orderedProducts/{productId}/customAttributes
shopFilterFilter.ShopGET /accounts/{accountId}/shops
webhookFilterFilter.WebhookGET /accounts/{accountId}/shops/{shopId}/webhooks
countryFilterFilter.CountryGET /accounts/{accountId}/countries
productionOrderCsvImportFilterFilter.OrderCsvImportGET /accounts/{accountId}/shops/{shopId}/orderCsvImport
Sub-entity filter types

These filter types are used as nested sub-filters inside top-level filters (e.g. productLocalizedFilter inside productFilter). They cannot be used directly as a filterId on endpoints.

Filter root elementData typeDescription
productLocalizedFilterFilter.ProductLocalizedLocalized product attributes (e.g. translated name)
productAssignedToCategoryFilterFilter.ProductAssignedToCategoryProduct-to-category assignments
productSkuFilterFilter.ProductSkuProduct SKU entries
productColorFilterFilter.ProductColorProduct color definitions
productSizeFilterFilter.ProductSizeProduct size definitions
productViewFilterFilter.ProductViewPrintable view definitions of a product
productPriceFilterFilter.ProductPriceProduct price entries (by country, color, size)
assignedProductColorFilterFilter.ProductAssignedColorColor variants assigned to a product
assignedProductSizeFilterFilter.ProductAssignedSizeSize variants assigned to a product
assignedProductViewFilterFilter.ProductAssignedViewPrintable view assignments to a product
productViewColorDetailFilterFilter.ProductAssignedViewColorColor assignments per product view
assignedProductStickerFilterFilter.ProductAssignedStickerSticker assignments to product views
assignedPrintTechnologyFilterFilter.ProductAssignedPrintTechnologyPrint technology assignments to products
assignedAttributeListItemFilterFilter.ProductAssignedAttributeListItemAttribute list item assignments to products
motiveLocalizedFilterFilter.MotiveLocalizedLocalized motive attributes (e.g. translated name)
motiveAssignedToCategoryFilterFilter.MotiveAssignedToCategoryMotive-to-category assignments
motivePrintTechnologyFilterFilter.MotivePrintTechnologyPrint technology assignments to motives
tagFilterFilter.TagTag resources
shopPropertyFilterFilter.ShopPropertyShop configuration property entries
Step 1: Create a filter

Send a POST request to /rest/filters with a JSON body describing your filter criteria. The root element name determines which entity the filter targets (e.g., productFilter, productionOrderFilter, motiveFilter). The response includes a filterId that you can use in subsequent requests.

http
POST /rest/filters HTTP/1.1
Content-Type: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647
json — request body
{
  "productFilter": {
    "expressionSimple": {
      "value": "false",
      "op": "=",
      "property": "deleted"
    },
    "order": {
      "direction": "asc",
      "property": "name"
    }
  }
}
json — response (abbreviated)
{
  "productFilter": {
    "filterId": "42",
    "expressionSimple": {
      "value": "false",
      "op": "=",
      "property": "deleted"
    },
    "order": {
      "direction": "asc",
      "property": "name"
    }
  }
}

If an identical filter already exists for your user (matched by content digest), the existing filter is returned instead of creating a duplicate.

Expression types

The criteria list in a filter body accepts six expression types. All expressions within the same filter are combined with AND logic by default.

TypeXML element nameFieldsPurpose
Simple expressionSimple property, op, value Compare a single property against a value using an operator (=, !=, like, etc.)
Between betweenExpression property, minValue, maxValue Match values within an inclusive range (dates, numbers)
Contain (IN) expressionContain property, negation, list Match a property against a list of values (SQL IN / NOT IN)
Is Null expressionIsNull property Match records where the property value is null
Disjunction (OR) expressionDisjunction expressions (nested list) Combine nested expressions with OR logic
Conjunction (AND) expressionConjuction expressions (nested list) Explicitly combine nested expressions with AND logic
Operators for expressionSimple
OperatorDescriptionExample value
=Equal"value": "false", "op": "=", "property": "deleted"
!=Not equal"value": "CANCELLED", "op": "!=", "property": "status"
likePattern match (case-sensitive, use % as wildcard)"value": "%shirt%", "op": "like", "property": "name"
ilikePattern match (case-insensitive)"value": "%shirt%", "op": "ilike", "property": "name"
<Less than"value": "100", "op": "<", "property": "id"
>Greater than"value": "100", "op": ">", "property": "id"
<=Less than or equal"value": "50", "op": "<=", "property": "price"
>=Greater than or equal"value": "10", "op": ">=", "property": "price"

All values are strings. The server automatically converts them to the target field's Java type (Boolean, Integer, Date, Enum, etc.).

Note on date format: Date values in filter expressions must use yyyy/MM/dd HH:mm:ss (24-hour clock). This is different from the ISO 8601 format used in API responses — do not use the response timestamp format directly in filter values.

Advanced examples

Date range with betweenExpression — filter orders created in Q1 2026. Date format is yyyy/MM/dd HH:mm:ss.

json — betweenExpression
{
  "productionOrderFilter": {
    "betweenExpression": {
      "property": "createdDate",
      "minValue": "2026/01/01 00:00:00",
      "maxValue": "2026/03/31 23:59:59"
    }
  }
}

IN-list with expressionContain — fetch specific products by ID.

json — expressionContain (IN list)
{
  "productFilter": {
    "expressionContain": {
      "property": "id",
      "negation": false,
      "list": {
        "String": ["101", "102", "103"]
      }
    }
  }
}

Nested sub-filter — search products by localized name. The productLocalizedFilter joins the localized data and applies a case-insensitive pattern match.

json — nested sub-filter
{
  "productFilter": {
    "expressionSimple": {
      "value": "false",
      "op": "=",
      "property": "deleted"
    },
    "productLocalizedFilter": {
      "expressionSimple": {
        "value": "%shirt%",
        "op": "ilike",
        "property": "name"
      }
    }
  }
}

OR logic with expressionDisjunction — match motives of type BITMAP or VECTOR.

json — expressionDisjunction (OR)
{
  "motiveFilter": {
    "expressionDisjunction": {
      "expressionSimple": [
        { "value": "BITMAP", "op": "=", "property": "type" },
        { "value": "VECTOR", "op": "=", "property": "type" }
      ]
    }
  }
}
Step 2: Use the filter

Pass the filterId as a query parameter to any paginated list endpoint. The server loads the stored filter and applies it to the query.

http
GET /rest/accounts/15/shops/86/products?filterId=42&page=0&size=20 HTTP/1.1
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647
Error handling
ScenarioBehavior
filterId is empty or not providedThe endpoint uses its own default filter (typically deleted = false with default ordering)
filterId is provided but does not existError code -104 FilterNotFoundException
Invalid property name in a filter expressionSqlValidationException at query execution time

Webhooks

Webhook subscriptions let your app receive notifications when specific events occur in your shops — without polling. For example, your app can react immediately when a customer places an order or when Shirtplatform fulfills an order.

Supported events
DomainTopicPayload type
Orderorders/updatedProductionOrderExpanded
orders/readyForProductionProductionOrderExpanded
orders/fulfilledProductionOrderExpanded
orders/acknowledgedProductionOrderExpanded
orders/failedProductionOrderProcessingError
orders/splittedProductionOrderSplitted
orders/cancelledProductionOrderExpanded
Webhook anatomy

Each notification is an HTTP POST to your endpoint URL with a JSON or XML payload and context headers:

http headers
x-shirtplatform-topic: orders/updated
x-shirtplatform-hmac-sha256: XWmrwMey6OsLMeiZKwP4FppHH3cmAiiJJAweH5Jo4bM=
Payload example

The request body is a JSON (or XML) representation of the event's payload type. Below is an abbreviated example for orders/fulfilled:

json — orders/fulfilled payload (abbreviated)
{
  "productionOrderExpanded": {
    "id": 177,
    "uniqueId": "SHOP-ORDER-001",
    "created": "2024-06-01T10:23:00+02:00",
    "financialStatus": "PAID",
    "fulfilmentStatus": "FULFILLED",
    "customer": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@example-shop.com"
    },
    "orderedProducts": {
      "designedOrderedProduct": [
        {
          "id": 5512,
          "amount": 2,
          "atom.link": [
            { "@rel": "self", "@href": "https://api.shirtplatform.com/webservices/rest/accounts/15/shops/86/orders/177/orderedProducts/5512" }
          ]
        }
      ]
    },
    "fulfillments": {
      "orderFulfillmentExpanded": [
        {
          "id": 88,
          "trackingNumber": "TRACK123456",
          "trackingUrl": "https://carrier.example.com/track?nr=TRACK123456"
        }
      ]
    },
    "atom.link": [
      { "@rel": "self", "@href": "https://api.shirtplatform.com/webservices/rest/accounts/15/shops/86/orders/177" }
    ]
  }
}
Configuring a webhook

Send a POST request to the Webhook resource with your endpoint URL and the events you want to subscribe to.

Responding to webhooks

Your endpoint must return 200 OK. Any other response (including 3xx redirects) is treated as a failure. Shirtplatform retries every 60 minutes for up to 48 hours.

Verifying webhooks

Each request includes an x-shirtplatform-hmac-sha256 header. Compute the HMAC-SHA256 of the request body using your webhook secret and compare it to the header value:

java
private String computeHmacSignature(String secret, byte[] requestBody) throws Exception {
    final Mac sha256Hmac = Mac.getInstance("HmacSHA256");
    String authToken = DigestUtils.sha256Hex(secret);
    final SecretKeySpec secretKey = new SecretKeySpec(authToken.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
    sha256Hmac.init(secretKey);
    return Base64.encodeBase64String(sha256Hmac.doFinal(requestBody)).trim();
}

CSV Import

You can upload a CSV file containing multiple orders for batch processing via the OrderCsvImport resource.

File format
  • Default: European CSV/DSV — decimal separator ,, value separator ;
  • USA/UK format: decimal separator ., value separator , — set the separator (and optionally quote) query parameter
  • Encoding: UTF-8 by default; BOM header is recognized; other encodings can be specified — see Java encoding docs

An example European CSV file can be downloaded here.

Column reference

Columns must appear in this exact order. All 54 columns are required as headers; unused fields may be left empty.

#Column nameDescription
Order
1order group idGroups rows into the same order. Rows with the same value become items in one order.
2uniqueIdYour external order identifier.
3countryIdShirtplatform country ID (determines currency and VAT).
Shipping
4shipping carrier IdShirtplatform carrier ID.
5orderShippingCodeShipping method code.
6orderShippingTitleShipping method display title.
7orderShippingPriceShipping price.
8orderShippingCodPriceCash-on-delivery surcharge.
9orderShippingOrderValueOrder value used for shipping cost calculation.
Customer
10customer first name
11customer last name
12customer email
13customer phone
Billing address
14customer billing address first name
15customer billing address last name
16customer billing address nameCompany name.
17customer billing address street
18customer billing address street no
19customer billing address city
20customer billing address country name
21customer billing address country codeISO 3166-1 alpha-2 (e.g. DE).
22customer billing address zip
23customer billing address state name
24customer billing address state code
25customer billing address phone
26customer billing address email
Shipping address
27customer shipping address first name
28customer shipping address last name
29customer shipping address nameCompany name.
30customer shipping address street
31customer shipping address street no
32customer shipping address city
33customer shipping address country name
34customer shipping address country codeISO 3166-1 alpha-2 (e.g. DE).
35customer shipping address zip
36customer shipping address state name
37customer shipping address state code
38customer shipping address phone
39customer shipping address email
Design
40design group idGroups rows into the same design (multiple motives, different sides).
41design product idShirtplatform product ID.
42design product skuProduct SKU (alternative to product ID).
43design amountQuantity.
44composition group idGroups rows into the same composition (multiple motives on the same area).
45product area idShirtplatform product area ID.
46product area nameProduct area name (alternative to area ID).
47element motive idShirtplatform motive ID.
48element motive urlURL of a bitmap motive to upload on-the-fly.
Motive position
49position leftDistance from left edge of print area (mm or %).
50position rightDistance from right edge of print area (mm or %).
51position topDistance from top edge of print area (mm or %).
52position bottomDistance from bottom edge of print area (mm or %).
53position horizontal centerCenter horizontally on the print area (true/false).
54position vertical centerCenter vertically on the print area (true/false).
Group ID fields

Most fields correspond to the ProductionOrderDeferred data type. Three special fields control how rows are grouped into orders and designs:

FieldPurpose
order group id Rows with the same value are imported as items in the same order
design group id Rows with the same value are imported as composition items in the same design (multiple motives, different sides/areas)
composition group id Rows with the same value are imported as element items in the same composition (multiple motives on the same side/area)