Status monitors

Embed
Preview of the card
<a href="https://forumulate.com/guides/status-monitors"><img src="https://forumulate.com/guides/_api/public/orgs/046a9bc0-d530-43ae-9bae-af7945008cda/spaces/36aa4df0-1e95-4cef-8ae9-795169441345/pages/ce58b4e8-59c3-4e37-9c8f-c2cf917ccc2a/social-card.svg?v=3e7ae33eec8b" alt="Status monitors" width="600" height="315"></a>

A status space watches things and shows readers whether they are up. This page covers the monitors themselves: what each kind checks, where it is checked from, the fields, and in particular expectStatus — which exists because the default rule calls a healthy endpoint down. How the page those monitors feed looks and behaves (its looks, sub-pages, incidents, subscribers and embeds) is in Status pages.

Kinds of monitor

A monitor is a component on the page. Its kind says where its state comes from, and it is fixed at creation.

kind

How it decides

Interval

http (default)

We poll your URL.

60 seconds by default, clamped to 30–3600.

heartbeat

Your job pings us.

3600 seconds by default, clamped to 60–604800.

tcp, udp, icmp, dns, tls, smtp, imap, pop3, domain

A protocol probe of probe.host. See Protocol probes.

As http.

browser

A real browser loads probe.url and looks for probe.selector.

As http.

manual

Nothing probes it. Its state is declaredState, or what an open incident linked to it says, else operational.

—

space

Rolls up another status page of your organization (targetSpaceId): its state and uptime are that page's.

—

statuspage, instatus, betterstack, feed

Mirrors a vendor's public status. See Vendor components.

Read on a schedule.

A heartbeat is up while its last ping is no older than one and a half times its interval, unknown until the first ping arrives, and down after that. Ping it at GET or POST /status/ping/{monitorId}/{token}, which always answers {"ok": boolean}.

Reporting a run that did not go cleanly

A ping with no body is a clean run — exactly what every ping was before this existed. A job that ran but had part of it fail can say so, instead of going silent (which reads as an outage once 1.5× the interval has passed):

curl -X POST "$PING_URL" -H 'content-type: application/json' \
  -d '{"ok": false, "detail": "settle_crypto_invoices failed"}'
# or, from a cron line with no body:
curl "$PING_URL?status=degraded&detail=queue%20lagging"

Field

Effect

ok

false = the component reads partial outage while pings keep arriving. Ignored when status names a state.

status

up (clean), degraded, partial_outage, or major_outage / down. The last records a failed check now, counted toward failureThreshold.

detail

Up to 500 characters. Shown to your organization in the console beside the monitor, never on the public page. Dropped on a clean run.

  • degraded and partial_outage still count as the job being up for the uptime percentage — it ran. They colour the component (and the headline turns degraded), and never make it look better than its history does.

  • The next clean ping clears the report. Silence past the window is still an outage, whatever the last report said.

  • The ping never refuses a body it cannot read: an unparseable body or an unknown status is treated as a clean run (or falls back to ok), because a job whose ping starts failing gets its alerting switched off.

  • Like a missed heartbeat, a reported state does not open an incident on its own.

Reporting a restart

A container that restarts in a few seconds is invisible to a 60-second poll, so the service has to say so itself. Call POST /status/restart/{monitorId}/{token} from your boot or deploy script. It needs no session, because a process that has just started has none; the token is the same secret as the monitor's heartbeat ping URL, so take the monitor's pingUrl and replace /status/ping/ with /status/restart/.

curl -X POST "$RESTART_URL" -H 'content-type: application/json' \
  -d '{"reason": "deploy"}'
  • reason is optional, up to 120 characters, and defaults to restarted.

  • The restart is recorded as a failed check at the database's clock, labelled restart: <reason>, so it shows as a dip in the uptime history beside the checks.

  • It does not raise an alert or open an incident: a deploy is not an outage.

  • A restart within 30 seconds of a failed check already recorded on that monitor is folded into it, so a crash loop does not turn the whole bar into dips.

  • It always answers 200, so a deploy script cannot fail on it: {"ok": true} for a known monitor and a valid token (a folded restart included), and {"ok": false} for a bad token or an unknown monitor, the same answer for both so that neither can be probed for.

kind cannot be changed after creation. PATCH accepts the field and ignores it. To change a kind, delete the monitor and create it again.

Protocol probes

Not everything worth watching answers HTTP: a database port, a mail server, a DNS record, a certificate about to lapse, a domain about to expire. Each of these kinds takes one object, probe, checked against the kind on create and on PATCH; a missing piece is a 422 that names it.

