Sites: one header, footer and theme over many spaces

Embed
Preview of the card
<a href="https://forumulate.com/guides/sites"><img src="https://forumulate.com/guides/_api/public/orgs/046a9bc0-d530-43ae-9bae-af7945008cda/spaces/36aa4df0-1e95-4cef-8ae9-795169441345/pages/6a2215e5-1889-4450-8249-214678518165/social-card.svg?v=3e7ae33eec8b" alt="Sites: one header, footer and theme over many spaces" width="600" height="315"></a>

A site gathers several public spaces under one address and gives them one header, one footer and one theme. It is what you want when a brand publishes docs, a changelog, a blog and a forum and all four have to look like the same product.

Without a site, each space carries its own chrome and its own theme, and you keep seven copies of the same design in step by hand. With one, the site holds the design and the spaces hold the content.

This page is the schema and the calls. Theme your site covers the theme keys themselves; Custom domains covers pointing a hostname at what you build here.

The calls

Call

What it does

GET /orgs/{orgId}/sites

Every site in the organization.

POST /orgs/{orgId}/sites

Create one.

GET /orgs/{orgId}/sites/{siteId}

One site, with its full stored config.

PATCH /orgs/{orgId}/sites/{siteId}

Change it. config deep-merges (see below).

PUT /orgs/{orgId}/sites/{siteId}

Replace it. config is stored exactly as sent.

DELETE /orgs/{orgId}/sites/{siteId}

Remove the site. The spaces survive it.

POST /orgs/{orgId}/sites/{siteId}/staging

Hide it behind a preview token, or publish it.

PATCH /orgs/{orgId}/sites/{siteId}/theme/draft

Change the site theme as a DRAFT; POST …/theme/draft/publish makes it live. See Theme drafts.

GET /orgs/{orgId}/sites/{siteId}/domains

Its custom domains.

POST /orgs/{orgId}/sites/{siteId}/domains

Add one.

GET /public/orgs/{orgId}/sites/{slug}

What an anonymous reader is served.

Writes need space.update (space.create for the POST); reads need space.read.

Create one

POST /orgs/{orgId}/sites
{
  "slug": "docs",
  "name": "Acme",
  "spaceIds": ["3f2a…", "9c71…"],
  "config": { "tagline": "Everything about Acme" }
}

spaceIds is optional. An empty site is a legitimate thing to create, and usually the right first move — see Spaces join your oldest site below.

slug follows the same rule as a space slug: lowercase letters, digits and single inner dashes.

The config schema

Every key is optional. Together they are the header, the footer and the theme every space in the site wears.

Key

Shape

What it is

tagline

string, ≤ 200

A line under the site name on its landing page.

cta

{ label, href }

The button on the right of the header. label ≤ 60, href ≤ 2048.

headerLinks

up to 12 nav items

Items in the top bar, beside the space navigation. Below.

headerSpaceIds

up to 50 space ids

Which spaces appear in the top bar, in order. Unset = all of them, or none once headerLinks is set (your links replace the automatic tabs); [] = none.

tabs

up to 20 × { title, slug, spaceIds }

Named groups of spaces. Spaces in no tab fall under "More".

footerLinks

up to 20 × { label, href }

A flat row of footer links.

footerColumns

up to 12 × { heading, links, stack }, ≤ 20 links each

A real multi-column footer. The link field is label, not title.

footerDescription

string, ≤ 400

A blurb under the name in the footer.

socialLinks

up to 10 × { platform, href }

Badged profile links. platform is from the fixed list.

copyright

string, ≤ 200

The legal line at the very bottom.

footer

{ logo, logoMark, cookieLinkPlacement, html, css, htmlPlacement, newsletter }

The footer's own lockup, where "Cookie settings" sits, your own footer HTML and a newsletter row. Below.

mobileNav

"menu" | "bar"

Phone header: hamburger (default), or the inline bar.

theme

a full theme object

The site-wide look. Every space inherits it.

Every chrome key a space takes

