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.

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}
          }]
        }
      }]
    }
  }
}
Step 3 — Commit the order

Push the order to the production pipeline with a PUT commitOrder request to the Order resource.

http
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.

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.

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)