Replace the preset in a space

Embed
Preview of the card
<a href="https://forumulate.com/reference/forumulate-api-spacesettings-setpreset"><img src="https://forumulate.com/reference/_api/public/orgs/046a9bc0-d530-43ae-9bae-af7945008cda/spaces/8042f004-e3d9-445f-b7a4-b6c1f86836e6/pages/3a7504f8-cce7-4d87-9cb7-0e356a90909a/social-card.svg?v=3e7ae33eec8b" alt="Replace the preset in a space" width="600" height="315"></a>
PUThttps://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/preset

The layouts each type accepts. preset and piecePreset are validated against the space's own type, so the same word is legal for one space and a 422 for another. The same list is served as data by GET /space-types/{type}/presets (and GET /space-types/presets for all of them at once), which is the one to read if you are generating configuration. That route answers FOUR vocabularies — presets, piecePresets, shapePresets and frontDoor (the keys the type's front door accepts, and the values each one takes).

Space type

Field

Value

What it looks like

DOCS

preset

guide (default)

The page tree beside the writing, an on-this-page rail, and previous/next at the foot.

DOCS

preset

reference

The tree and the page, nothing else — for material read in a hurry by somebody who knows why.

DOCS

preset

minimal

Just the page — no tree, no rail. For docs that are really one document.

DOCS

preset

landing

A front door: your intro, a search box, and each section as a card. Pages inside keep the Guide layout.

FORUM

preset

categories (default)

Category cards on the way in, threads inside each.

FORUM

preset

firehose

One stream, newest first — no cards on the way in. For communities that live in the flow.

FORUM

preset

dense

The stat table a big community reads at a glance: title and tags on the left, replies, views and freshness in columns.

BLOG

preset

feed (default)

One column, newest first, with the standfirst under each headline.

BLOG

preset

grid

A card grid led by the cover images.

BLOG

preset

magazine

The newest post writ large, the rest as a grid beneath it.

BLOG

piecePreset

article-clean (default)

Nothing beside the words; more to read waits at the end.

BLOG

piecePreset

article-toc

An on-this-page rail to the right — for long, structured pieces.

BLOG

piecePreset

article-suggested

Other posts down the left, magazine-style.

BLOG

piecePreset

article-rail

Authors, date and sharing in a rail down the left; title and body beside it.

BLOG

piecePreset

article-meta-rail

The words first, with date, read time, tags and page actions in a rail to the right.

BLOG

piecePreset

article-margin

An offset column with a wide right margin for contents and sidenotes.

BLOG

piecePreset

article-split

The cover beside the title and standfirst, then the body.

ROADMAP

preset

board (default)

Columns by status, cards within them.

ROADMAP

preset

list

One column, grouped by status — reads top to bottom, best for long boards.

CHANGELOG

preset

timeline (default)

Every entry in one dated line, newest first.

CHANGELOG

preset

releases

Entries grouped under the version that shipped them.

CHANGELOG

preset

gutter

Dates in a left column on a timeline rail, each release beside its date.

CHANGELOG

preset

rows

One ruled line per release: date, type, title and tags, newest first.

STATUS

preset

standard (default)

Current state on top, incident history beneath.

LEGAL

preset

standard (default)

The documents, in the order you put them, as a ruled list.

LEGAL

preset

split

A large heading and intro in a column on the left, the documents ruled on the right with a Read button each.

LEGAL

preset

cards

Each document as a card with its description, grouped under your collections — for a register of many policies.

LEGAL

preset

no-front-door

No index page — each document is its own address, linked from wherever you use it.

FAQ

preset

sectioned (default)

Every answer open, grouped by topic, each with an anchor to link to.

FAQ

preset

accordion

Questions closed until asked — for a long list scanned by eye.

FAQ

preset

help-centre

A search hero, category cards, popular questions and contact — each category’s questions on its own page.

FAQ

preset

two-column

Heading, intro and contact on the left, the questions as an accordion on the right — the pricing-page FAQ.

CAREERS

preset

list (default)

Every open role in one list, location and kind beside each.

CAREERS

preset

departments

Roles grouped under the team they join, with how many each has open.

CAREERS

preset

table

One table with a column each for team, location and type — for a long list.

