Update the category

Embed
Preview of the card
<a href="https://forumulate.com/reference/forumulate-api-forumtaxonomy-updatecategory"><img src="https://forumulate.com/reference/_api/public/orgs/046a9bc0-d530-43ae-9bae-af7945008cda/spaces/8042f004-e3d9-445f-b7a4-b6c1f86836e6/pages/215c2573-17cd-4ff0-9164-79a5c1a2c442/social-card.svg?v=3e7ae33eec8b" alt="Update the category" width="600" height="315"></a>
PATCHhttps://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/categories/{categoryId}

Changes a category: any field POST …/forum/categories takes, plus its look and topicKind — "question" makes its topics count toward the automatic Q&A look and files new topics there as questions; null clears a field.

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
categoryIdstringpathrequired
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.
spaceIdstringpathrequired
The space: its uuid, or its slug within the organization. It is not decoration on a nested route — an id further down the path that belongs to a DIFFERENT space is a 404, not a cross-space read, which is why the operations that never bound this parameter still had to declare it.
Request body application/json
namestring
descriptionstring
colorstring
parentIdstring
sortOrderinteger
defaultNotificationLevelstring
watching | watching_first_post | tracking | normal | muted
topicTemplateobject
minimumRequiredTagsinteger
defaultTagsstring[]
allowedTagsstring[]
defaultSortstring
logoUrlstring
backgroundUrlstring
numFeaturedTopicsinteger
showSubcategoryListboolean
autoCloseHoursinteger
defaultSlowModeSecondsinteger
requiredTagGroupsobject[]
Show child parameters
tagGroupIdstringrequired
minCountintegerrequired
navigateToFirstPostboolean
defaultListFilterstring
slugstring
iconHeaderIconName | string
An icon name from GET /icons?for=header (see the HeaderIconName enum: our glyphs, the extended set and the brand marks), or an image URL (https://…, /api/assets/…, or a data: PNG/JPEG/WebP/GIF — not SVG). Any other bare word is refused.
emojistring
stylestring
textColorstring
textColorDarkstring
colorDarkstring
subcategoryListStylestring
defaultTopPeriodstring
sortAscendingboolean
aboutTopicIdstring
topicKindstring
translationsobject
{
  "name": "string",
  "description": "string",
  "color": "string",
  "parentId": "string",
  "sortOrder": 0,
  "defaultNotificationLevel": "watching",
  "topicTemplate": {},
  "minimumRequiredTags": 0,
  "defaultTags": [
    "string"
  ],
  "allowedTags": [
    "string"
  ],
  "defaultSort": "latest",
  "logoUrl": "string",
  "backgroundUrl": "string",
  "numFeaturedTopics": 0,
  "showSubcategoryList": true,
  "autoCloseHours": 0,
  "defaultSlowModeSeconds": 0,
  "requiredTagGroups": [
    {
      "tagGroupId": "string",
      "minCount": 0
    }
  ],
  "navigateToFirstPost": true,
  "defaultListFilter": "string",
  "slug": "string",
  "icon": "book",
  "emoji": "string",
  "style": "square",
  "textColor": "string",
  "textColorDark": "string",
  "colorDark": "string",
  "subcategoryListStyle": "rows",
  "defaultTopPeriod": "day",
  "sortAscending": true,
  "aboutTopicId": "string",
  "topicKind": "question",
  "translations": {}
}
Code samples
cURL
curl -X PATCH "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/categories/{categoryId}" \
  -H "forumulate-version: <value>" \
  -H "Idempotency-Key: <value>" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","description":"string","color":"string","parentId":"string","sortOrder":0,"defaultNotificationLevel":"watching","topicTemplate":{},"minimumRequiredTags":0,"defaultTags":["string"],"allowedTags":["string"],"defaultSort":"latest","logoUrl":"string","backgroundUrl":"string","numFeaturedTopics":0,"showSubcategoryList":true,"autoCloseHours":0,"defaultSlowModeSeconds":0,"requiredTagGroups":[{"tagGroupId":"string","minCount":0}],"navigateToFirstPost":true,"defaultListFilter":"string","slug":"string","icon":"book","emoji":"string","style":"square","textColor":"string","textColorDark":"string","colorDark":"string","subcategoryListStyle":"rows","defaultTopPeriod":"day","sortAscending":true,"aboutTopicId":"string","topicKind":"question","translations":{}}'
TypeScript
const res = await fetch('https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/categories/{categoryId}', {
  method: 'PATCH',
  headers: {
    'forumulate-version': '<value>',
    'Idempotency-Key': '<value>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"name":"string","description":"string","color":"string","parentId":"string","sortOrder":0,"defaultNotificationLevel":"watching","topicTemplate":{},"minimumRequiredTags":0,"defaultTags":["string"],"allowedTags":["string"],"defaultSort":"latest","logoUrl":"string","backgroundUrl":"string","numFeaturedTopics":0,"showSubcategoryList":true,"autoCloseHours":0,"defaultSlowModeSeconds":0,"requiredTagGroups":[{"tagGroupId":"string","minCount":0}],"navigateToFirstPost":true,"defaultListFilter":"string","slug":"string","icon":"book","emoji":"string","style":"square","textColor":"string","textColorDark":"string","colorDark":"string","subcategoryListStyle":"rows","defaultTopPeriod":"day","sortAscending":true,"aboutTopicId":"string","topicKind":"question","translations":{}}),
});
const data = await res.json();
Python
import requests

res = requests.request(
    "PATCH",
    "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/categories/{categoryId}",
    headers={
    "forumulate-version": "<value>",
    "Idempotency-Key": "<value>",
    "Content-Type": "application/json",
    },
    json={"name": "string", "description": "string", "color": "string", "parentId": "string", "sortOrder": 0, "defaultNotificationLevel": "watching", "topicTemplate": {}, "minimumRequiredTags": 0, "defaultTags": ["string"], "allowedTags": ["string"], "defaultSort": "latest", "logoUrl": "string", "backgroundUrl": "string", "numFeaturedTopics": 0, "showSubcategoryList": True, "autoCloseHours": 0, "defaultSlowModeSeconds": 0, "requiredTagGroups": [{"tagGroupId": "string", "minCount": 0}], "navigateToFirstPost": True, "defaultListFilter": "string", "slug": "string", "icon": "book", "emoji": "string", "style": "square", "textColor": "string", "textColorDark": "string", "colorDark": "string", "subcategoryListStyle": "rows", "defaultTopPeriod": "day", "sortAscending": True, "aboutTopicId": "string", "topicKind": "question", "translations": {}},
)
data = res.json()
Go
package main

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

func main() {
	req, _ := http.NewRequest("PATCH", "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/categories/{categoryId}", strings.NewReader(`{"name":"string","description":"string","color":"string","parentId":"string","sortOrder":0,"defaultNotificationLevel":"watching","topicTemplate":{},"minimumRequiredTags":0,"defaultTags":["string"],"allowedTags":["string"],"defaultSort":"latest","logoUrl":"string","backgroundUrl":"string","numFeaturedTopics":0,"showSubcategoryList":true,"autoCloseHours":0,"defaultSlowModeSeconds":0,"requiredTagGroups":[{"tagGroupId":"string","minCount":0}],"navigateToFirstPost":true,"defaultListFilter":"string","slug":"string","icon":"book","emoji":"string","style":"square","textColor":"string","textColorDark":"string","colorDark":"string","subcategoryListStyle":"rows","defaultTopPeriod":"day","sortAscending":true,"aboutTopicId":"string","topicKind":"question","translations":{}}`))
	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}/forum/categories/{categoryId}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
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, '{"name":"string","description":"string","color":"string","parentId":"string","sortOrder":0,"defaultNotificationLevel":"watching","topicTemplate":{},"minimumRequiredTags":0,"defaultTags":["string"],"allowedTags":["string"],"defaultSort":"latest","logoUrl":"string","backgroundUrl":"string","numFeaturedTopics":0,"showSubcategoryList":true,"autoCloseHours":0,"defaultSlowModeSeconds":0,"requiredTagGroups":[{"tagGroupId":"string","minCount":0}],"navigateToFirstPost":true,"defaultListFilter":"string","slug":"string","icon":"book","emoji":"string","style":"square","textColor":"string","textColorDark":"string","colorDark":"string","subcategoryListStyle":"rows","defaultTopPeriod":"day","sortAscending":true,"aboutTopicId":"string","topicKind":"question","translations":{}}');
$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}/forum/categories/{categoryId}')
req = Net::HTTP::Patch.new(uri)
req['forumulate-version'] = '<value>'
req['Idempotency-Key'] = '<value>'
req['Content-Type'] = 'application/json'
req.body = '{"name":"string","description":"string","color":"string","parentId":"string","sortOrder":0,"defaultNotificationLevel":"watching","topicTemplate":{},"minimumRequiredTags":0,"defaultTags":["string"],"allowedTags":["string"],"defaultSort":"latest","logoUrl":"string","backgroundUrl":"string","numFeaturedTopics":0,"showSubcategoryList":true,"autoCloseHours":0,"defaultSlowModeSeconds":0,"requiredTagGroups":[{"tagGroupId":"string","minCount":0}],"navigateToFirstPost":true,"defaultListFilter":"string","slug":"string","icon":"book","emoji":"string","style":"square","textColor":"string","textColorDark":"string","colorDark":"string","subcategoryListStyle":"rows","defaultTopPeriod":"day","sortAscending":true,"aboutTopicId":"string","topicKind":"question","translations":{}}'
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}/forum/categories/{categoryId}"))
    .header("forumulate-version", "<value>")
    .header("Idempotency-Key", "<value>")
    .header("Content-Type", "application/json")
    .method("PATCH", BodyPublishers.ofString("{\"name\":\"string\",\"description\":\"string\",\"color\":\"string\",\"parentId\":\"string\",\"sortOrder\":0,\"defaultNotificationLevel\":\"watching\",\"topicTemplate\":{},\"minimumRequiredTags\":0,\"defaultTags\":[\"string\"],\"allowedTags\":[\"string\"],\"defaultSort\":\"latest\",\"logoUrl\":\"string\",\"backgroundUrl\":\"string\",\"numFeaturedTopics\":0,\"showSubcategoryList\":true,\"autoCloseHours\":0,\"defaultSlowModeSeconds\":0,\"requiredTagGroups\":[{\"tagGroupId\":\"string\",\"minCount\":0}],\"navigateToFirstPost\":true,\"defaultListFilter\":\"string\",\"slug\":\"string\",\"icon\":\"book\",\"emoji\":\"string\",\"style\":\"square\",\"textColor\":\"string\",\"textColorDark\":\"string\",\"colorDark\":\"string\",\"subcategoryListStyle\":\"rows\",\"defaultTopPeriod\":\"day\",\"sortAscending\":true,\"aboutTopicId\":\"string\",\"topicKind\":\"question\",\"translations\":{}}"))
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
200 Success.
Example
{
  "category": {
    "aboutTopicId": "string",
    "allowedTags": [
      "string"
    ],
    "autoCloseHours": 0,
    "backgroundUrl": "string",
    "color": "string",
    "colorDark": "string",
    "defaultListFilter": "string",
    "defaultNotificationLevel": "string",
    "defaultSlowModeSeconds": 0,
    "defaultSort": "string",
    "defaultTags": [
      "string"
    ],
    "defaultTopPeriod": "string",
    "description": "string",
    "emoji": "string",
    "formTemplateId": "string",
    "icon": "string",
    "id": "string",
    "logoUrl": "string",
    "minimumRequiredTags": 0,
    "name": "string",
    "navigateToFirstPost": true,
    "numFeaturedTopics": 0,
    "parentId": "string",
    "requiredTagGroups": [
      {
        "minCount": 0,
        "tagGroupId": "string"
      }
    ],
    "showSubcategoryList": true,
    "slug": "string",
    "sortAscending": true,
    "sortOrder": 0,
    "style": "string",
    "subcategoryListStyle": "string",
    "textColor": "string",
    "textColorDark": "string",
    "topicCount": 0,
    "topicKind": "discussion",
    "topicTemplate": {},
    "totalTopicCount": 0,
    "translations": {}
  },
  "warnings": [
    {
      "field": "textColor",
      "message": "string",
      "ratio": 0,
      "required": 0
    }
  ]
}
Schema
categoryobjectrequired
Show child parameters
aboutTopicIdstringrequired
allowedTagsstring[]required
autoCloseHoursnumberrequired
backgroundUrlstringrequired
colorstringrequired
colorDarkstringrequired
defaultListFilterstringrequired
defaultNotificationLevelstringrequired
defaultSlowModeSecondsnumberrequired
defaultSortstringrequired
defaultTagsstring[]required
defaultTopPeriodstringrequired
descriptionstringrequired
emojistringrequired
formTemplateIdstringrequired
iconstringrequired
idstringrequired
logoUrlstringrequired
minimumRequiredTagsnumberrequired
namestringrequired
navigateToFirstPostbooleanrequired
numFeaturedTopicsnumberrequired
parentIdstringrequired
requiredTagGroupsRequiredTagGroup[]required
Show child parameters
minCountnumberrequired
tagGroupIdstringrequired
showSubcategoryListbooleanrequired
slugstringrequired
sortAscendingbooleanrequired
sortOrdernumberrequired
stylestringrequired
subcategoryListStylestringrequired
textColorstringrequired
textColorDarkstringrequired
topicCountnumberrequired
topicKindstringrequired
discussion | question
topicTemplateobjectrequired
totalTopicCountnumberrequired
translationsobjectrequired
warningsCategoryWarning[]
Show child parameters
fieldstringrequired
textColor | textColorDark
messagestringrequired
rationumberrequired
requirednumberrequired
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.
409 Refused because of the state this already is in — a name or slug already taken, a resource that already exists, or a precondition on the thing itself (conflict, *.taken, *.exists). Unlike a 422 the body is fine; unlike a 503 retrying it unchanged will not help.
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