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
| Environment | Base URL | Purpose |
|---|---|---|
| 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.
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/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:
| Mechanism | Request header to send |
|---|---|
| Token header | x-auth-token: <token> |
| Cookie | Cookie: SESSION=<token> |
GET /webservices/rest/accounts/15/shops HTTP/1.1
Host: api.shirtplatform.com
x-auth-token: f81d4fae-7dec-11d0-a765-00a0c91e6bf6
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.
Media Type
The API supports both XML and JSON. Set the appropriate request headers to choose a format:
| Format | Content-Type | Accept |
|---|---|---|
| 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
@fieldNamekeys (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:
{
"exception": {
"message": "Shop not found",
"internalErrorMessage": "Shop with ID 999 does not exist"
}
}
<exception>
<message>Shop not found</message>
<internalErrorMessage>
Shop with ID 999 does not exist
</internalErrorMessage>
</exception>
| Field | Description |
|---|---|
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
| Status | When |
|---|---|
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:
<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:
{
"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:
| rel | Description |
|---|---|
| Navigation | |
self | Canonical URL of this resource. |
next | Next page in a paginated collection. |
expanded | Expanded variant of this resource (full object tree). |
| Account collections | |
shops | Shops belonging to the account. |
countries | Countries available on the account. |
shippingModules | Shipping modules configured on the account. |
| Shop collections | |
products | Products available in the shop. |
orders | Orders placed in the shop. |
userMotives | User-uploaded motives in the shop. |
webhooks | Webhook subscriptions for the shop. |
orderCsvImports | CSV order import jobs for the shop. |
| Order relations | |
orderedProducts | Ordered products within an order. |
| Product relations | |
productsExpanded | Expanded product list. |
assignedColors | Colors assigned to a product. |
assignedSizes | Sizes assigned to a product. |
assignedViews | Views (sides/areas) assigned to a product. |
| Motive relations | |
motives | Motives associated with the resource. |
localizations | Localized content for the resource. |
tags | Tags assigned to a motive. |
technologies | Print technologies for a motive. |
| Media | |
image | Source image of the resource. |
preview | Preview image of the resource. |
| Shop configuration | |
properties | Configuration properties of a shop. |
providers | Providers for a shipping module. |
configCreator | Creator configuration for a shop. |
Pagination parameters
All collection endpoints that return pagedData support the following query parameters:
| Parameter | Default | Description |
|---|---|---|
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.
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.
How to Make an Order
Prerequisites
- Account and Shop (obtain
accountIdandshopIdvia 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:
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:
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}
}]
}
}]
}
}
}
Step 3 — Commit the order
Push the order to the production pipeline with a PUT commitOrder request to the Order resource.
PUT /webservices/rest/accounts/15/shops/86/orders/177/commitOrder 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.
| Value | Description | Notes |
|---|---|---|
PENDING | Payment not yet confirmed | Initial state on order creation |
AUTHORIZED | Payment authorized but not yet captured | |
PARTIALLY_PAID | Partial payment received | |
PAID | Full payment confirmed | Triggers the production pipeline |
PARTIALLY_REFUNDED | Partial refund issued | |
REFUNDED | Full refund issued | |
VOIDED | Transaction 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.
| Value | Description | Notes |
|---|---|---|
WAITING_FOR_RESOURCES | Processing high-quality motive files | Set automatically after PAID |
PREPARED_TO_PRODUCE | All resources ready, awaiting production pickup | |
NOT_EDITABLE | Order picked up by production — locked for editing | |
FINISHED | Order shipped | Irreversible. Triggers orders/fulfilled webhook |
RECLAMATION | Reclamation request received | |
CANCELLATION_WAITING | Cancellation requested, awaiting confirmation | |
CANCELLED | Order cancelled | Irreversible. Triggers orders/cancelled webhook |
ERROR_HQ_MOTIVES | Failed to process high-quality motive files | Contact support |
Lifecycle overview
The diagram below shows the standard order lifecycle and the cancellation flow:
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.
| Status | Webhook event |
|---|---|
FINISHED | orders/fulfilled |
CANCELLED | orders/cancelled |
| Any status change | orders/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
leftandright - To control vertical position and height: set both
topandbottom - Default unit is millimeters; percentage of area width/height is also supported

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:
{
"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.
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:
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:
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:
{
"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.
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.
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.
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.
{
"creatorse_element": {
"motive": {"id": 67890}
}
}
Additional management endpoints
GET .../motives— list all motives in the shop (paginated)GET .../motives/{motiveId}— get motive detailPUT .../motives/{motiveId}— update motive name or typeDELETE .../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 Catalog | User 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:
| Type | Lifetime | Access |
|---|---|---|
| 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
- Obtain a Customer Key by making a
GET uuidrequest to the public Nonce resource (no authentication required). - Log in with a
POSTto the Authentication resource, passing your Customer Key in thex-customer-keyrequest header. Using the same key always grants access to the same permanent library.
Uploading a motive
- HTML / form-based clients: use the
createFromMultipartFormPOST method on the UserMotive resource - API clients: use the
createFromDataPOST 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 element | Data type | Example endpoint |
|---|---|---|
productFilter | Filter.Product | GET /accounts/{accountId}/shops/{shopId}/products |
productionOrderFilter | Filter.Order | GET /accounts/{accountId}/shops/{shopId}/orders |
motiveFilter | Filter.Motive | GET /accounts/{accountId}/shops/{shopId}/creator/motives |
sharedProductFilter | Filter.SharedProduct | GET /accounts/{accountId}/shops/{shopId}/sharedProducts |
orderedProductFilter | Filter.OrderedProduct | GET /accounts/{accountId}/shops/{shopId}/orders/{orderId}/orderedProducts |
orderedProductCustomAttributeFilter | Filter.OrderedProductCustomAttribute | GET /accounts/{accountId}/shops/{shopId}/orders/{orderId}/orderedProducts/{productId}/customAttributes |
shopFilter | Filter.Shop | GET /accounts/{accountId}/shops |
webhookFilter | Filter.Webhook | GET /accounts/{accountId}/shops/{shopId}/webhooks |
countryFilter | Filter.Country | GET /accounts/{accountId}/countries |
productionOrderCsvImportFilter | Filter.OrderCsvImport | GET /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 element | Data type | Description |
|---|---|---|
productLocalizedFilter | Filter.ProductLocalized | Localized product attributes (e.g. translated name) |
productAssignedToCategoryFilter | Filter.ProductAssignedToCategory | Product-to-category assignments |
productSkuFilter | Filter.ProductSku | Product SKU entries |
productColorFilter | Filter.ProductColor | Product color definitions |
productSizeFilter | Filter.ProductSize | Product size definitions |
productViewFilter | Filter.ProductView | Printable view definitions of a product |
productPriceFilter | Filter.ProductPrice | Product price entries (by country, color, size) |
assignedProductColorFilter | Filter.ProductAssignedColor | Color variants assigned to a product |
assignedProductSizeFilter | Filter.ProductAssignedSize | Size variants assigned to a product |
assignedProductViewFilter | Filter.ProductAssignedView | Printable view assignments to a product |
productViewColorDetailFilter | Filter.ProductAssignedViewColor | Color assignments per product view |
assignedProductStickerFilter | Filter.ProductAssignedSticker | Sticker assignments to product views |
assignedPrintTechnologyFilter | Filter.ProductAssignedPrintTechnology | Print technology assignments to products |
assignedAttributeListItemFilter | Filter.ProductAssignedAttributeListItem | Attribute list item assignments to products |
motiveLocalizedFilter | Filter.MotiveLocalized | Localized motive attributes (e.g. translated name) |
motiveAssignedToCategoryFilter | Filter.MotiveAssignedToCategory | Motive-to-category assignments |
motivePrintTechnologyFilter | Filter.MotivePrintTechnology | Print technology assignments to motives |
tagFilter | Filter.Tag | Tag resources |
shopPropertyFilter | Filter.ShopProperty | Shop 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.
POST /rest/filters HTTP/1.1
Content-Type: application/json
x-auth-token: c4094ac8-fbae-4d67-ab71-7ff0714b7647
{
"productFilter": {
"expressionSimple": {
"value": "false",
"op": "=",
"property": "deleted"
},
"order": {
"direction": "asc",
"property": "name"
}
}
}
{
"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.
| Type | XML element name | Fields | Purpose |
|---|---|---|---|
| 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
| Operator | Description | Example value |
|---|---|---|
= | Equal | "value": "false", "op": "=", "property": "deleted" |
!= | Not equal | "value": "CANCELLED", "op": "!=", "property": "status" |
like | Pattern match (case-sensitive, use % as wildcard) | "value": "%shirt%", "op": "like", "property": "name" |
ilike | Pattern 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.
{
"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.
{
"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.
{
"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.
{
"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.
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
| Scenario | Behavior |
|---|---|
filterId is empty or not provided | The endpoint uses its own default filter (typically deleted = false with default ordering) |
filterId is provided but does not exist | Error code -104 FilterNotFoundException |
| Invalid property name in a filter expression | SqlValidationException 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
| Domain | Topic | Payload type |
|---|---|---|
| Order | orders/updated | ProductionOrderExpanded |
orders/readyForProduction | ProductionOrderExpanded | |
orders/fulfilled | ProductionOrderExpanded | |
orders/acknowledged | ProductionOrderExpanded | |
orders/failed | ProductionOrderProcessingError | |
orders/splitted | ProductionOrderSplitted | |
orders/cancelled | ProductionOrderExpanded |
Webhook anatomy
Each notification is an HTTP POST to your endpoint URL with a JSON or XML payload and context 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:
{
"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:
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 theseparator(and optionallyquote) 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 name | Description |
|---|---|---|
| Order | ||
| 1 | order group id | Groups rows into the same order. Rows with the same value become items in one order. |
| 2 | uniqueId | Your external order identifier. |
| 3 | countryId | Shirtplatform country ID (determines currency and VAT). |
| Shipping | ||
| 4 | shipping carrier Id | Shirtplatform carrier ID. |
| 5 | orderShippingCode | Shipping method code. |
| 6 | orderShippingTitle | Shipping method display title. |
| 7 | orderShippingPrice | Shipping price. |
| 8 | orderShippingCodPrice | Cash-on-delivery surcharge. |
| 9 | orderShippingOrderValue | Order value used for shipping cost calculation. |
| Customer | ||
| 10 | customer first name | |
| 11 | customer last name | |
| 12 | customer email | |
| 13 | customer phone | |
| Billing address | ||
| 14 | customer billing address first name | |
| 15 | customer billing address last name | |
| 16 | customer billing address name | Company name. |
| 17 | customer billing address street | |
| 18 | customer billing address street no | |
| 19 | customer billing address city | |
| 20 | customer billing address country name | |
| 21 | customer billing address country code | ISO 3166-1 alpha-2 (e.g. DE). |
| 22 | customer billing address zip | |
| 23 | customer billing address state name | |
| 24 | customer billing address state code | |
| 25 | customer billing address phone | |
| 26 | customer billing address email | |
| Shipping address | ||
| 27 | customer shipping address first name | |
| 28 | customer shipping address last name | |
| 29 | customer shipping address name | Company name. |
| 30 | customer shipping address street | |
| 31 | customer shipping address street no | |
| 32 | customer shipping address city | |
| 33 | customer shipping address country name | |
| 34 | customer shipping address country code | ISO 3166-1 alpha-2 (e.g. DE). |
| 35 | customer shipping address zip | |
| 36 | customer shipping address state name | |
| 37 | customer shipping address state code | |
| 38 | customer shipping address phone | |
| 39 | customer shipping address email | |
| Design | ||
| 40 | design group id | Groups rows into the same design (multiple motives, different sides). |
| 41 | design product id | Shirtplatform product ID. |
| 42 | design product sku | Product SKU (alternative to product ID). |
| 43 | design amount | Quantity. |
| 44 | composition group id | Groups rows into the same composition (multiple motives on the same area). |
| 45 | product area id | Shirtplatform product area ID. |
| 46 | product area name | Product area name (alternative to area ID). |
| 47 | element motive id | Shirtplatform motive ID. |
| 48 | element motive url | URL of a bitmap motive to upload on-the-fly. |
| Motive position | ||
| 49 | position left | Distance from left edge of print area (mm or %). |
| 50 | position right | Distance from right edge of print area (mm or %). |
| 51 | position top | Distance from top edge of print area (mm or %). |
| 52 | position bottom | Distance from bottom edge of print area (mm or %). |
| 53 | position horizontal center | Center horizontally on the print area (true/false). |
| 54 | position vertical center | Center 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:
| Field | Purpose |
|---|---|
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) |