A site's config is validated by the same schema as a lone space's theme.chrome, with tagline, tabs, headerSpaceIds and theme added. So every key in Header and footer (chrome) is accepted here at the top level of config, with the same shapes and limits. That includes the ones not listed in the table above:

Key

What it does on a site

sticky

The site header follows the reader down the page

height

compact | standard | tall: the header row's size

align

split | left | center

ctaStyle

solid | pill | outline | link

showSignIn

false removes our reader sign-in control from the site header

themeToggle

{ show, style, position, radius, activeColor, hideOn, phone }: the light/dark control in the site header. style: "cycle" is one icon button; hideOn: ["desktop"] hides it on a wide screen; phone: "row" puts it in the phone header row instead of the menu

secondaryCta

A second header button beside cta, with its own style

header

How the header bar looks: overlay, height, border, shadow, blur, logo, nav type

navMenu

How the header's dropdowns and mega menus open and look

sidebarBrand

The default for every space in the site's docs rail. A space's own chrome.sidebarBrand beats it

Because it is the same schema, an href in cta, headerLinks, footerLinks or footerColumns refuses a javascript: URL here, as it does on a space.

See A second button, The header's appearance and Navigation menus in the theming guide for each one's fields.

An item is { label, href } at its simplest — every list ever stored is still valid — and may also take:

Field

Shape

What it is

label

string, 1–60

The word in the bar. Required.

href

URL, ≤ 2048

Where the word goes. Optional when the item has children or a panel.

children

1–12 links

A simple dropdown list.

panel

a mega menu (columns, featured, footer) or { html, css }

What the item opens instead of a list. Not with children.

style

"link" | "button" | "outline"

link is the default.

highlight

boolean

Draw it in the brand's ink and a heavier weight.

The full shapes, the panel's own limits and the navMenu behaviour are in Navigation menus.

config.footer

The footer's own two decisions, in one object so "footer": null takes the whole layer off again. Identical to a lone space's theme.chrome.footer — the same schema validates both — and inside a site it is this copy that renders, like every other chrome key here.

Field

Shape

What it is

logo

https URL / data image, "", false

The footer wordmark. Unset or "" = the header's logoUrl; false = none.

logoMark

https URL / data image, "", false

The square mark. Unset or "" = the header's logoMark; false = none.

cookieLinkPlacement

"bottom" | "brand" | "columns"

Where "Cookie settings" sits. bottom is the default.

html

string, ≤ 20,000

Your own footer markup, sanitised — no scripts, no form controls.

css

string, ≤ 10,000

CSS for html, scoped so it cannot reach the rest of the page.

htmlPlacement

"above" | "below" | "replace"

Where html sits relative to the columns. above is the default.

newsletter

{ formId, heading? }

A one-row email form from the Forms area. heading ≤ 120.

cookieLinkPlacement moves the consent control; nothing removes it. It is only drawn where there is something to consent to: a consent provider configured for the organization, or a page that loads an analytics tag or an opt-in chat widget. See the theming guide for both keys in full, including why there is no value that hides it. html, css, htmlPlacement and newsletter are described in Your own footer HTML, and a newsletter row.

A space left out of headerSpaceIds stays completely reachable — footer links, sitemap, search, its own URL. It is only off the top bar, which is the point: a brand with fourteen spaces does not want fourteen tabs.

theme.chrome is refused, on purpose

A space that belongs to no site keeps its header and footer inside its theme, at theme.chrome. A site does not. A site's chrome is the top level of config — headerLinks, cta, footerColumns, socialLinks, copyright, mobileNav, themeToggle — and the site's chrome is what renders for every space in it.

The same goes for a MEMBER space's own theme.chrome and whiteLabel: inside the site they are stored and not drawn. The space's theme read and write say so — ignoredInSite: ["chrome", "whiteLabel"] (the ones it sets; present only while the space is in a site) and a site.ignored warning per key naming the site. They apply again if the space leaves the site.

So config.theme.chrome used to validate, store, come back in the read-back, and be rendered by nothing. It is now a 422 that names the right key:

{
  "error": {
    "code": "validation.failed",
    "message": "A site's header and footer are not part of its theme. Move these keys up to `config` itself.",
    "details": {
      "config.theme.chrome": ["A site's chrome is the top level of `config` — …"],
    },
  },
}

Everything else inside config.theme is a normal theme and is held to the same strict rule as PATCH …/theme: an unrecognised key is a 422 naming its full path (config.theme.palette.primayr) rather than a silent drop.

PATCH merges config, it does not replace it

PATCH /orgs/{orgId}/sites/{siteId}
{ "config": { "cta": { "label": "Start free", "href": "/signup" } } }

That changes the CTA and leaves the theme, the tabs, the footer columns and the header links exactly as they were. config deep-merges onto what is stored:

  • nested objects merge (config.theme.palette.primary on its own is fine),

  • arrays and scalars replace — headerLinks: [] removes every header link, because an ordered list a human arranged has no honest merge,

  • an explicit null clears a key, at any depth: {"config": {"cta": null}} removes the header button, {"config": {"footer": {"logo": null}}} goes back to the header's wordmark, and {"config": {"theme": {"logoUrl": null}}} clears the site's logo.

null is refused (422) in one place: inside an array element, such as {"config": {"footerColumns": [{"heading": null}]}}. Arrays replace wholesale, so a null there would be stored rather than applied. Send the array without the entry instead. POST …/sites takes no null at all, because there is nothing stored yet to clear.

These are the same semantics PATCH …/theme has, deliberately: patching config.theme.primaryColor and patching theme.primaryColor mean the same thing.

name and spaceIds are not merged. name is a scalar, and spaceIds is the membership list — send it whole, or leave it out.

PUT replaces config, and ?dryRun=true shows you first

A publisher that keeps its site config in a repository wants "make it exactly this", not "merge this in" — with PATCH, a key you deleted from your file stays live until you send a null for it. PUT is that call:

PUT /orgs/{orgId}/sites/{siteId}?dryRun=true
{ "name": "Numera", "config": { "headerLinks": [ … ], "footer": { … } } }

name and config are required; every config key you leave out is removed. spaceIds is optional even here — membership is not configuration, and omitting it keeps the current members.

Add ?dryRun=true (to PUT or PATCH) and every check a real write runs still runs, nothing is stored, and the answer is the site as it would be plus a diff, sorted by path:

{
  "site": { … },
  "dryRun": true,
  "diff": [
    { "path": "footer.art", "op": "remove", "from": "glow" },
    { "path": "headerLinks", "op": "change", "from": [ … ], "to": [ … ] },
  ],
}

Objects are compared key by key; arrays compare whole, because an array here is an ordered list a person arranged.

This used to replace the whole config. A patch carrying only header links dropped the site theme stored beside it, which is how a white-labelled site started saying "Published with Forumulate" again. Nothing announced it: the 200 echoed the small object you sent. If you have code written against the old behaviour that re-sends the whole config every time, it still works — a full config merged over itself is itself.

Read before you write

GET /orgs/{orgId}/sites/{siteId} returns one site with its whole stored config. Use it as the read half of a read-modify-write, and to confirm what a patch actually left behind.

{
  "site": {
    "id": "…",
    "slug": "docs",
    "name": "Acme",
    "spaceIds": ["…"],
    "config": { … },
    "staging": false,
    "stagingToken": null,
    "createdAt": "2026-02-11T09:14:02.000Z",
  },
}

The site's front page

A site's own front door is a composed document, stored on the site with PUT /orgs/{orgId}/sites/{siteId}/front-page (and GET/DELETE on the same address). It renders at the site's root: / of a whole-host domain, /shop/ of a domain mounted at /shop, or /s/{orgId}/{siteSlug} on our own address. Until you store one it is generated: the search band, then the sections band. DELETE goes back to that.

What a site's front page accepts

Block

On a site's front page

spaceBand

Two bands only: search (the search box across the site's spaces) and sections (each space's collections and pages, or your tabs when the site has some). Any other band is a 422 naming the two.

spaceFeed

Must name its space by id. Only a space in this site is drawn. A feed of an organization space you left off the site, or a feed with no space, renders nothing.

