The InStore Theming API endpoints let you read, replace, and partially update your tenant's POS theme, with request and response examples and notes on how each call affects the running InStore POS.
This page is the endpoint reference for the InStore Theming API.
- To set up an API client and authenticate, see Run InStore POS API requests.
- To learn what to put in the theme payload (palette, typography, component overrides, and responsive layout tokens), see Customize styles and behavior.
Base path and methods
All theme operations act on a single resource path:
{mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme
mistApiBase, projectKey, tenantId) and the required request headers are described in Run InStore POS API requests.| Method | Purpose | Required scope |
|---|---|---|
GET | Read the persisted theme. | Open to any authenticated caller. |
PUT | Replace the whole theme. Fields you omit are unset. | Administration. |
PATCH | Apply a partial update via deep-merge. | Administration. |
PUT, PATCH) send a JSON body and require Content-Type: application/json.How a request takes effect in the InStore POS
PUT or PATCH therefore takes effect on the next load of the POS. Reload to see your change.GET /theme
Returns the theme document stored for the tenant. It's read-only and has no effect on the running app. Inspect the active theme and use the response as the starting point for your next edit.
GET {mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme
The response is the persisted theme document:
{
"name": "My branded theme",
"palette": {
"text": { "primary": "#212121" },
"primary": { "main": "#1976d2", "contrastText": "#ffffff" },
"secondary": { "main": "#dc004e", "contrastText": "#ffffff" },
"tertiary": { "main": "#4caf50", "contrastText": "#ffffff" },
"background": { "default": "#fafafa" }
},
"typography": {
"fontFamily": "Roboto, sans-serif",
"h1": { "fontSize": "2.5rem", "fontWeight": 700, "lineHeight": 1.2 }
},
"spacing": 8,
"shape": { "borderRadius": 4 },
"components": {
"MuiButton": {
"defaultProps": { "disableElevation": true },
"styleOverrides": {
"root": {
"borderRadius": "8px",
"textTransform": "none",
"&.Mui-disabled": {
"backgroundColor": "action.disabledBackground",
"color": "action.disabled"
}
}
}
}
},
"customTokens": {
"layout": { "mobileFooter": { "xs": true, "md": false } },
"sidebar": { "showCollapseButton": true }
}
}
Effect on the app: none. Nothing re-renders.
GET before each change and use its response as the base for your next PUT or PATCH. The InStore POS stores only the currently active theme and keeps no server-side version history. commercetools cannot recover a configuration you overwrite. To avoid losing a working configuration, see Back up your theme payloads.PUT /theme
Replaces the entire theme in one call. Any top-level field you don't send is unset.
PUT {mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme
{
"name": "My branded theme",
"palette": {
"primary": { "main": "#1976d2", "contrastText": "#ffffff" },
"secondary": { "main": "#dc004e", "contrastText": "#ffffff" },
"tertiary": { "main": "#4caf50", "contrastText": "#ffffff" }
},
"typography": { "fontFamily": "Roboto, sans-serif" },
"spacing": 8,
"shape": { "borderRadius": 4 },
"components": {
"MuiButton": {
"defaultProps": { "disableElevation": true },
"styleOverrides": { "root": { "borderRadius": "8px" } }
}
},
"customTokens": {
"layout": { "mobileFooter": { "xs": true, "md": false } },
"sidebar": { "showCollapseButton": true }
}
}
PUT returns the persisted theme, which is the same body you sent, normalized.PATCH /theme
components.MuiX block, which is replaced atomically.Scenario 1: change only the sidebar's responsive layout.
PATCH {mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme
{
"customTokens": {
"sidebar": {
"showCollapseButton": { "xs": true, "md": false }
}
}
}
customTokens.sidebar.showCollapseButton is updated and everything else is preserved.Scenario 2: replace a single component override.
PATCH {mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme
{
"components": {
"MuiButton": {
"defaultProps": { "disableElevation": true },
"styleOverrides": {
"root": {
"borderRadius": "8px",
"&.Mui-disabled": {
"backgroundColor": "action.disabledBackground",
"color": "action.disabled"
}
}
},
"variants": [
{
"props": { "className": "instore-primary-action" },
"style": {
"backgroundColor": "primary.main",
"color": "primary.contrastText",
"&:hover": { "backgroundColor": "primary.dark" }
}
}
]
}
}
}
style values reference palette tokens such as primary.main, the derived primary.dark, and the semantic MUI action.* tokens, rather than hard-coded hex. To understand which token strings are supported and when derived shades are available, see Reference palette tokens in component overrides.Scenario 3: move the sidebar to the left or right.
components.MuiDrawer.defaultProps.anchor. The bundled POS theme docks it on the right ("anchor": "right"); set it to "left" to move the sidebar (and the surrounding page layout, which flips to match) to the left. Only "left" and "right" are meaningful for the POS sidebar.PATCH {mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme
{
"components": {
"MuiDrawer": {
"defaultProps": { "anchor": "left" }
}
}
}
anchor is the only field that changes the side, but a components.MuiX block is replaced atomically. A MuiDrawer payload that carries only defaultProps drops the bundled sidebar styleOverrides and its responsive variants, which breaks the sidebar's appearance. Run GET /theme first, change defaultProps.anchor inside the returned MuiDrawer block, then send the whole block back.PATCH any components.X entry, the entire block under that component is replaced. Sibling components (for example, MuiFormControl) are preserved, but the MuiButton inner defaultProps, styleOverrides, and variants are not deep-merged. Send the full block if you want to keep existing properties.components.MuiX block is replaced wholesale, omitting slots you previously set will visibly drop those styles. Resend the full block to keep them.PUT vs PATCH at a glance
PUT | PATCH | |
|---|---|---|
| Top-level fields you omit | Unset | Preserved |
| Leaf values you send | Replace | Deep-merged |
A components.MuiX block you send | Replaces the whole block | Replaces the whole block (atomic) |
| Empty or absent body | Reverts to the Default theme | No-op |
| Use it to | Set or reset the whole theme | Tweak specific values |
Theme payload fields
ThemeOptions shape plus a small set of InStore-specific fields. The top-level fields are summarized below; for what each one controls and how to author it, follow the links into Customize POS styles and behavior. Inside components, color values resolve as MUI sx, so reference palette tokens such as 'primary.main' instead of repeating hex. To choose valid token strings and avoid hard-coded color values, see Reference palette tokens in component overrides. To find which components.MuiX block and customTokens flag drives a given on-screen surface, see the POS style reference.| Field | Type | Description |
|---|---|---|
name | String | Human-readable identifier for the theme. |
palette | Object | Color tokens: primary, secondary, tertiary, text, background. Mirrors MUI palette. |
typography | Object | Font scale: fontFamily, h1 to h6, body1, body2, and other variants. Mirrors MUI typography. |
breakpoints | Object | Responsive breakpoint thresholds. To understand the breakpoint keys and values, see MUI breakpoints. |
spacing | Number | Number[] | MUI spacing unit. |
shape | Object | Geometry tokens: for example, borderRadius. |
components | Object | Per-MUI-component overrides. To author slots, variants, and default props, see Customize MUI component overrides. |
customTokens | Object | POS-specific responsive layout flags. To change responsive POS layout behavior, see Responsive layout tokens. |
Validation and errors
400 when they break these rules:- String values: max 512 characters; forbidden characters
<,>, backtick,\r,\n. The applied regular expression (with the backtick shown asBT) is^[^<>BT\r\n]*$. - Colors: any string MUI accepts (for example,
#15375C,rgba(0,0,0,0.87),hsl(210, 50%, 45%), or named colors). Strings are passed through unchanged. __fnallowlist: only{ "__fn": "ownerState", "cases": { ... } }is accepted, with no other discriminator value and no inline function literals. To define conditional styles from supportedownerStatevalues, see The ownerState escape hatch.- Unknown fields are rejected at every nesting level.
{
"statusCode": 400,
"message": "Expected SafeCssString but got string with forbidden character",
"errors": [
{
"code": "InvalidInput",
"message": "Forbidden character at index 8",
"path": "$input.palette.primary.main"
}
]
}