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. Unlessvariationis 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 a422listing 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 a422.
POST /design/preview/takes the same body, validates it, and returnspreview_url: the site rendered with that design but nothing saved. It needs onlydesign: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 topage_size(default 100, max 500) entries; follownext_cursorwith?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 a502and those entries stay listed for a retry.POST /files/upload/uploads a file, either asmultipart/form-data(file, pluspath, optionalname,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 storedcontent_typefollows the extension; acontent_typethat contradicts it is a422. Whitespace and slashes in names become_. An existing name is a409unlessoverwriteis true; a folder of that name is always a409.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.
