Skip to Content

Branding

Available.

A brand is { name, logo, skin }: your organization’s display name, a logo, and the color/shape skin. Branding is tenant-first: set the tenant brand with PUT /v1/branding (branding:manage); every user sees it. A tenant may grant individual users override permission (canOverrideBranding on the user record); a permitted user can then set a personal brand for their own account via PUT /v1/branding/me (session auth). Resolution is per-field: user → tenant → platform default (the skin always resolves as a whole).

// PUT /v1/branding (tenant-wide) { "name": "Acme Growers", "logo": { "light": "https://cdn.acme.com/logo.png", // https URL… "dark": "data:image/png;base64,…" // …or an uploaded data-URL (≤ 300 KB) }, "skin": { /* see below */ } }

GET /v1/branding/theme returns the resolved brand for the caller (name, logo, and the merge-ready MUI fragment), so the GUI shows each user exactly their view.

A skin puts the Growth Lab GUI in your brand: your colors for the light and dark themes, plus optional corner-radius overrides for the GUI’s surface categories. A skin is a minimal Material UI theme fragment. The GUI fetches it at session init and merges it over the platform default, so everything (buttons, charts, alerts, tiles) picks up your palette in both modes automatically.

Set your skin

PUT /v1/branding/skin with an API key holding the branding:manage scope. Both light and dark are required (your skin must work in both modes); shape is optional.

{ "light": { "palette": { "primary": { "main": "#0055aa" }, "secondary": { "main": "#ffaa00", "contrastText": "#000000" }, "background": { "default": "#fafafa", "paper": "#ffffff" } } }, "dark": { "palette": { "primary": { "main": "#66aaff" }, "background": { "default": "#101418", "paper": "#181d23" } } }, "shape": { "panel": 16, "pane": 12, "widget": 4 } }

Palette: the allowed keys per scheme (anything else is rejected): primary, secondary, error, warning, info, success (each { main, light?, dark?, contrastText? }), background { default?, paper? }, text { primary?, secondary?, disabled? }, and divider. Colors are hex only (#rgb, #rrggbb, #rrggbbaa). Omit a key and the platform default applies; Material UI derives hover/shade variants from main unless you set them.

Shape: border-radius overrides in px (0–48) for the three surface categories:

TokenApplies to
panelTop-level surface cards (workspace, dialogs, sign-in, loading overlay)
paneContent areas inside a panel or tab (tile grid, Sources list/map)
widgetTiles and small cards

Omitted tokens keep the GUI’s default geometry.

GET /v1/branding/skin reads back exactly what you stored; DELETE /v1/branding/skin returns your tenant to the platform default.

How the GUI consumes it

GET /v1/branding/theme (session cookie or any tenant key) returns the resolved brand for the caller:

{ "name": "Acme Growers", "logo": { "light": "https://…", "dark": "data:image/png;base64,…" }, "colorSchemes": { "light": { "palette": { /* your light palette */ } }, "dark": { "palette": { /* your dark palette */ } } }, "shape": { "panel": 16, "pane": 12, "widget": 4 } // null values = no override }

With no skin set, the palettes are empty and every radius is null, so clients can always deep-merge the response into a base theme without special-casing. name / logo are null when neither the user nor the tenant set them.

The Growth Lab GUI:

  • Merges colorSchemes and shape over the platform theme at session init
  • Shows name and the mode-matching logo in the workspace chrome
  • Lets a user with canOverrideBranding edit their personal brand from Settings → Account Settings (PUT /v1/branding/me). Blank fields fall through to the tenant brand; Use tenant brand clears the personal override (DELETE /v1/branding/me)

The two palettes are used as:

TokenRole
primaryBrand chrome and main actions (tabs, Next / Create / Save, stepper)
secondaryAccent: selected tiles, outlined supporting actions (Back, Upload, Run, History), and form controls (switches, radios, checkboxes, sliders)

Source markers keep their own hint colors; the selected-on-map ring is a fixed high-contrast red so it still reads against an orange sensor hint.

Resolution is per-field: a permitted user’s personal brand overlays the tenant brand for their session only (name, logo, and the skin as a whole). Other users of the tenant are unchanged. Light/dark mode (user preference or your host page’s hint) selects which palette and which logo apply.