POST /orgs/{orgId}/spaces/{spaceId}/status/monitors
{
  "name": "Primary database",
  "kind": "tcp",
  "probe": { "host": "db.yourcompany.com", "port": 5432 }
}

probe field

Used by

Default

What it does

host

every kind but browser (required)

—

The host name or address. For dns, the name asked about; for domain, the registered domain.

port

tcp, udp (required); tls, smtp, imap, pop3

tls 443, smtp 587, imap 993, pop3 995

The port connected to.

record

dns

A

A, AAAA, CNAME, MX, NS or TXT.

resolver

dns

1.1.1.1

The resolver asked. It must be a public address.

expect

dns, udp

none

dns: the exact answer that means up. udp: text the reply must contain.

payload

udp

none

What is sent, up to 500 characters.

days

tls, domain

none

Down when the certificate (tls) or the registration (domain) has fewer days than this left.

url

browser (required)

—

The page the browser loads.

selector

browser

none

A CSS selector that must appear on the loaded page.

  • Every host must resolve to a public address, exactly as an http URL must; a private or loopback target is refused.

  • The monitor's url is filled in for you as the probe's address (tcp://db.yourcompany.com:5432, dns://1.1.1.1/yourcompany.com?MX, domain:yourcompany.com), which is what the console shows.

  • A PATCH with probe replaces the stored probe whole, judged against the stored kind.

  • keyword, expectStatus and the other HTTP rules are stored and ignored on a probe, as they are on a heartbeat.

Browser checks: what you need to set up

browser monitors run on a browser runner that Forumulate operates. Until it is configured on Forumulate's side, creating a browser monitor answers 422 with "Browser checks need a browser runner, and this platform has none configured yet", and the console does not offer the kind. Nothing on your side needs setting. GET …/status/regions answers browserChecks: true once the runner is there.

Creating one

POST /orgs/{orgId}/spaces/{spaceId}/status/monitors
{
  "name": "API",
  "url": "https://api.yourcompany.com/health",
  "intervalSeconds": 60
}

Field

Type

Default

Notes

name

string, 1–120

required

Falls back to the URL's hostname if you send only whitespace.

url

string, ≤2048

""

For http. Checked against SSRF — a private or loopback address is refused.

method

GET | HEAD | POST

GET

Changeable with PATCH.

kind

http | heartbeat

http

Immutable after creation.

intervalSeconds

integer, 30–604800

60 (http) / 3600 (heartbeat)

Clamped per kind, see above — on PATCH too.

visible

boolean

true

false keeps it off the public board.

group

string, ≤60, nullable

null

Groups monitors under a heading.

keyword

string, ≤120, nullable

null

The body must contain this text.

certExpiryDays

integer, 1–365, nullable

null

Fail when the TLS certificate expires within this many days. https only.

expectStatus

integer, 100–599, nullable

null

See below.

alertsEnabled

boolean

true

On create and PATCH.

failureThreshold

integer, 1–10

3

On create and PATCH.

successThreshold

integer, 1–10

2

On create and PATCH.

declaredState

enum, nullable

null

On create and PATCH. operational, degraded, partial_outage, major_outage, maintenance. Overrides the check.

keywordAbsent

boolean

false

Turns keyword around: the check fails while the text is in the body ("error", "maintenance mode").

maxLatencyMs

integer, 1–120000, nullable

null

A response slower than this counts as down.

requestHeaders

object, nullable

null

Sent with every check. Values are write-only and stored encrypted; reads return the names only.

requestBody

string, ≤4096, nullable

null

Sent with a POST check.

bodyPath / bodyExpect

string, ≤200, nullable

null

A dotted JSON path in the response, and the value it must equal.

probe

object

—

A protocol or browser monitor's target. See Protocol probes.

regions

string[], ≤10

[]

The probe regions it is checked from. Empty: the primary checker only. See Probing from several regions.

confirmRegions

integer, 1–10

1

How many regions must see it failing before it reads down.

paused

boolean

false

Stops probing without deleting it. See below.

barDays

30 | 60 | 90, nullable

null

This component's own day-strip length on the page. null follows the page's theme.status.bars.days.

showUptime

boolean

true

Show its uptime figure beside the strip. false keeps the strip and drops the number.

display

bars | status | hidden-unless-degraded

bars

Its day bars, only its state, or nothing at all until something is wrong with it (a dependency nobody needs to see while it works).

description

string, ≤500, nullable

null

One sentence about what it is, shown to readers beside its name.

slug

string, 1–80

from the name

Its stable address on the page (/components/{slug}, per-component subscriptions). Unique per page; a taken one is a 409. Renaming does not move it.

linkUrl

URL, nullable

null

Its name links here (the component's own docs or product).

region

string, ≤60, nullable

null

Where it runs ("EU", "US-East"). The page can group by it (theme.status.components.groupBy: "region"). Not the same as regions.

startsOn

YYYY-MM-DD, nullable

null

The day it started existing. Earlier days draw as "not yet" rather than as no data.

audience

object

everyone

{ "who": "everyone" | "signedIn" | "groups", "groups": [...] }: who sees it on the public page. The machine doors (summary.json, feeds, badge, widget) always answer as an anonymous reader.

targetSpaceId

uuid

—

Kind space: the status page it rolls up.

vendorComponent

string, ≤200, nullable

null

Vendor kinds: the vendor component's id or exact name. null: the vendor page's overall state.

Pausing a monitor

paused: true is for a component you are working on, not removing. The row and its history stay on the page, no new checks are taken, no alert is sent, and the component reads unknown (or its declaredState) until you set it back to false. alertsEnabled: false is the other thing: it only mutes the alerts while the checks carry on.

The order on the page

Components are drawn in the order you give them:

PUT /orgs/{orgId}/spaces/{spaceId}/status/monitors/order
{ "ids": ["<api-id>", "<web-id>"] }

Components you leave out keep their order after the ones you list, so moving two components can send just those two. An id from another page is a 422.

Update with PATCH /orgs/{orgId}/spaces/{spaceId}/status/monitors/{monitorId}. Send only the fields you are changing; sending a field with the value it already has is a 200 that changes nothing. There is no PUT on a monitor. (PUT …/status/settings is a different thing — the space's status settings.)

expectStatus

What "up" means without it

A monitor is up when both of these hold:

the request connected
and the status code is under 400

Both, and in that order. A request that never connected reports a status of 0, which satisfies "under 400" — so the status condition on its own calls a server that cannot be resolved healthy, which is the one thing a status page exists to notice.

What "up" means with it

the request connected
and the status code is exactly the number you set

The under-400 rule is gone. A monitor with expectStatus: 401 is down on a 200.

Why you would want that

An unauthenticated probe of an API that requires a token answers 401 when it is perfectly healthy. Some answer 405 to a GET they only accept as POST. The under-400 rule called both permanently down, which made the monitor useless and the board a liar.

PATCH /orgs/{orgId}/spaces/{spaceId}/status/monitors/{monitorId}
  { "expectStatus": 401 }

Clearing it

PATCH …/status/monitors/{monitorId}
  { "expectStatus": null }

null is a real value here, and it is the one that restores the default under-400 rule.

Omitting the field does not clear it. An absent key means "leave this alone", so a PATCH that does not mention expectStatus keeps whatever is stored. The two are different on purpose, and they are the thing to get right when a client builds the patch body from a form.

An empty string is a validation error, not a clear. Send null.

What it accepts

A single integer between 100 and 599, or null. Nothing else:

You send

Result

200

Accepted.

null

Accepted. Clears it.

"200"

422. It is a number, not a string.

"200-299"

422. There is no range syntax.

"2xx"

422.

[200, 204]

422. One code, not a list.

999

422. Out of range is refused, not clamped.

0

422.

""

422.

Out of range is refused rather than clamped, because clamping 50 up to 100 would silently decide that only a 100 Continue is healthy.

It is http-only

expectStatus on a heartbeat monitor is accepted, stored, and silently ignored — not refused. A heartbeat has no response to read a status from; its verdict is purely the age of the last ping. keyword and certExpiryDays behave the same way for the same reason.

If you set it on a heartbeat and the board does not change, that is why.

Combining conditions

keyword and certExpiryDays are additional conditions, ANDed on top. So a monitor with expectStatus: 200 and keyword: "ok" is up only when it connected, returned exactly 200, and the body contained ok.

Probing from several regions

A failure seen from one place is often that place: a routing problem between one data centre and your host, not your host. So a component can be checked from several regions, and only read as down once enough of them agree.

GET /orgs/{orgId}/spaces/{spaceId}/status/regions
# { "regions": [ { "key": "primary", "label": "Primary", "live": true, "primary": true },
#                { "key": "eu", "label": "Europe", "live": true, "primary": false } ],
#   "browserChecks": false }

PATCH /orgs/{orgId}/spaces/{spaceId}/status/monitors/{monitorId}
{ "regions": ["primary", "eu"], "confirmRegions": 2 }
  • regions lists the region keys it is probed from. Empty (the default) is the primary checker alone. A list that leaves out the primary's key is checked only from the regions it names.

  • An unknown key is a 422 that names it.

  • The rule: the component is down when at least confirmRegions of the regions that have reported each see it failing failureThreshold times in a row. confirmRegions is capped at the number of regions that have reported, so a component probed from one live region is judged by it alone.

  • Alerts are sent once, not once per region.

  • Every check is stored with the region it ran from.

What readers see: on a page with two or more regions, each component row carries a small dot per region, and the component's own page has a "Checked from" table with each region's latest result (the regions part of theme.status.subpages.component). On a page with one region, neither is drawn.

In the studio: Checks and alerts → Checks, open a check, then Probe from and Regions that must agree it is down.

What you need to set up

Probe regions are run by Forumulate, not by you: each region is a checker host that Forumulate operates and declares on its side (STATUS_PROBE_REGIONS). Until at least one region besides the primary is declared and answering:

  • GET …/status/regions lists only the primary (or lists a declared region with live: false while it is not answering yet),

  • the console does not show the region pickers at all,

  • readers see no region dots and no "Checked from" table,

  • and every component is checked from the primary checker alone, exactly as before regions existed.

There is nothing to configure on your side beyond picking regions once they are offered.

Vendor components

A page can show the services you depend on next to your own. A vendor component reads the vendor's public status and puts it in your page's words:

kind

url

What it reads

statuspage

The vendor's Statuspage page (status.stripe.com)

Its summary.json: one component (vendorComponent) or the overall indicator, plus scheduled maintenance.

instatus

The vendor's Instatus page

Its public status: one component or the whole page.

betterstack

The vendor's Better Stack page

Its public status: one component or the whole page.

feed

An RSS or Atom feed (AWS, Azure, Slack) or Google Cloud's incidents.json

Google Cloud's feed says exactly what is ongoing. An RSS or Atom feed only lists posts, so the newest post, if it is from the last six hours and does not say it is resolved, reads as degraded.

A vendor's maintenance windows (from the kinds that publish them) can be shown on your page with the partners band. See Status pages.

Opening incidents from outside

Your alerting tool already knows when something breaks. An inbound address lets it open (and resolve) an incident on the page:

POST /orgs/{orgId}/spaces/{spaceId}/status/inbound
{ "source": "grafana", "monitorId": "<component id>", "label": "Grafana prod" }

The answer carries the url to paste into the tool as a webhook (or, for email, the address to mail).

source

What it understands

email

A mail to the address opens an incident.

datadog, pagerduty, opsgenie, newrelic, grafana, alertmanager, pingdom, uptimerobot, statuscake

Each tool's own webhook payload: firing opens, resolved resolves.

generic

Any JSON, read through your mapping.

generic takes a mapping of dotted paths into the JSON your tool sends:

mapping key

Default

What it is

key

id

What ties a later "resolved" to the alert it ends.

title

title

The incident's title.

message

message

Its first update.

status

status

The field that says whether it is resolved…

resolvedValue

resolved

…and the value that means it (any case).

severity

severity

The severity.

monitorId names the component the incident affects; unset, it names none.

Metrics

A page can chart numbers beside the components: response time from our own checks, and custom metrics you create (PUT …/status/metrics/{key}). A custom metric's points come from one of two places.

You push them, one at a time or up to 500 at once:

POST /orgs/{orgId}/spaces/{spaceId}/status/metrics/api.p95/points
{ "value": 212 }

A point more than 5 minutes ahead of the server's clock or more than 30 days behind it is refused and counted in rejected.

We pull them from a provider you already use, every everySeconds (default 300, 60–86400):

PUT /orgs/{orgId}/spaces/{spaceId}/status/metrics/api.p95/source
{
  "source": { "provider": "datadog", "query": "avg:trace.http.request.duration{service:api}", "site": "datadoghq.eu" },
  "secret": { "apiKey": "…", "appKey": "…" }
}

provider

source fields

secret keys (write-only)

datadog

query, site

apiKey, appKey

newrelic

accountId, nrql (returning one number), region (us | eu)

apiKey

librato

metric

email, token

pingdom

checkId

token

json

url, path (dotted path to the number)

any request headers

The secret is stored encrypted and never returned: the answer says only which names are set. "source": null stops pulling and keeps the points. In the studio: Checks and alerts → Metrics and embeds, then Pull from.

What you need to set up

A pulled metric needs your own account with the provider and the keys in the table above, entered in the studio or with the call above. Until they are, the metric is charted from whatever you push, and an empty metric draws an empty chart.

What a metric says about itself (PUT …/status/metrics/{key}): name, unit, description, decimals (0–4), aggregate (avg, sum, max, min, last), visible, sortKey, component (the component whose row chart draws it when it has no measured response time), and the chart's axisMin, axisMax and a dashed threshold line.

What a reader sees

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

Field

Notes

overall

up, degraded, maintenance, down or unknown. From each component's state, which by default comes from its latest checks — not from uptime history. stateSource says which rule the page uses (Status pages).

monitors[]

id, name, state, status, declaredState, group, latencyMs, uptime, uptimeOver (its uptime over the newest 30, 60 and 90 days), history.

incidents[]

Open and resolved incidents.

uptime is null, not 0, when nothing has been recorded yet. A percentage is published only once there is enough to stand on: at least 20 checks spanning at least 6 hours (window.minSamples / window.minSpanHours; both halves — 25 checks taken in the first hour still read "Not enough data yet"). Until then window.sufficient is false and the page says so, with the bar. history is 90 day-buckets, oldest first, each true, false or null; a day is true only when it had zero failures.

A reader never sees expectStatus. It is on the authenticated monitor routes and on GET …/status/board, and nowhere public. Only visible: true monitors appear at all.

Other public endpoints:

Path

Notes

GET …/status/summary.json

Statuspage-compatible. Cached 60s.

GET …/status/badge.svg

An uptime badge. Cached 300s.

GET …/status/rss.xml

The incident feed.

POST …/status/subscribe

Double-opt-in email subscription. Rate limited to 5/minute.

A status space that is not PUBLIC answers all of these with a flat 404 unless the request carries a valid rotating share token.

SMS alerts for readers

What you need to set up

Readers can subscribe to a status page by email, Slack, Discord, Microsoft Teams, Google Chat, Telegram or webhook (see Status pages). SMS is offered as well once your organization connects its own Twilio account. There is no shared sending number: texts are sent from yours and billed by Twilio to you. Until the account is connected, the page offers only the other channels. All three routes need org.manage_integrations.

PUT /orgs/{orgId}/sms
{
  "provider": "twilio",
  "accountSid": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "authToken": "your-twilio-auth-token",
  "fromNumber": "+14155550123"
}
  • accountSid must start with AC and be 34 characters.

  • authToken is 16 to 128 characters, write-only and stored encrypted. Omit it on an update to keep the stored one.

  • fromNumber is E.164, with the country code.

  • Unknown keys are refused.

GET /orgs/{orgId}/sms answers { configured, provider, accountSid, fromNumber, updatedAt }, never the token. DELETE /orgs/{orgId}/sms disconnects it and the page stops offering SMS.

A reader's number is verified before anything is sent: the page texts a six-digit code and delivers nothing until it is typed back, so nobody can enrol a number that is not theirs. A number that replies STOP is removed from the subscription instead of being retried.

Monitoring Forumulate itself

The Forumulate API has three unauthenticated health endpoints. Point an http monitor (yours or any other tool's) at the one that answers your question.

  • GET /health/live answers {"status": "ok"} as soon as the process accepts connections and never touches the database or Redis. It tells you the process is up, not that it can serve you.

  • GET /health/ready checks that Postgres and Redis both answer and that the process is not saturated (event-loop lag under one second at p99). It answers {"status": "ok", "db": true, "queue": true} with 200, or "degraded" with 503 when any of those fails. This is the one with a status-code contract.

  • GET /health checks only the database and always answers 200, with {"status": "ok" | "degraded", "db": boolean}. Read the status field; the code stays 200 so a brief blip is not reported as an outage.

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.

Org Sms

Operation

Request

What it does

Shortcuts

OrgSms_get

GET /orgs/{orgId}/sms

The organization’s SMS account (never the token)

client.orgs.sms.get()

OrgSms_set

PUT /orgs/{orgId}/sms

Set the organization’s Twilio account

client.orgs.sms.set()

OrgSms_remove

DELETE /orgs/{orgId}/sms

Remove the organization’s SMS account

client.orgs.sms.remove()

Public Status

Operation

Request

What it does

Shortcuts

PublicStatus_subscribe

POST /public/orgs/{orgId}/spaces/{spaceId}/status/subscribe

Subscribe the status

client.status.public.subscribe()

PublicStatus_board

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

The published status board

client.status.public.board()

PublicStatus_uptimeCsv

GET /public/orgs/{orgId}/spaces/{spaceId}/status/uptime.csv

The uptime report as CSV

client.status.public.uptimeCsv()

PublicStatus_badge

GET /public/orgs/{orgId}/spaces/{spaceId}/status/badge.svg

A status badge (SVG)

client.status.public.badge()

PublicStatus_summary

GET /public/orgs/{orgId}/spaces/{spaceId}/status/summary.json

Statuspage-compatible status summary

client.status.public.summary()

PublicStatus_rss

GET /public/orgs/{orgId}/spaces/{spaceId}/status/rss.xml

RSS feed of the status

client.status.public.rss()

PublicStatus_atom

GET /public/orgs/{orgId}/spaces/{spaceId}/status/atom.xml

Atom feed of the status

client.status.public.atom()

PublicStatus_jsonFeed

GET /public/orgs/{orgId}/spaces/{spaceId}/status/feed.json

JSON feed of the status

client.status.public.jsonFeed()

PublicStatus_maintenanceIcs

GET /public/orgs/{orgId}/spaces/{spaceId}/status/maintenance.ics

File of maintenance

client.status.public.maintenanceIcs()

Public Status Access

Operation

Request

What it does

Shortcuts

PublicStatusAccess_facts

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

Whether a status page is gated

client.status.publicAccess.facts()

PublicStatusAccess_check

GET /public/orgs/{orgId}/spaces/{spaceId}/status/access/check

May this reader read a status page?

client.status.publicAccess.check()

Public Status Alerts

Operation

Request

What it does

Shortcuts

PublicStatusAlerts_options

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

Which alert channels a reader can subscribe with

client.status.publicAlerts.options()

PublicStatusAlerts_start

POST /public/orgs/{orgId}/spaces/{spaceId}/status/alerts

Subscribe a Slack hook, webhook or phone to this status page

client.status.publicAlerts.start()

PublicStatusAlerts_verify

POST /public/orgs/{orgId}/spaces/{spaceId}/status/alerts/{alertId}/verify

Confirm a reader alert with the code it was sent

client.status.publicAlerts.verify()

PublicStatusAlerts_unsubscribe

POST /public/orgs/{orgId}/spaces/{spaceId}/status/alerts/{alertId}/unsubscribe

Stop a reader alert, with the token every delivery carries

client.status.publicAlerts.unsubscribe()

Public Status Embeds

Operation

Request

What it does

Shortcuts

PublicStatusEmbeds_day

GET /public/orgs/{orgId}/spaces/{spaceId}/status/day.json

One component's day, in hourly buckets

client.status.publicEmbeds.day()

PublicStatusEmbeds_latency

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

A status page's response times

client.status.publicEmbeds.latency()

PublicStatusEmbeds_metricSeries

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

A status page's custom metric series

client.status.publicEmbeds.metricSeries()

PublicStatusEmbeds_widgetJson

GET /public/orgs/{orgId}/spaces/{spaceId}/status/widget.json

What is happening on a status page right now

client.status.publicEmbeds.widgetJson()

PublicStatusEmbeds_widgetJs

GET /public/orgs/{orgId}/spaces/{spaceId}/status/widget.js

Get the widget JS in a space (status)

client.status.publicEmbeds.widgetJs()

Public Status Incidents

Operation

Request

What it does

Shortcuts

PublicStatusIncidents_archive

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

A status page's incident archive

client.status.publicIncidents.archive()

PublicStatusIncidents_card

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

One incident on a status page

client.status.publicIncidents.card()

PublicStatusIncidents_one

GET /public/orgs/{orgId}/spaces/{spaceId}/status/incidents/{incidentId}

Get the incident

client.status.publicIncidents.one()

Public Statuspage

Operation

Request

What it does

Shortcuts

PublicStatuspage_summary

GET /public/orgs/{orgId}/spaces/{spaceId}/status/api/v2/summary.json

Statuspage-compatible summary (API v2)

client.status.publicPage.summary()

PublicStatuspage_status

GET /public/orgs/{orgId}/spaces/{spaceId}/status/api/v2/status.json

Statuspage-compatible overall status (API v2)

client.status.publicPage.status()

PublicStatuspage_components

GET /public/orgs/{orgId}/spaces/{spaceId}/status/api/v2/components.json

Statuspage-compatible components and groups (API v2)

client.status.publicPage.components()

PublicStatuspage_incidents

GET /public/orgs/{orgId}/spaces/{spaceId}/status/api/v2/incidents.json

Statuspage-compatible incidents (API v2)

client.status.publicPage.incidents()

PublicStatuspage_unresolved

GET /public/orgs/{orgId}/spaces/{spaceId}/status/api/v2/incidents/unresolved.json

Statuspage-compatible unresolved incidents (API v2)

client.status.publicPage.unresolved()

PublicStatuspage_maintenances

GET /public/orgs/{orgId}/spaces/{spaceId}/status/api/v2/scheduled-maintenances.json

Statuspage-compatible scheduled maintenances (API v2)

client.status.publicPage.maintenances()

PublicStatuspage_upcoming

GET /public/orgs/{orgId}/spaces/{spaceId}/status/api/v2/scheduled-maintenances/upcoming.json

Statuspage-compatible upcoming maintenance (API v2)

client.status.publicPage.upcoming()

PublicStatuspage_active

GET /public/orgs/{orgId}/spaces/{spaceId}/status/api/v2/scheduled-maintenances/active.json

Statuspage-compatible maintenance under way (API v2)

client.status.publicPage.active()

Operation

Request

What it does

Shortcuts

PublicStatusSearch_search

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

Search a status page's incidents

client.status.publicSearch.search()

Public Status Siblings

Operation

Request

What it does

Shortcuts

PublicStatusSiblings_siblings

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

A status page's sibling pages

client.status.publicSiblings.siblings()

Status

Operation

Request

What it does

Shortcuts

Status_updateIncident

PATCH /orgs/{orgId}/spaces/{spaceId}/status/incidents/{incidentId}

Update the incident

forumulate status incidents update<br>client.status.updateIncident()<br>MCP edit_status_component

Status_listChannels

GET /orgs/{orgId}/spaces/{spaceId}/status/channels

List channels in a space (status)

forumulate status channels list<br>client.status.listChannels()

Status_addChannel

POST /orgs/{orgId}/spaces/{spaceId}/status/channels

Create a channel in a space (status)

forumulate status channels add<br>client.status.addChannel()

Status_removeChannel

DELETE /orgs/{orgId}/spaces/{spaceId}/status/channels/{channelId}

Delete the channel (status)

forumulate status channels remove<br>client.status.removeChannel()

Status_monitors

GET /orgs/{orgId}/spaces/{spaceId}/status/monitors

List monitors in a space

forumulate status components list<br>client.status.monitors()<br>MCP list_entities

Status_addMonitor

POST /orgs/{orgId}/spaces/{spaceId}/status/monitors

Add a status monitor

forumulate status components create<br>client.status.addMonitor()

Status_updateMonitor

PATCH /orgs/{orgId}/spaces/{spaceId}/status/monitors/{monitorId}

Update the monitor

forumulate status components update<br>client.status.updateMonitor()<br>MCP edit_status_component

Status_removeMonitor

DELETE /orgs/{orgId}/spaces/{spaceId}/status/monitors/{monitorId}

Delete the monitor

forumulate status components delete<br>client.status.removeMonitor()

Status_getSettings

GET /orgs/{orgId}/spaces/{spaceId}/status/settings

List settings in a space (status)

forumulate status settings<br>client.status.getSettings()

Status_setSettings

PUT /orgs/{orgId}/spaces/{spaceId}/status/settings

Replace settings in a space

forumulate status configure<br>client.status.setSettings()

Status_getGroups

GET /orgs/{orgId}/spaces/{spaceId}/status/groups

List groups in a space

forumulate status groups get<br>client.status.getGroups()

Status_setGroups

PUT /orgs/{orgId}/spaces/{spaceId}/status/groups

Replace groups in a space

forumulate status groups set<br>client.status.setGroups()

Status_board

GET /orgs/{orgId}/spaces/{spaceId}/status/board

Get the board in a space

forumulate status board<br>forumulate status incidents list<br>client.status.board()<br>MCP list_entities

Status_createIncident

POST /orgs/{orgId}/spaces/{spaceId}/status/incidents

Create an incident in a space

forumulate status incidents create<br>client.status.createIncident()

Status_addIncidentUpdate

POST /orgs/{orgId}/spaces/{spaceId}/status/incidents/{incidentId}/updates

Create an update in a space

forumulate status incidents post<br>client.status.addIncidentUpdate()

Status Authoring

Operation

Request

What it does

Shortcuts

StatusAuthoring_regions

GET /orgs/{orgId}/spaces/{spaceId}/status/regions

The probe regions

client.status.authoring.regions()

StatusAuthoring_reorder

PUT /orgs/{orgId}/spaces/{spaceId}/status/monitors/order

Reorder the components

client.status.authoring.reorder()

StatusAuthoring_editUpdate

PATCH /orgs/{orgId}/spaces/{spaceId}/status/incidents/{incidentId}/updates/{updateId}

Correct a posted incident update

client.status.authoring.editUpdate()

StatusAuthoring_deleteUpdate

DELETE /orgs/{orgId}/spaces/{spaceId}/status/incidents/{incidentId}/updates/{updateId}

Delete a posted incident update

client.status.authoring.deleteUpdate()

StatusAuthoring_deleteIncident

DELETE /orgs/{orgId}/spaces/{spaceId}/status/incidents/{incidentId}

Delete an incident

client.status.authoring.deleteIncident()

Status Heartbeat

Operation

Request

What it does

Shortcuts

StatusHeartbeat_pingGet

GET /status/ping/{monitorId}/{token}

Record a heartbeat for a monitor

client.status.heartbeat.pingGet()

StatusHeartbeat_pingPost

POST /status/ping/{monitorId}/{token}

Record a heartbeat for a monitor, by POST

client.status.heartbeat.pingPost()

Status Integrations

Operation

Request

What it does

Shortcuts

StatusIntegrations_listAlerts

GET /orgs/{orgId}/spaces/{spaceId}/status/alerts

List readers’ Slack, webhook and SMS subscriptions

client.status.integrations.listAlerts()

StatusIntegrations_removeAlert

DELETE /orgs/{orgId}/spaces/{spaceId}/status/alerts/{alertId}

Remove a reader’s alert subscription

client.status.integrations.removeAlert()

StatusIntegrations_listInbound

GET /orgs/{orgId}/spaces/{spaceId}/status/inbound

List the addresses that open incidents from outside

client.status.integrations.listInbound()

StatusIntegrations_createInbound

POST /orgs/{orgId}/spaces/{spaceId}/status/inbound

Create an inbound address (email, Datadog or PagerDuty)

client.status.integrations.createInbound()

StatusIntegrations_removeInbound

DELETE /orgs/{orgId}/spaces/{spaceId}/status/inbound/{hookId}

Revoke an inbound address

client.status.integrations.removeInbound()

Status Metrics

Operation

Request

What it does

Shortcuts

StatusMetrics_list

GET /orgs/{orgId}/spaces/{spaceId}/status/metrics

A status page's custom metrics, hidden ones included

client.status.metrics.list()

StatusMetrics_upsert

PUT /orgs/{orgId}/spaces/{spaceId}/status/metrics/{key}

Create a custom metric, or change what it says about itself

client.status.metrics.upsert()

StatusMetrics_remove

DELETE /orgs/{orgId}/spaces/{spaceId}/status/metrics/{key}

Delete a custom metric and every point of it

client.status.metrics.remove()

StatusMetrics_push

POST /orgs/{orgId}/spaces/{spaceId}/status/metrics/{key}/points

Push points to a custom metric

client.status.metrics.push()

Status Slack

Operation

Request

What it does

Shortcuts

StatusSlack_command

POST /public/status/slack/{orgId}

Slack slash command for a status page

client.status.slack.command()

Status Subscribers

Operation

Request

What it does

Shortcuts

StatusSubscribers_list

GET /orgs/{orgId}/spaces/{spaceId}/status/subscribers

A status page's email subscribers

client.status.subscribers.list()

StatusSubscribers_add

POST /orgs/{orgId}/spaces/{spaceId}/status/subscribers

Add an email subscriber

client.status.subscribers.add()

StatusSubscribers_csv

GET /orgs/{orgId}/spaces/{spaceId}/status/subscribers/export.csv

A status page's email subscribers as CSV

client.status.subscribers.csv()

StatusSubscribers_import

POST /orgs/{orgId}/spaces/{spaceId}/status/subscribers/import

Import email subscribers from CSV

client.status.subscribers.import()

StatusSubscribers_resend

POST /orgs/{orgId}/spaces/{spaceId}/status/subscribers/{subscriberId}/resend

Send a pending subscriber a fresh confirmation link

client.status.subscribers.resend()

StatusSubscribers_remove

DELETE /orgs/{orgId}/spaces/{spaceId}/status/subscribers/{subscriberId}

Remove an email subscriber

client.status.subscribers.remove()

Status Templates

Operation

Request

What it does

Shortcuts

StatusTemplates_list

GET /orgs/{orgId}/spaces/{spaceId}/status/templates

List the status page’s incident templates

client.status.templates.list()

StatusTemplates_create

POST /orgs/{orgId}/spaces/{spaceId}/status/templates

Save an incident template

client.status.templates.create()

StatusTemplates_update

PATCH /orgs/{orgId}/spaces/{spaceId}/status/templates/{templateId}

Update the template

client.status.templates.update()

StatusTemplates_remove

DELETE /orgs/{orgId}/spaces/{spaceId}/status/templates/{templateId}

Delete the template

client.status.templates.remove()

StatusTemplates_use

POST /orgs/{orgId}/spaces/{spaceId}/status/templates/{templateId}/incidents

Open an incident from a template

client.status.templates.use()

The Forumulate teamUpdated