Design, Site Settings & Files

Part of the Content API. Endpoints for the site’s design (template and color scheme), its editable settings, and its uploaded files.

Design

/api/v3/design/

Scopes: design:read / design:write. The site’s design is a template (the design family: miranda, miranda-thin, molly, anna, anna-modern) and a color scheme: a named variation of that template plus its variable values. CSS is generated from these on request, so changes are live immediately.

  • GET /design/{"template", "template_family", "styles": {"name", "vars": {...}}, "previous_template"}.
  • GET /design/templates/ → the catalogue, [{"name", "screenshot", "variations": [names]}].
  • GET /design/templates/<template>/variations/<name>/ → that variation’s variables.
  • PATCH /design/ with any of:
    • template: switch template. Unless variation is also given, the new template’s default variation is applied, since variables are specific to a template family.
    • variation: switch color scheme within the (new or current) template.
    • vars: override individual variables of the resulting scheme, e.g. {"palette-brand-color": "#0066A7"}. Unknown variable names are a 422 listing the available ones. Values are plain CSS values (up to 512 characters, with a small set of forbidden characters); for the SCSS-compiled templates (miranda, miranda-thin, molly) they are compiled before saving, so a value that would break the site’s stylesheet is a 422.
  • POST /design/preview/ takes the same body, validates it, and returns preview_url: the site rendered with that design but nothing saved. It needs only design:read. Open the link while logged in to the site’s admin: the unsaved variables are only applied for a logged-in admin.

GET /design/ also reports consistent: whether the stored color scheme belongs to the current template. A template’s CSS only reads its own variable names, so a scheme carried over from another template renders nothing; the API never writes such a state, and any PATCH on a site already in it rebuilds the scheme from the catalogue first (problem says what was wrong).

Switching away from a legacy template records previous_template so the admin’s revert still works. Changes appear in the site’s settings history. Some content features depend on the template (for example tiles and featured agents on anna-modern); the admin hides them for other designs.

Site settings

/api/v3/settings/

Scopes: settings:read / settings:write. The settings a site owner can change in the admin (Website Settings), with JSON-native values. Anything else in the site’s configuration is not readable or writable here.

  • GET /settings/ returns every editable setting; GET /settings/<NAME>/ one.
  • PATCH /settings/ with {"NAME": value, ...} changes only the settings you send. null (or "") removes the site’s own value so the setting falls back to the inherited default; required settings cannot be cleared. The response lists the settings you sent, updated.

Each setting looks like:

{"name": "LEAD_CAPTURE_ON_PROPERTY",
 "label": "Lead Capture On Property",
 "group": "Advanced Site Settings",
 "description": "...",
 "type": "choice",
 "choices": [0, 1, 2, 3, 4, 5, 10],
 "value": 1,
 "overridden": false,
 "inherited_value": 1,
 "required": false,
 "depends": {}}

type is one of string, email, color, file (a site file path), boolean, integer, integer_list, list (of strings), object, yaml, choice. depends names other settings whose values must allow this one (as the admin form does); the API rejects a change that violates it. Changes are recorded in the site’s settings history and take effect on the live site within a few seconds.

Files

/api/v3/files/

Scopes: files:read / files:write. The site’s uploaded files (what the admin’s Manage Files page shows), served from https://u.realgeeks.media/. Paths are relative to the site’s folder, e.g. images/logo.png; the root is "".

  • GET /files/?path=<folder> lists a folder’s entries (folders first). ?q=<text> searches names across all folders. Pages hold up to page_size (default 100, max 500) entries; follow next_cursor with ?cursor= when present.
  • GET /files/<path>/ returns one entry; DELETE /files/<path>/ deletes a file, or a folder and everything in it. If storage refuses some objects the call is a 502 and those entries stay listed for a retry.
  • POST /files/upload/ uploads a file, either as multipart/form-data (file, plus path, optional name, overwrite) or as JSON {"path", "name", "content_type", "content_base64", "overwrite"?}. Max 8,000,000 bytes (JSON uploads are limited to about 2.5 MB of base64 body; use multipart for larger files). Allowed types, by extension: jpg/jpeg, png, gif, ico, mp4, pdf, txt, css. Files are served inline from a domain shared by every site, so HTML, SVG, XML and scripts cannot be uploaded here (use the admin). The stored content_type follows the extension; a content_type that contradicts it is a 422. Whitespace and slashes in names become _. An existing name is a 409 unless overwrite is true; a folder of that name is always a 409.
  • POST /files/folders/ with {"path", "name"} creates a folder.
  • POST /files/move/ with {"from", "to", "overwrite"?} moves or renames a file (folders cannot be moved).

An entry:

{"name": "logo.png",
 "path": "images/logo.png",
 "type": "file",
 "url": "https://u.realgeeks.media/.../logo.png",
 "size": 12345,
 "content_type": "image/png",
 "last_modified":
   "2026-09-02T18:00:00+00:00",
 "dimensions": {"width": 400,
                "height": 200},
 "thumbnail_url":
   "https://t.realgeeks.media/resize/140x/..."}

Use an entry’s url wherever a file is referenced: facebook_image on posts, image src in HTML, and file-typed site settings such as HEADER_LOGO and FAVICON.