# Theme API reference 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](/instore/customization/pos-api-access.md). - To learn what to put in the theme payload (palette, typography, component overrides, and responsive layout tokens), see [Customize styles and behavior](/instore/customization/pos-theming.md). ## Base path and methods All theme operations act on a single resource path: ```bash title="Theme resource path" {mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme ``` The path placeholders (`mistApiBase`, `projectKey`, `tenantId`) and the required request headers are described in [Run InStore POS API requests](/instore/customization/pos-api-access.md#api-base-host-and-path-elements). | 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. | Writes (`PUT`, `PATCH`) send a JSON body and require `Content-Type: application/json`. ## How a request takes effect in the InStore POS A theme write doesn't change the screen immediately. The InStore POS fetches the persisted theme at bootstrap, deep-merges it over the bundled default, and hands the result to MUI. A `PUT` or `PATCH` therefore takes effect on the next load of the POS. Reload to see your change. ```mermaid flowchart LR Client["API client
PUT and PATCH"] Store[("Persisted tenant theme")] Fetch["POS fetches theme
at next bootstrap"] Bundled["Bundled default theme"] Merge{{deep-merge}} MUI["MUI ThemeProvider and useTheme"] POS["POS federated modules
(Cart, Catalog, …)"] Core["core payment, cash, and device modules"] UI["Rendered InStore POS UI"] Client --> Store --> Fetch --> Merge Bundled --> Merge Merge --> MUI MUI --> POS --> UI MUI --> Core --> UI classDef src fill:#C2C2FF,stroke:#6359FF,stroke-width:2px,color:#191741; classDef store fill:#FFE7A8,stroke:#FFC738,stroke-width:2px,color:#191741; classDef proc fill:#8F8FFF,stroke:#4E4ED7,stroke-width:2px,color:#191741; classDef pos fill:#9FF7EE,stroke:#08A88A,stroke-width:2px,color:#003037; classDef mist fill:#F9C9C0,stroke:#FF8A00,stroke-width:2px,color:#191741; class Client,Bundled src; class Store store; class Fetch,Merge,MUI proc; class POS,UI pos; class Core mist; ``` Changes apply on the next POS load; they are not live. For the full merge model, see [How overrides compose](/instore/customization/pos-theming.md#how-overrides-compose). ## 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. ```bash title="GET request" GET {mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme ``` ```mermaid flowchart LR C["Client: GET /theme"] --> API["Theming API"] API --> Store[("Persisted tenant theme")] Store --> Resp["Response: theme JSON"] Resp --> Reuse["Base for your next PUT and PATCH"] classDef src fill:#C2C2FF,stroke:#6359FF,stroke-width:2px,color:#191741; classDef store fill:#FFE7A8,stroke:#FFC738,stroke-width:2px,color:#191741; classDef out fill:#9FF7EE,stroke:#08A88A,stroke-width:2px,color:#003037; class C,Reuse src; class API,Resp out; class Store store; ``` The response is the persisted theme document: ```json title="Response body example" { "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. Run `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](/instore/customization/pos-theming.md#back-up-your-theme-payloads). ## PUT /theme Replaces the entire theme in one call. Any top-level field you don't send is unset. ```bash title="PUT request" 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 } } } ``` ```mermaid flowchart TD C["Client: PUT /theme"] --> Q{Body provided?} Q -->|"Full theme"| Replace["Replace stored theme
omitted fields unset"] Q -->|"Empty or absent"| Default["Revert to Default theme
(legacy colleague-app look)"] Replace --> Load["Next POS load"] Default --> Load Load --> UI["Whole POS re-skinned"] classDef src fill:#C2C2FF,stroke:#6359FF,stroke-width:2px,color:#191741; classDef dec fill:#FFE7A8,stroke:#FFC738,stroke-width:2px,color:#191741; classDef rep fill:#8F8FFF,stroke:#4E4ED7,stroke-width:2px,color:#191741; classDef def fill:#F9C9C0,stroke:#FF8A00,stroke-width:2px,color:#191741; classDef out fill:#9FF7EE,stroke:#08A88A,stroke-width:2px,color:#003037; class C src; class Q dec; class Replace rep; class Default def; class Load,UI out; ``` A successful `PUT` returns the persisted theme, which is the same body you sent, normalized. Effect on the app: re-skins the whole POS on the next load. Sending an empty or absent body reverts the tenant to the Default theme, which resembles the legacy InStore look. To compare the fallback theme with the starter theme, see [Default and POS starter themes](/instore/customization/pos-theming.md#default-and-pos-starter-themes). ## PATCH /theme Applies a partial update. Leaf values are deep-merged into the stored theme, so you only send what changes, except a `components.MuiX` block, which is replaced atomically. Scenario 1: change only the sidebar's responsive layout. ```bash title="PATCH request: sidebar only" PATCH {mistApiBase}/{projectKey}/instore-tenants/{tenantId}/theme { "customTokens": { "sidebar": { "showCollapseButton": { "xs": true, "md": false } } } } ``` The response shows the merged result: `customTokens.sidebar.showCollapseButton` is updated and everything else is preserved. Scenario 2: replace a single component override. ```bash title="PATCH request: replace MuiButton" 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" } } } ] } } } ``` The `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](/instore/customization/pos-theming.md#reference-palette-tokens-in-component-overrides). Scenario 3: move the sidebar to the left or right. The InStore POS reads which side the sidebar docks on from `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. ```bash title="PATCH request: move the sidebar to the left" 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`](/instore/customization/pos-theme-api.md#get-theme) first, change `defaultProps.anchor` inside the returned `MuiDrawer` block, then send the whole block back. ```mermaid flowchart TD C["Client: PATCH /theme"] --> Path{Path type} Path -->|"components.MuiX"| Atomic["Replace that component block
atomically"] Path -->|"other paths"| Leaf["Deep-merge at leaf level
siblings preserved"] Atomic --> Load["Next POS load"] Leaf --> Load Load --> UI["Only the targeted surfaces change"] classDef src fill:#C2C2FF,stroke:#6359FF,stroke-width:2px,color:#191741; classDef dec fill:#FFE7A8,stroke:#FFC738,stroke-width:2px,color:#191741; classDef atom fill:#8F8FFF,stroke:#4E4ED7,stroke-width:2px,color:#191741; classDef leaf fill:#C2C2FF,stroke:#6359FF,stroke-width:2px,color:#191741; classDef out fill:#9FF7EE,stroke:#08A88A,stroke-width:2px,color:#003037; class C src; class Path dec; class Atomic atom; class Leaf leaf; class Load,UI out; ``` When you `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. Effect on the app: changes only the surfaces you targeted. Because a `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 The theme document is the MUI `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](/instore/customization/pos-theming.md). 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](/instore/customization/pos-theming.md#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](/instore/customization/pos-style-reference.md). | Field | Type | Description | | --- | --- | --- | | `name` | String | Human-readable identifier for the theme. | | `palette` | Object | Color tokens: `primary`, `secondary`, `tertiary`, `text`, `background`. Mirrors [MUI palette](https://v7.mui.com/material-ui/customization/palette/). | | `typography` | Object | Font scale: `fontFamily`, `h1` to `h6`, `body1`, `body2`, and other variants. Mirrors [MUI typography](https://v7.mui.com/material-ui/customization/typography/). | | `breakpoints` | Object | Responsive breakpoint thresholds. To understand the breakpoint keys and values, see [MUI breakpoints](https://v7.mui.com/material-ui/customization/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](/instore/customization/pos-theming.md#customize-mui-component-overrides). | | `customTokens` | Object | POS-specific responsive layout flags. To change responsive POS layout behavior, see [Responsive layout tokens](/instore/customization/pos-theming.md#responsive-layout-tokens). | ## Validation and errors The API accepts JSON only and enforces a strict schema. Writes are rejected with `400` when they break these rules: - String values: max 512 characters; forbidden characters `<`, `>`, backtick, `\r`, `\n`. The applied regular expression (with the backtick shown as `BT`) 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. - `__fn` allowlist: only `{ "__fn": "ownerState", "cases": { ... } }` is accepted, with no other discriminator value and no inline function literals. To define conditional styles from supported `ownerState` values, see [The ownerState escape hatch](/instore/customization/pos-theming.md#the-ownerstate-escape-hatch). - Unknown fields are rejected at every nesting level. ```json title="Validation error response example" { "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" } ] } ``` ## Related pages - [Run InStore POS API requests](/instore/customization/pos-api-access.md): set up a request client and authenticate. - [Customize styles and behavior](/instore/customization/pos-theming.md): author the theme payload: palette, typography, component overrides, hooks, and responsive layout tokens. - [POS style reference](/instore/customization/pos-style-reference.md): map an on-screen surface to its class, component, and slot. ## Related pages - [Area overview page with navigation](/instore.md) - [Previous page: Run InStore POS API requests](/instore/customization/pos-api-access.md) - [Next page: Customize styles and behavior](/instore/customization/pos-theming.md) - [Search documentation and API specs](/search.md)