CAREERS

preset

cards

Each role a card, two to a row, its facts as chips — for a handful of roles.

CAREERS

piecePreset

single (default)

The role, then the apply form under it, with an Apply bar that stays in reach.

CAREERS

piecePreset

split

The role beside a column that stays in view: its facts, Apply and share.

CAREERS

piecePreset

tabs

Overview and Application as two tabs — the form one click from anywhere.

CONTACT

preset

standard (default)

Your words above the form, expectations beside it.

CONTACT

preset

split

Your pitch and facts on the left, the form in a card on the right that stays in view (Vercel, Intercom).

CONTACT

preset

router

Topic cards first; the form opens on the one somebody picks, or the card sends them where that topic is answered (Linear).

CONTACT

preset

steps

Email and topic first, the rest after Continue — a short first step people finish (Stripe).

EVENTS

preset

standard (default)

Upcoming events as cards with a date tile and a picture, the last few past events beneath.

EVENTS

preset

luma

Events grouped under each day, Upcoming and Past as tabs; the event page puts the cover beside the details.

EVENTS

preset

community

A month-by-month timeline with hosts and who is going; a wide banner and an RSVP bar on phones.

EVENTS

preset

conference

A grid of wide covers; each event opens on a full-width hero with a countdown.

EVENTS

preset

webinar

Rows with a video thumbnail, recordings in the past half, every time also in the reader’s zone.

COURSES

preset

standard (default)

A hero with the start button, modules of lessons with a progress bar, and the outline beside every lesson.

COURSES

preset

tutorial

Numbered chapters, a chapter badge over each lesson and a “Next up” card at its end.

COURSES

preset

video

A wide cover over a stats strip, and the lessons as a table with their times.

COURSES

preset

cohort

The pitch beside a sticky panel with the facts and the button; the syllabus folded by module.

COURSES

preset

path

The lessons as a winding path of nodes, with a chunky progress bar.

CUSTOM

preset

landing (default)

The space is one page: its address shows your home page full width, with nothing round it but your header and footer.

CUSTOM

preset

pages

A small site: each top-level page is a link in the header, and every page is full width with no sidebar.

CUSTOM

preset

article

A long read such as a security or trust page: the page tree, an on-this-page rail, a breadcrumb and the date it was updated.

CONTENT

preset

headless (default)

No reader of its own: your website fetches entries through the delivery API and renders them itself.

Requires token scope: write (the coarse method gate) for Atlas key (ak_), Personal Access Token (cft_) or OAuth (cfo_) auth — in addition to any catalog scope (GET /pats/scopes) the route’s capability needs. Session/cookie auth is governed by RBAC capabilities instead.

Parameters
orgIdstringpathrequired
spaceIdstringpathrequired
forumulate-versionstringheader
API version negotiation. Send forumulate-version: 2026-12-01 on every request from a new integration; it is optional only so that integrations written before versioning keep working. Each version includes everything before it:
Idempotency-Keystringheader
Makes this write safe to retry. Optional — send any unique string (a UUID is ideal) and the first request runs while its response is remembered under that key for 24 hours; an identical retry replays that same status and body instead of acting twice, so a timeout or a 5xx from the edge can be retried without creating a second row. A retry sent while the first request is still in flight is refused with 409. The key is scoped to the method and path, so the same key on a different endpoint is a different request. Error responses of 5xx are never cached — those retries re-run. A key is bound to the BODY it was first used with: reusing it with a different body is a 409 idempotency.key_reused, not a replay, because replaying would tell you a write landed that never ran. Generate one key per request, never per process or per session.
Request body application/json
presetstring
The named layout the space's index wears. Valid values depend on the SPACE's type — see the table in this operation's description, or GET /space-types/{type}/presets. An unknown value is a 422 that lists the ones this type accepts.
piecePresetstring
The named layout ONE piece of the space wears. Only some types offer a choice; for the others any value is a 422 saying so. GET /space-types/{type}/presets lists them per type.
frontDoorobject
The front door's knobs, by key. Only the keys this SPACE's type declares, of the kind it declares — a toggle takes a boolean, a choice takes one of its values — plus sectionOrder. An unknown key is a 422 that names it and lists the ones this type has. GET /space-types/{type}/presets serves the whole set as data under frontDoor.
{
  "preset": "string",
  "piecePreset": "string",
  "frontDoor": {}
}
Code samples
cURL
curl -X PUT "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/preset" \
  -H "forumulate-version: <value>" \
  -H "Idempotency-Key: <value>" \
  -H "Content-Type: application/json" \
  -d '{"preset":"string","piecePreset":"string","frontDoor":{}}'