spaceCategories, spaceLeaderboard

The same rule: they name a community that is in the site.

every other block

As on any page: headings, a hero, section bands, cards, columns. This is how you put your own words on the site's door.

The usual composition is a magazine feed of the blog, a compact feed of the changelog and a spaceCategories of the community. A feed of a space a reader may not see renders nothing to them.

The page opens with the site's name as its heading and tagline under it, then the document. Every front-page setting a space's front door honours, the site's honours too:

Key

What it does on the site's front page

hideTitle: true

No name-and-tagline heading: you compose your own. The name stays the page's <h1> for search engines and screen readers, visually hidden, unless your document has an <h1> of its own

sidebar, aside

A rail beside the page, and a second rail on the right of a left sidebar

width

How wide the page runs: list, board (unset), max, full, or a px number

gap

The room between top-level bands: none, sm, md, lg

paddingTop, paddingBottom

The room above the page and under it

customization

CSS, share card, JSON-LD

A site's front page and each space's front page

They are separate pages and never replace each other.

  • The site's front page is the address of the site itself (/shop/). It has no intro band and no homeDoc. Write its words as ordinary blocks in its document.

  • Each space keeps its own front page at its own address inside the site (/shop/blog, /shop/help). It is composed with PUT /orgs/{orgId}/spaces/{spaceId}/front-page and accepts that type's own bands (see the table in Space front pages).

  • A space's homeDoc (PUT …/spaces/{spaceId}/home-doc) is that space's intro. It is drawn by the space's intro band, on the space's own front page, and never on the site's. A DOCS space has no front door unless it uses the Landing preset or a stored front page with an intro band; otherwise it opens on its first page and its homeDoc is not shown at all.

So for a site with a landing page at /shop/ and a blog at /shop/blog: the /shop/ words go in the site's front page, and the blog's intro goes in the blog's homeDoc.

Spaces join your oldest site

A new public space is added to your organization's oldest site automatically, so it appears on your published address without a second call.

This only happens if a site exists. The site is normally made for you at signup, from the surfaces you pick in the welcome wizard — so an organization created through the API, or one whose only site was deleted, has nothing to join and every new space is published nowhere you can link to.

If GET /orgs/{orgId}/sites is empty, make one. spaceIds is optional for exactly this reason: create the site empty and the spaces will fill it as you make them.

A space is joined once, at creation. Flipping a space from PRIVATE to PUBLIC later does not join it — add it with a PATCH.

What a space in a site actually wears

GET /public/orgs/{orgId}/spaces/{spaceId}/chrome

