The published status board

Embed
Preview of the card
<a href="https://forumulate.com/reference/forumulate-api-publicstatus-board"><img src="https://forumulate.com/reference/_api/public/orgs/046a9bc0-d530-43ae-9bae-af7945008cda/spaces/8042f004-e3d9-445f-b7a4-b6c1f86836e6/pages/559a4ab3-9651-4d8f-9a32-169b52ba2d31/social-card.svg?v=3e7ae33eec8b" alt="The published status board" width="600" height="315"></a>
GEThttps://forumulate.com/api/public/orgs/{orgId}/spaces/{spaceId}/status

overall and each component's status are the REPORTED state, and three things decide it, in this order: a human's declaredState always wins; then the latest check (a failing one is a major_outage); then measured history is allowed to degrade a passing check — under 99.5% uptime reads degraded and under 97% reads partial_outage, so the headline can no longer contradict the percentage printed beside it. History only ever degrades, never improves, and only once window.sufficient is true (at least 20 checks spanning at least 6 hours). window says what each percentage was actually measured over — samples, daysCovered, spanHours and the first/last check — because uptime alone was being printed beside a hardcoded '90 days'. historyDays are the day keys the history arrays line up with, oldest first. outages are the failing runs our own checks recorded, longer than each monitor's failureThreshold, whether or not anybody opened an incident for them.

Parameters
orgIdstringpathrequired
spaceIdstringpathrequired
sharestringquery
previewstringquery
localestringquery
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:
Code samples
cURL
curl -X GET "https://forumulate.com/api/public/orgs/{orgId}/spaces/{spaceId}/status?share=&preview=&locale=" \
  -H "forumulate-version: <value>"
TypeScript
const res = await fetch('https://forumulate.com/api/public/orgs/{orgId}/spaces/{spaceId}/status?share=&preview=&locale=', {
  method: 'GET',
  headers: {
    'forumulate-version': '<value>',
  },
});
const data = await res.json();
Python
import requests

res = requests.request(
    "GET",
    "https://forumulate.com/api/public/orgs/{orgId}/spaces/{spaceId}/status?share=&preview=&locale=",
    headers={
    "forumulate-version": "<value>",
    },
)
data = res.json()
Go
package main

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

