Opbox ships with six built-in themes - light, dark, system, neon, ember, and ocean - and lets each user build their own custom themes on top. A custom theme is a named set of CSS variable overrides that apply at runtime. Tokens that aren't set fall back to the base theme defaults.
The endpoints below give programmatic access to the same system used by the in-app theme editor.
Active Theme
Get or set which theme the user sees. Built-in themes are referenced by their name (light, dark, system, neon, ember, ocean). Custom themes use the format custom-{themeId}.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/user/theme | Get the user's active theme |
| PUT | /api/user/theme | Set the active theme |
Custom Themes
Users can create up to 20 custom themes. Each theme stores a name and a set of token overrides (CSS variable values). Tokens not set fall back to the base theme defaults.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/user/themes | List all custom themes |
| POST | /api/user/themes | Create a custom theme |
| GET | /api/user/themes/:id | Get a specific custom theme |
| PUT | /api/user/themes/:id | Full update (name, tokens, isActive) |
| PATCH | /api/user/themes/:id | Partial token merge |
| DELETE | /api/user/themes/:id | Delete a custom theme |
Per-Token Control
Individual token endpoints let you read, set, or remove a single color override within a theme. Ideal for AI-driven theme builders or granular adjustments.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/user/themes/:id/tokens/:tokenKey | Get a single token value + metadata |
| PUT | /api/user/themes/:id/tokens/:tokenKey | Set a single token value |
| DELETE | /api/user/themes/:id/tokens/:tokenKey | Remove a token override (revert to default) |
Token Reference
Retrieve the full list of available design tokens with their metadata, defaults, and groupings.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/user/themes/tokens | List all 48 design tokens with defaults |
Examples
Get active theme
GET /api/user/theme
{
"theme": "neon"
}
Set active theme
PUT /api/user/theme
Content-Type: application/json
{
"theme": "ocean"
}
For a custom theme:
{
"theme": "custom-cmlf5a2xk000btb..."
}
Create a custom theme
POST /api/user/themes
Content-Type: application/json
Request body:
{
"name": "Midnight",
"tokens": {
"bgPrimary": "#0a0a1a",
"bgSecondary": "#060612",
"bgTertiary": "#141432",
"fgPrimary": "#e8e8f0",
"fgSecondary": "#8888a0",
"accent": "#7c3aed",
"accentFg": "#ffffff"
}
}
Response:
{
"theme": {
"id": "cmlf5a2xk000btb...",
"name": "Midnight",
"tokens": { },
"isActive": false,
"createdAt": "2026-02-12T..."
}
}
Set a single token
PUT /api/user/themes/:id/tokens/:tokenKey
Content-Type: application/json
Request body:
{
"value": "#ff6b6b"
}
Response:
{
"key": "accent",
"value": "#ff6b6b",
"theme": { }
}
Get token reference
GET /api/user/themes/tokens
Response:
{
"tokens": [
{
"key": "bgPrimary",
"cssVar": "--bg-primary",
"label": "Primary Background",
"group": "Backgrounds",
"type": "color",
"description": "Main surface color (cards, sidebar, tables)"
}
],
"groups": ["Backgrounds", "Text", "Borders"],
"defaults": {
"light": { "bgPrimary": "#ffffff" },
"dark": { "bgPrimary": "#1a1a1a" }
}
}
Partial token merge
PATCH /api/user/themes/:id
Content-Type: application/json
Request body - merges with existing tokens, only the specified keys are updated:
{
"tokens": {
"accent": "#00d4ff",
"accentFg": "#0a0e12",
"success": "#39d98a"
}
}
Token Groups
Tokens are organized into 10 semantic groups. Core groups cover the most impactful colors; advanced groups provide fine-grained control. The full palette totals 48 tokens.
| Group | Tokens | Examples |
|---|---|---|
| Backgrounds | 3 | bgPrimary, bgSecondary, bgTertiary |
| Text | 3 | fgPrimary, fgSecondary, fgTertiary |
| Borders | 2 | border, borderHover |
| Accent | 3 | accent, accentFg, colorPrimaryHover |
| Spotlight | 5 | spotlightIconActive, spotlightBackdrop, spotlightGlass, ... |
| Status | 4 | success, warning, error, destructiveForeground |
| Status Tints | 4 | statusSuccessBg, statusErrorBg, ... |
| Filters | 4 | filterActive, filterActiveBorder, filterActiveText, ... |
| Sidebar | 5 | sidebarBg, sidebarFg, sidebarAccent, ... |
| Components | 15 | card, cardForeground, popover, popoverForeground, ... |
Notes
- All changes require authentication.
- Theme names must be unique per user. Duplicate names return
409 Conflict. - Maximum 20 custom themes per user.
- Token values must be valid CSS colors: hex (
#rrggbb),rgb(),rgba(), orhsl(). - Setting
isActive: trueon PUT automatically deactivates all other custom themes for the user. - Deleting a token override (DELETE per-token) reverts that token to the base theme default.