This is the "what furniture does this page have" call, and for a space in a site it answers with the site's chrome and the site theme with the space's own theme layered over it — which is what renders. inSite names the site.

  • theme: the site's, with the space's own winning per field. So a site sets the type and the colours and one space can still be narrower than the rest.

  • chrome: the site's, replacing the space's. A header is one composition; half of each is not a header anybody chose. A space's stored theme.chrome is kept but not rendered while the space is in a site, except chrome.sidebarBrand, which the space's docs rail still reads (over the site's config.sidebarBrand, which is the default).

It used to report the space's own stored chrome here, so checking a site's footer through the API showed an empty one while three columns rendered.

Inside a site there is one header, and it is the site's. Nothing in it merges with a member space's theme.chrome:

  • A member space's own theme.chrome.headerLinks (and the rest of its chrome) is not drawn while the space is in the site. It is stored, and ignoredInSite says so. The site's headerLinks do not merge with it; they replace it on every page of the site.

  • The site's header has two kinds of link. The space links are one per space, the site's own navigation. The owner's links are config.headerLinks.

    • With headerSpaceIds unset and no headerLinks, every space gets a link.

    • With headerLinks set and headerSpaceIds unset, your links replace the space links.

    • With headerSpaceIds set, those spaces are listed, in that order, and your headerLinks appear too. [] lists no spaces.

  • Order. Space links come first, after the brand. The first five sit on the bar and the rest fold behind More; the space you are reading is always swapped onto the bar. Your headerLinks follow, in the order you stored them. By default they sit in the group at the end of the row, with the buttons and controls. header.linksAlign: "start" (or "center") moves them in beside the space links. header.maxLinks folds the extras behind More.

  • A space's own tabs are the one thing a member space adds. A DOCS space with theme.docs.sections.placement: "header" draws its section tabs in the site header's sub-row, ahead of the site's own config.subnav.links. A CUSTOM space on the pages preset draws its pages there the same way. This happens only on that space's pages: the site's top row is unchanged, and the other spaces keep the site's sub-row as it is.

  • Tabs inside the page body are part of that space's page and not of the header. A community's Latest / Top / Categories row and a status page's tabs are examples. They render as they would outside a site.

The announcement: site and space

There is one strip, never two. Inside a site, a page's strip is decided in this order — the space first, then the site:

Space's announcement

Site's announcement

What a reader sees on that space's pages

false

anything

No strip. The space has switched the site's strip off

a strip

anything

The space's strip, whole. It replaces the site's: nothing of the site's (href, button, pages, colours) carries over

unset

a strip

The site's strip

unset

unset or false

No strip

The site's own front page wears the site's strip. The strip is the one theme key that is not layered field by field: every other key of a space's theme still wins per field over the site's.

# This space shows no strip, whatever the site announces:
PATCH /orgs/{orgId}/spaces/{spaceId}/theme   {"announcement": false}
# …and back to the site's strip:
PATCH /orgs/{orgId}/spaces/{spaceId}/theme   {"announcement": null}

null unsets the space's key, so the site's strip shows again; false is the explicit "none". To keep a site-wide strip off only some pages of one space, give the site's strip pages (page and item ids, or "front"), or aim it with audience.

Dismissal is per browser and per address. A dismissed strip is remembered in that browser's local storage under a key made from what the reader saw: level, text, href, lead and the button label. Dismissing it on one page hides the identical strip on every page of the same address, across all the site's spaces. A change to any of those fields shows it again. A danger strip cannot be dismissed unless you set dismissible: true.

Staging

POST /orgs/{orgId}/sites/{siteId}/staging
{ "staging": true }

The response carries a stagingToken. While staging is true the site answers anonymous readers with nothing and the token is the only way in — for building an address before you announce it. {"staging": false} publishes it and discards the token.

Custom domains

A site has its own domain list, separate from a space's: a hostname can point at a whole site rather than at one space.

GET  /orgs/{orgId}/sites/{siteId}/domains
POST /orgs/{orgId}/sites/{siteId}/domains
POST /orgs/{orgId}/sites/{siteId}/domains/subdomain

Verification, activation, the DNS records and the IP allow-list all work exactly as they do for a space — see Custom domains. The only difference is which …/domains you post to.

White-label

config.theme.whiteLabel: true removes "Published with Forumulate" from the site footer, and the credit line from the generated link-preview cards. It is a theme key, so it lives in the site theme and covers every space in the site at once — which is also why losing it to a replacing PATCH was so visible.

The overview a custom front end fetches first

If you render a space's reader yourself, one public call returns the whole navigation: the collections, the glossary, the locales and versions on offer and the chat widgets configured for it.

GET /public/orgs/{orgId}/spaces/{spaceId}

It needs no token and no capability. Called without a reader session or share token, it answers only for what an anonymous reader may see. Take page and collection addresses from the API responses rather than assembling them yourself.

The site's robots.txt

A site's robots.txt is written by the API from the spaces in it, so it follows their settings instead of a fixed file. The web serves it as the site's robots.txt, naming the sitemap of the host it was asked on; the API call behind it is GET /public/orgs/{orgId}/sites/{siteSlug}/robots.txt, which takes an absolute ?sitemap= URL to name on the Sitemap: line. What decides each space's lines:

  • A space that is private, sets seo.noindex, or gates its readers (visitorAuth) gets a Disallow: for its path.

  • A space whose AI ingestion is off (discovery.aiIngestion, or the organization's default) stays open to search engines and gets a Disallow: for the known AI crawlers only.

  • A site with no indexable spaces disallows everything.

It is cached for ten minutes, so a settings change reaches crawlers within that.

In the API

Every operation below is also reachable from the other surfaces without a dedicated command. forumulate api <Operation> calls it from the CLI, the JavaScript SDK has a typed method for each one (the last column names it; the Python and Go clients are generated from the same spec), and an agent reaches the organization-scoped ones through the MCP call_api tool. Where a CLI command or MCP tool exists too, the last column names it. Operation names link to the API reference.

Hub Intro

Operation

Request

What it does

Shortcuts

HubIntro_get

GET /orgs/{orgId}/spaces/{spaceId}/hubs/{kind}/{key}/intro

Get the intro in a space

client.spaces.hubIntro.get()

HubIntro_set

PUT /orgs/{orgId}/spaces/{spaceId}/hubs/{kind}/{key}/intro

Replace the intro in a space

client.spaces.hubIntro.set()

HubIntro_renameSeries

PATCH /orgs/{orgId}/spaces/{spaceId}/hubs/series/{key}

Update the series

client.spaces.hubIntro.renameSeries()

Mcp Discovery

Operation

Request

What it does

Shortcuts

McpDiscovery_aiCatalog

GET /public/orgs/{orgId}/sites/{slug}/ai-catalog

Get the AI catalog in an organization

client.mcp.discovery.aiCatalog()

McpDiscovery_serverCard

GET /public/orgs/{orgId}/sites/{slug}/mcp-server-card

Get the MCP server card in an organization

client.mcp.discovery.serverCard()

Public hubs

Operation

Request

What it does

Shortcuts

Public_hubIntro

GET /public/orgs/{orgId}/spaces/{spaceId}/hubs/{kind}/{key}

Get the hub

client.public.hubIntro()

Public robots.txt

Operation

Request

What it does

Shortcuts

Public_robots

GET /public/orgs/{orgId}/spaces/{spaceId}/robots.txt

File of robots (spaces)

client.public.robots()

Public site

Operation

Request

What it does

Shortcuts

Public_siteOf

GET /public/orgs/{orgId}/spaces/{spaceId}/site

Get the site in a space

client.public.siteOf()

Public sitemap.xml

Operation

Request

What it does

Shortcuts

Public_sitemap

GET /public/orgs/{orgId}/spaces/{spaceId}/sitemap.xml

RSS feed of sitemap

client.public.sitemap()

Public updates

Operation

Request

What it does

Shortcuts

Public_updates

GET /public/orgs/{orgId}/spaces/{spaceId}/updates

List updates in a space

client.public.updates()

Public Cards

Operation

Request

What it does

Shortcuts

PublicCards_socialCardPng

GET /public/orgs/{orgId}/spaces/{spaceId}/social-card.png

File of social card

client.public.cards.socialCardPng()

PublicCards_pageSocialCardPng

GET /public/orgs/{orgId}/spaces/{spaceId}/pages/{pageId}/social-card.png

File of social card (pages)

client.public.cards.pageSocialCardPng()

PublicCards_collectionSocialCardPng

GET /public/orgs/{orgId}/spaces/{spaceId}/c/{collection}/social-card.png

File of social card (c)

client.public.cards.collectionSocialCardPng()

PublicCards_topicSocialCardPng

GET /public/orgs/{orgId}/spaces/{spaceId}/t/{topicId}/social-card.png

File of social card (t)

client.public.cards.topicSocialCardPng()

PublicCards_topicSocialCard

GET /public/orgs/{orgId}/spaces/{spaceId}/t/{topicId}/social-card.svg

Get the social card svg in a space (t)

client.public.cards.topicSocialCard()

PublicCards_socialCard

GET /public/orgs/{orgId}/spaces/{spaceId}/social-card.svg

Get the social card svg in a space

client.public.cards.socialCard()

PublicCards_pageSocialCard

GET /public/orgs/{orgId}/spaces/{spaceId}/pages/{pageId}/social-card.svg

Get the social card svg in a space (pages)

client.public.cards.pageSocialCard()

Public Org

Operation

Request

What it does

Shortcuts

PublicOrg_scriptOrigins

GET /public/orgs/{orgId}/script-origins

List script origins in an organization

client.orgs.public.scriptOrigins()

PublicOrg_get

GET /public/orgs/{orgId}

Get the org (public reader)

client.orgs.public.get()

PublicOrg_about

GET /public/orgs/{orgId}/about

Get the about in an organization

client.orgs.public.about()

Public Reaction

Operation

Request

What it does

Shortcuts

PublicReaction_image

GET /public/orgs/{orgId}/reactions/{slug}

Get the reaction

client.public.reaction.image()

Public Site

Operation

Request

What it does

Shortcuts

PublicSite_overview

GET /public/orgs/{orgId}/sites/{slug}

Get the site (public reader)

client.sites.public.overview()

PublicSite_search

GET /public/orgs/{orgId}/sites/{slug}/search

Get the search in an organization (public reader sites)

client.sites.public.search()

PublicSite_ask

POST /public/orgs/{orgId}/sites/{slug}/ask

Create the ask in an organization (public reader sites)

client.sites.public.ask()

Public Space Index

Operation

Request

What it does

Shortcuts

PublicSpaceIndex_list

GET /public/spaces

List spaces

client.spaces.publicIndex.list()

Site

Operation

Request

What it does

Shortcuts

Site_list

GET /orgs/{orgId}/sites

List sites in an organization

forumulate sites list<br>client.sites.list()

Site_create

POST /orgs/{orgId}/sites

Create a site in an organization

forumulate sites create<br>client.sites.create()

Site_get

GET /orgs/{orgId}/sites/{siteId}

Get the site

forumulate sites get<br>client.sites.get()

Site_replace

PUT /orgs/{orgId}/sites/{siteId}

Replace the site

forumulate sites replace<br>client.sites.replace()

Site_update

PATCH /orgs/{orgId}/sites/{siteId}

Update the site

forumulate sites update<br>client.sites.update()

Site_remove

DELETE /orgs/{orgId}/sites/{siteId}

Delete the site

forumulate sites delete<br>client.sites.remove()

Site_setStaging

POST /orgs/{orgId}/sites/{siteId}/staging

Create the staging in an organization

forumulate sites staging<br>client.sites.setStaging()

Site_listDomains

GET /orgs/{orgId}/sites/{siteId}/domains

List domains in an organization

forumulate sites domains list<br>client.sites.listDomains()

Site_addDomain

POST /orgs/{orgId}/sites/{siteId}/domains

Create a domain in an organization

forumulate sites domains add<br>client.sites.addDomain()

Site_domainSetup

GET /orgs/{orgId}/sites/{siteId}/domains/{domainId}/setup

Get the setup in an organization

forumulate sites domains setup<br>client.sites.domainSetup()

Site_setDomainWww

PUT /orgs/{orgId}/sites/{siteId}/domains/{domainId}/www

Replace the www in an organization

forumulate sites domains www<br>client.sites.setDomainWww()

Site_allocateSubdomain

POST /orgs/{orgId}/sites/{siteId}/domains/subdomain

Create the subdomain in an organization

forumulate sites domains subdomain<br>client.sites.allocateSubdomain()

Site_verifyDomain

POST /orgs/{orgId}/sites/{siteId}/domains/{domainId}/verify

Verify the domain (sites)

forumulate sites domains verify<br>client.sites.verifyDomain()

Site_activateDomain

POST /orgs/{orgId}/sites/{siteId}/domains/{domainId}/activate

Activate the domain (sites)

forumulate sites domains activate<br>client.sites.activateDomain()

Site_removeDomain

DELETE /orgs/{orgId}/sites/{siteId}/domains/{domainId}

Delete the domain (sites)

forumulate sites domains remove<br>client.sites.removeDomain()

Viewer

Operation

Request

What it does

Shortcuts

Viewer_viewer

GET /public/orgs/{orgId}/spaces/{spaceId}/viewer

Get the viewer in a space

client.public.viewer.viewer()

The Forumulate teamUpdated