TypeScript
const res = await fetch('https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/preset', {
  method: 'PUT',
  headers: {
    'forumulate-version': '<value>',
    'Idempotency-Key': '<value>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"preset":"string","piecePreset":"string","frontDoor":{}}),
});
const data = await res.json();
Python
import requests

res = requests.request(
    "PUT",
    "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/preset",
    headers={
    "forumulate-version": "<value>",
    "Idempotency-Key": "<value>",
    "Content-Type": "application/json",
    },
    json={"preset": "string", "piecePreset": "string", "frontDoor": {}},
)
data = res.json()
Go
package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

func main() {
	req, _ := http.NewRequest("PUT", "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/preset", strings.NewReader(`{"preset":"string","piecePreset":"string","frontDoor":{}}`))
	req.Header.Set("forumulate-version", "<value>")
	req.Header.Set("Idempotency-Key", "<value>")
	req.Header.Set("Content-Type", "application/json")
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/preset');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['forumulate-version: <value>', 'Idempotency-Key: <value>', 'Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"preset":"string","piecePreset":"string","frontDoor":{}}');
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Ruby
require 'net/http'
require 'uri'

uri = URI('https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/preset')
req = Net::HTTP::Put.new(uri)
req['forumulate-version'] = '<value>'
req['Idempotency-Key'] = '<value>'
req['Content-Type'] = 'application/json'
req.body = '{"preset":"string","piecePreset":"string","frontDoor":{}}'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
  http.request(req)
end
puts res.body
Java
import java.net.URI;
import java.net.http.*;
import java.net.http.HttpRequest.BodyPublishers;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/preset"))
    .header("forumulate-version", "<value>")
    .header("Idempotency-Key", "<value>")
    .header("Content-Type", "application/json")
    .method("PUT", BodyPublishers.ofString("{\"preset\":\"string\",\"piecePreset\":\"string\",\"frontDoor\":{}}"))
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
200 Success.
Example
{
  "frontDoor": {},
  "piecePreset": "string",
  "preset": "string",
  "warnings": [
    "tags: \"Launch Day\" is stored as \"launch-day\""
  ]
}
Schema
frontDoorobject
piecePresetstring
presetstring
warningsstring[]
Values we ACCEPTED and then rewrote, one sentence each — a slugified tag, a normalised colour, a clamped range, a slug that was taken. Absent when nothing was rewritten, never []. The same sentences are on the X-Field-Warnings response header. If this is present, something you sent is not what is stored; read the resource back rather than assuming your own value.
400 The request could not be understood — a malformed header, path or query value (request.malformed). A value that was understood but is not acceptable is a 422 validation.failed.
Example
{
  "error": {
    "code": "string",
    "message": "string",
    "details": {},
    "docs": "string",
    "reason": "string",
    "slugs": [
      "string"
    ],
    "conflict": {
      "etag": "string",
      "ops": [
        null
      ]
    }
  },
  "requestId": "string"
}
Schema
errorobjectrequired
Show child parameters
codestringrequired
Stable, machine-readable error code, e.g. rbac.forbidden.
messagestringrequired
Human-readable explanation.
detailsobject
Field-level validation problems, keyed by field path (422 only).
docsstring
Where the vocabulary or format this error is about is published — an absolute URL, or an API route such as GET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.
reasonstring
Why a credential was refused, as one stable word, where one status has several causes — e.g. an external_jwt redeem answers iat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.
slugsstring[]
The exact slugs that collided, on a slug-conflict 409 — space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.
conflictobject
On a 409 from a content entry field write (PATCH …/entries/{entryId}/fields) whose If-Match was stale.
Show child parameters
etagstringrequired
The entry's current fields etag.
opsarrayrequired
The field operations since your If-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.
requestIdstring
The id of this request — the same value as the x-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.
401 No credential, or one that is expired or revoked (auth.required). Send a Bearer token or the session cookie.
Example
{
  "error": {
    "code": "string",
    "message": "string",
    "details": {},
    "docs": "string",
    "reason": "string",
    "slugs": [
      "string"
    ],
    "conflict": {
      "etag": "string",
      "ops": [
        null
      ]
    }
  },
  "requestId": "string"
}
Schema
errorobjectrequired
Show child parameters
codestringrequired
Stable, machine-readable error code, e.g. rbac.forbidden.
messagestringrequired
Human-readable explanation.
detailsobject
Field-level validation problems, keyed by field path (422 only).
docsstring
Where the vocabulary or format this error is about is published — an absolute URL, or an API route such as GET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.
reasonstring
Why a credential was refused, as one stable word, where one status has several causes — e.g. an external_jwt redeem answers iat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.
slugsstring[]
The exact slugs that collided, on a slug-conflict 409 — space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.
conflictobject
On a 409 from a content entry field write (PATCH …/entries/{entryId}/fields) whose If-Match was stale.
Show child parameters
etagstringrequired
The entry's current fields etag.
opsarrayrequired
The field operations since your If-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.
requestIdstring
The id of this request — the same value as the x-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.
403 Authenticated, and not allowed — always rbac.forbidden, whether what is missing is the capability, the token scope, or a resource the token is pinned away from. The message names the capability and, for a scope refusal, the scopes that would grant it. A refusal because of the PLAN is a 402 with quota.exceeded, not this.
Example
{
  "error": {
    "code": "string",
    "message": "string",
    "details": {},
    "docs": "string",
    "reason": "string",
    "slugs": [
      "string"
    ],
    "conflict": {
      "etag": "string",
      "ops": [
        null
      ]
    }
  },
  "requestId": "string"
}
Schema
errorobjectrequired
Show child parameters
codestringrequired
Stable, machine-readable error code, e.g. rbac.forbidden.
messagestringrequired
Human-readable explanation.
detailsobject
Field-level validation problems, keyed by field path (422 only).
docsstring
Where the vocabulary or format this error is about is published — an absolute URL, or an API route such as GET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.
reasonstring
Why a credential was refused, as one stable word, where one status has several causes — e.g. an external_jwt redeem answers iat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.
slugsstring[]
The exact slugs that collided, on a slug-conflict 409 — space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.
conflictobject
On a 409 from a content entry field write (PATCH …/entries/{entryId}/fields) whose If-Match was stale.
Show child parameters
etagstringrequired
The entry's current fields etag.
opsarrayrequired
The field operations since your If-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.
requestIdstring
The id of this request — the same value as the x-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.
404 No such thing — one of the ids in the path does not resolve, or resolves to something this caller may not see (*.not_found).
Example
{
  "error": {
    "code": "string",
    "message": "string",
    "details": {},
    "docs": "string",
    "reason": "string",
    "slugs": [
      "string"
    ],
    "conflict": {
      "etag": "string",
      "ops": [
        null
      ]
    }
  },
  "requestId": "string"
}
Schema
errorobjectrequired
Show child parameters
codestringrequired
Stable, machine-readable error code, e.g. rbac.forbidden.
messagestringrequired
Human-readable explanation.
detailsobject
Field-level validation problems, keyed by field path (422 only).
docsstring
Where the vocabulary or format this error is about is published — an absolute URL, or an API route such as GET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.
reasonstring
Why a credential was refused, as one stable word, where one status has several causes — e.g. an external_jwt redeem answers iat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.
slugsstring[]
The exact slugs that collided, on a slug-conflict 409 — space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.
conflictobject
On a 409 from a content entry field write (PATCH …/entries/{entryId}/fields) whose If-Match was stale.
Show child parameters
etagstringrequired
The entry's current fields etag.
opsarrayrequired
The field operations since your If-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.
requestIdstring
The id of this request — the same value as the x-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.
422 The body was understood and a value is unacceptable (validation.failed). error.details names the field paths.
Example
{
  "error": {
    "code": "string",
    "message": "string",
    "details": {},
    "docs": "string",
    "reason": "string",
    "slugs": [
      "string"
    ],
    "conflict": {
      "etag": "string",
      "ops": [
        null
      ]
    }
  },
  "requestId": "string"
}
Schema
errorobjectrequired
Show child parameters
codestringrequired
Stable, machine-readable error code, e.g. rbac.forbidden.
messagestringrequired
Human-readable explanation.
detailsobject
Field-level validation problems, keyed by field path (422 only).
docsstring
Where the vocabulary or format this error is about is published — an absolute URL, or an API route such as GET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.
reasonstring
Why a credential was refused, as one stable word, where one status has several causes — e.g. an external_jwt redeem answers iat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.
slugsstring[]
The exact slugs that collided, on a slug-conflict 409 — space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.
conflictobject
On a 409 from a content entry field write (PATCH …/entries/{entryId}/fields) whose If-Match was stale.
Show child parameters
etagstringrequired
The entry's current fields etag.
opsarrayrequired
The field operations since your If-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.
requestIdstring
The id of this request — the same value as the x-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.
429 Rate limited — see the RateLimit-* headers.
Example
{
  "error": {
    "code": "string",
    "message": "string",
    "details": {},
    "docs": "string",
    "reason": "string",
    "slugs": [
      "string"
    ],
    "conflict": {
      "etag": "string",
      "ops": [
        null
      ]
    }
  },
  "requestId": "string"
}
Schema
errorobjectrequired
Show child parameters
codestringrequired
Stable, machine-readable error code, e.g. rbac.forbidden.
messagestringrequired
Human-readable explanation.
detailsobject
Field-level validation problems, keyed by field path (422 only).
docsstring
Where the vocabulary or format this error is about is published — an absolute URL, or an API route such as GET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.
reasonstring
Why a credential was refused, as one stable word, where one status has several causes — e.g. an external_jwt redeem answers iat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.
slugsstring[]
The exact slugs that collided, on a slug-conflict 409 — space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.
conflictobject
On a 409 from a content entry field write (PATCH …/entries/{entryId}/fields) whose If-Match was stale.
Show child parameters
etagstringrequired
The entry's current fields etag.
opsarrayrequired
The field operations since your If-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.
requestIdstring
The id of this request — the same value as the x-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.
default Error — the stable { error: { code, message } } envelope.
Example
{
  "error": {
    "code": "string",
    "message": "string",
    "details": {},
    "docs": "string",
    "reason": "string",
    "slugs": [
      "string"
    ],
    "conflict": {
      "etag": "string",
      "ops": [
        null
      ]
    }
  },
  "requestId": "string"
}
Schema
errorobjectrequired
Show child parameters
codestringrequired
Stable, machine-readable error code, e.g. rbac.forbidden.
messagestringrequired
Human-readable explanation.
detailsobject
Field-level validation problems, keyed by field path (422 only).
docsstring
Where the vocabulary or format this error is about is published — an absolute URL, or an API route such as GET /space-types/{type}/presets. Present on errors over a controlled list, so the answer to "what am I allowed to send?" is in the error itself.
reasonstring
Why a credential was refused, as one stable word, where one status has several causes — e.g. an external_jwt redeem answers iat_too_old, iat_in_future, bad_signature, bad_issuer, bad_audience, expired and more. Branch on this, not on message.
slugsstring[]
The exact slugs that collided, on a slug-conflict 409 — space.slug_taken, page.slug_taken, collection.slug_taken, site.slug_taken or badge.slug_taken.
conflictobject
On a 409 from a content entry field write (PATCH …/entries/{entryId}/fields) whose If-Match was stale.
Show child parameters
etagstringrequired
The entry's current fields etag.
opsarrayrequired
The field operations since your If-Match that touch a path your own operations touch. Empty: none did — retry the batch unchanged under etag. null: the history no longer reaches your tag — re-read the entry first.
requestIdstring
The id of this request — the same value as the x-request-id and x-forumulate-request-id response headers. Quote it in a bug report: it is the only thing that finds your exact request in our logs. It is in the body because that is the part that survives — an SDK that throws the parsed body, a serverless log that keeps the body and drops the headers, a ticket with the JSON pasted in.
The Forumulate teamUpdated