---
title: "Create a theme"
method: POST
path: "/api/user_themes"
tags: ["User Themes"]
---

# Create a theme

`POST /api/user_themes`

## Request

- Base URL: `https://trmnl.com`
- URL: `https://trmnl.com/api/user_themes`
- Auth: HTTP bearer

settings is validated the same way the theme builder validates it: a value outside the vocabulary (an unrecognized token, surface, hue, or advanced channel) answers 422; a key the recipe does not read is ignored. advanced is either a mapping (channels/slots restated on one token) or the same mapping as YAML text.

## Request body

- object
  - `name` string, required: Unique per account
  - `settings` UserThemeSettings: Every key is optional; an omitted key keeps the framework default. A value outside the vocabulary (an unrecognized token, surface, hue, or advanced channel) answers 422; a key the recipe does not read is ignored, not rejected.
    - `font` string, nullable: A FontPack id such as "bitter" or "space-mono", or blank for the device font
    - `chip` 'filled' | 'outlined'
    - `screen_scale` string: "none", "invert", or a hue side like "red-dark"/"red-bright"
    - `surfaces` object: paper, text, muted_text, strong_fill, soft_fills, borders, title_bar, progress, dividers — each a color token ("black", "white", "gray-30", "red-40", ...) or "hidden" for dividers
    - `remap` object
      - `grays` string: "keep", "invert", a hue side, "<hue>-linear", or any color token
      - `colors` object: target token per hue: red, orange, yellow, lime, green, cyan, blue, violet, purple, pink
    - `layout` object
      - `whitespace` 'compact' | 'regular' | 'airy' | 'spacious'
      - `corners` 'sharp' | 'regular' | 'round'
      - `title_bar_height` 'slim' | 'regular' | 'tall'
      - `progress` 'slim' | 'regular' | 'thick'
    - `typography` object: weight ("light"/"regular"/"medium"/"bold"), plus <role>_case ("as-written"/"uppercase"/"lowercase") and <role>_tracking ("normal"/"wide"/"wider") for title, value, label, description, title_bar, title_bar_instance, table_head (table_body has no _case)
    - `spacing` object
      - `title_bar_padding` 'flush' | 'regular' | 'wide'
      - `item_padding` 'none' | 'small' | 'regular' | 'large'
    - `title_bar` object: ink, instance, stroke, instance_stroke — a color token, or "auto"/"inherit"
    - `item` object
      - `fill` string: "none", "ramp", or a color token
      - `border` 'none' | 'outline' | 'corner-brackets'
      - `ink` string: "auto" or a color token
    - `advanced` object: Framework contract channels and slots restated on one token, e.g. { "channels": { "canvas": "black" } }. Also accepted as the same mapping written as YAML text.

## Response `200`

Created

- object
  - `data` UserTheme
    - `id` integer
    - `name` string
    - `settings` UserThemeSettings: Every key is optional; an omitted key keeps the framework default. A value outside the vocabulary (an unrecognized token, surface, hue, or advanced channel) answers 422; a key the recipe does not read is ignored, not rejected.
      - `font` string, nullable: A FontPack id such as "bitter" or "space-mono", or blank for the device font
      - `chip` 'filled' | 'outlined'
      - `screen_scale` string: "none", "invert", or a hue side like "red-dark"/"red-bright"
      - `surfaces` object: paper, text, muted_text, strong_fill, soft_fills, borders, title_bar, progress, dividers — each a color token ("black", "white", "gray-30", "red-40", ...) or "hidden" for dividers
      - `remap` object
        - `grays` string: "keep", "invert", a hue side, "<hue>-linear", or any color token
        - `colors` object: target token per hue: red, orange, yellow, lime, green, cyan, blue, violet, purple, pink
      - `layout` object
        - `whitespace` 'compact' | 'regular' | 'airy' | 'spacious'
        - `corners` 'sharp' | 'regular' | 'round'
        - `title_bar_height` 'slim' | 'regular' | 'tall'
        - `progress` 'slim' | 'regular' | 'thick'
      - `typography` object: weight ("light"/"regular"/"medium"/"bold"), plus <role>_case ("as-written"/"uppercase"/"lowercase") and <role>_tracking ("normal"/"wide"/"wider") for title, value, label, description, title_bar, title_bar_instance, table_head (table_body has no _case)
      - `spacing` object
        - `title_bar_padding` 'flush' | 'regular' | 'wide'
        - `item_padding` 'none' | 'small' | 'regular' | 'large'
      - `title_bar` object: ink, instance, stroke, instance_stroke — a color token, or "auto"/"inherit"
      - `item` object
        - `fill` string: "none", "ramp", or a color token
        - `border` 'none' | 'outline' | 'corner-brackets'
        - `ink` string: "auto" or a color token
      - `advanced` object: Framework contract channels and slots restated on one token, e.g. { "channels": { "canvas": "black" } }. Also accepted as the same mapping written as YAML text.
    - `created_at` string, date_time
    - `updated_at` string, date_time
    - `scss` string: getUserTheme only: the framework SCSS file this theme exports

## Other responses

- `401`: Unauthorized
- `422`: Rejects advanced YAML that does not parse

---

[API](https://skmtc.dev/trmnl/apis/trmnl-api.md) · [All operations](https://skmtc.dev/trmnl/apis/trmnl-api/llms.txt) · [OpenAPI document](https://skmtc.dev/trmnl/apis/trmnl-api/revisions/66179e6d663b?raw)