func main() {
	req, _ := http.NewRequest("GET", "https://forumulate.com/api/public/orgs/{orgId}/spaces/{spaceId}/status?share=&preview=&locale=", nil)
	req.Header.Set("forumulate-version", "<value>")
	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/public/orgs/{orgId}/spaces/{spaceId}/status?share=&preview=&locale=');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['forumulate-version: <value>']);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Ruby
require 'net/http'
require 'uri'

uri = URI('https://forumulate.com/api/public/orgs/{orgId}/spaces/{spaceId}/status?share=&preview=&locale=')
req = Net::HTTP::Get.new(uri)
req['forumulate-version'] = '<value>'
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/public/orgs/{orgId}/spaces/{spaceId}/status?share=&preview=&locale="))
    .header("forumulate-version", "<value>")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
200 Success.
Example
{
  "brand": "string",
  "dayThresholds": {
    "operational": 0,
    "partial": 0
  },
  "frontPage": {
    "aside": {
      "doc": {
        "content": null,
        "type": null
      },
      "phone": "after",
      "width": "default"
    },
    "customization": {},
    "doc": {
      "content": [
        null
      ],
      "type": "doc"
    },
    "gap": "lg",
    "hideTitle": true,
    "paddingBottom": "string",
    "paddingTop": "string",
    "preset": "string",
    "sidebar": {
      "divider": {
        "color": null,
        "style": null,
        "width": null
      },
      "doc": {
        "content": null,
        "type": null
      },
      "gap": null,
      "phone": null,
      "position": "left",
      "source": "doc",
      "startAfter": 0,
      "width": "default"
    },
    "width": 0
  },
  "groups": [
    {
      "collapsed": true,
      "description": "string",
      "name": "string",
      "parent": "string"
    }
  ],
  "historyDays": [
    "string"
  ],
  "homeDoc": {},
  "homeDocTranslations": {},
  "incidents": [
    {
      "audience": {
        "groups": [
          null
        ],
        "who": "everyone"
      },
      "autoComplete": true,
      "autoStart": true,
      "body": {},
      "components": [
        {
          "impact": null,
          "monitorId": null,
          "name": null,
          "slug": null
        }
      ],
      "fields": {},
      "id": "string",
      "locale": "string",
      "machineTranslated": true,
      "maintenanceState": "completed",
      "resolvedAt": "string",
      "retroactive": true,
      "scheduledFor": "string",
      "scheduledUntil": "string",
      "severity": "string",
      "startedAt": "string",
      "state": "string",
      "title": "string",
      "updatedAt": "string",
      "updates": [
        {
          "body": null,
          "createdAt": null,
          "id": null,
          "state": null
        }
      ]
    }
  ],
  "languages": [
    "string"
  ],
  "monitors": [
    {
      "declaredState": "degraded",
      "description": "string",
      "display": "bars",
      "failingChecks": 0,
      "group": "string",
      "history": [
        null
      ],
      "historyImpact": [
        "degraded"
      ],
      "historyState": [
        "operational"
      ],
      "historyUptime": [
        null
      ],
      "id": "string",
      "incidentImpact": "degraded",
      "kind": "heartbeat",
      "latencyMs": 0,
      "linkUrl": "string",
      "name": "string",
      "region": "string",
      "slug": "string",
      "startsOn": "string",
      "state": "down",
      "status": "degraded",
      "target": {
        "name": null,
        "spaceId": null,
        "url": null
      },
      "uptime": 0,
      "window": {
        "daysCovered": 0,
        "firstCheckAt": null,
        "lastCheckAt": null,
        "minSamples": 0,
        "minSpanHours": 0,
        "reportedDays": 0,
        "samples": 0,
        "spanHours": 0,
        "sufficient": true
      }
    }
  ],
  "outages": [
    {
      "endedAt": "string",
      "failures": 0,
      "monitorId": "string",
      "monitorName": "string",
      "ongoing": true,
      "startedAt": "string"
    }
  ],
  "overall": "degraded",
  "partnerMaintenance": [
    {
      "component": "string",
      "id": "string",
      "monitorId": "string",
      "name": "string",
      "scheduledFor": "string",
      "scheduledUntil": "string",
      "status": "string",
      "url": "string"
    }
  ],
  "status": "string",
  "window": {
    "daysCovered": 0,
    "firstCheckAt": "string",
    "lastCheckAt": "string",
    "minSamples": 0,
    "minSpanHours": 0,
    "reportedDays": 0,
    "samples": 0,
    "spanHours": 0,
    "sufficient": true
  }
}
Schema
brandstringrequired
dayThresholdsobjectrequired
Show child parameters
operationalnumberrequired
partialnumberrequired
frontPageStoredFrontPagerequired
Show child parameters
asideobject
Show child parameters
docobjectrequired
phonestring
after | hide
widthstring
default | narrow | wide
customizationobject
docobjectrequired
Show child parameters
contentobject[]required
typestringrequired
doc
gapstring
lg | md | none | sm
hideTitleboolean
paddingBottomstring | number
paddingTopstring | number | IndexFrameSteps
presetstring
sidebarobject
Show child parameters
dividerobject
docobjectrequired
gapstring | number
phonestring | object
positionstringrequired
left | none | right
sourcestring
doc | docs-nav
startAfternumber
widthstring
default | narrow | wide
widthnumber | string
groupsobject[]required
Show child parameters
collapsedboolean
descriptionstring
namestringrequired
parentstring
historyDaysstring[]required
homeDocrequired
homeDocTranslationsobject
incidentsIncidentSummary[]required
Show child parameters
audienceobject
Show child parameters
groupsstring[]required
whostringrequired
everyone | groups | signedIn
autoCompletebooleanrequired
autoStartbooleanrequired
bodyobjectrequired
componentsAffectedComponent[]required
Show child parameters
impactstringrequired
degraded | maintenance | major_outage | partial_outage
monitorIdstringrequired
namestringrequired
slugstringrequired
fieldsobjectrequired
idstringrequired
localestring
machineTranslatedboolean
maintenanceStatestringrequired
completed | in_progress | scheduled | verifying
resolvedAtstringrequired
retroactivebooleanrequired
scheduledForstringrequired
scheduledUntilstringrequired
severitystringrequired
startedAtstringrequired
statestringrequired
titlestringrequired
updatedAtstringrequired
updatesIncidentUpdate[]required
Show child parameters
bodystringrequired
createdAtstringrequired
idstring
statestringrequired
languagesstring[]required
monitorsMonitorState[]required
Show child parameters
declaredStatestringrequired
degraded | maintenance | major_outage | operational | partial_outage
descriptionstringrequired
displaystringrequired
bars | hidden-unless-degraded | status
failingChecksnumberrequired
groupstringrequired
historyboolean[]required
historyImpactstring[]required
historyStatestring[]required
historyUptimenumber[]required
idstringrequired
incidentImpactstringrequired
degraded | maintenance | major_outage | partial_outage
kindstringrequired
heartbeat | http | manual | space | statuspage
latencyMsnumberrequired
linkUrlstringrequired
namestringrequired
regionstringrequired
slugstringrequired
startsOnstringrequired
statestringrequired
down | unknown | up
statusstringrequired
degraded | maintenance | major_outage | operational | partial_outage | unknown
targetobjectrequired
Show child parameters
namestringrequired
spaceIdstringrequired
urlstring
uptimenumberrequired
windowobjectrequired
Show child parameters
daysCoverednumberrequired
firstCheckAtstringrequired
lastCheckAtstringrequired
minSamplesnumberrequired
minSpanHoursnumberrequired
reportedDaysnumberrequired
samplesnumberrequired
spanHoursnumberrequired
sufficientbooleanrequired
outagesOutageWindow[]required
Show child parameters
endedAtstringrequired
failuresnumberrequired
monitorIdstringrequired
monitorNamestringrequired
ongoingbooleanrequired
startedAtstringrequired
overallstringrequired
degraded | down | maintenance | unknown | up
partnerMaintenanceStatusPartnerMaintenance[]
Show child parameters
componentstringrequired
idstringrequired
monitorIdstringrequired
namestringrequired
scheduledForstringrequired
scheduledUntilstringrequired
statusstringrequired
urlstringrequired
statusstringrequired
windowobjectrequired
Show child parameters
daysCoverednumberrequired
firstCheckAtstringrequired
lastCheckAtstringrequired
minSamplesnumberrequired
minSpanHoursnumberrequired
reportedDaysnumberrequired
samplesnumberrequired
spanHoursnumberrequired
sufficientbooleanrequired
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.
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.
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