Agents & API
REST API reference
99 endpoints, generated from the same operation registry that powers the server, the OpenAPI spec and the MCP tools.
#Basics
| Base URL | https://upbutler.com/api/v1 |
| Auth | Authorization: Bearer ub_live_… with a read or write scope. Get one from the dashboard or POST /agent/bootstrap |
| Format | JSON in, JSON out. Send Content-Type: application/json with bodies |
| Errors | {"error": {"code", "message", "hint?", "details?"}}. See Errors |
| Retries | Idempotency-Key header on POST, replayed for 24 h |
| Live events | GET /api/v1/stream streams workspace events as Server-Sent Events (same auth, types filter, resume with Last-Event-ID). Not part of the OpenAPI spec; see Events |
| Spec | /api/v1/openapi.json (OpenAPI 3.1) |
| IDs | Wherever a pageId is expected, a page slug works too |
Agents · 5Bootstrap, one-call service setup, heartbeats and component pushes.Monitors · 10Create, update, run and inspect monitors, their checks and regions.Status pages · 10Pages, groups and subscribers.Components · 5Rows on status pages, their sources, overrides and batch pushes.Incidents · 18Incidents, updates, acknowledgements, AI analysis, postmortems, templates and maintenance.Alerts · 5Alert channels for your team and agents.Public status · 8Read any public page and subscribe. No key needed.Workspace · 11Workspace, members and API keys.Events · 1The event stream.Billing · 3Plans and upgrades.Import · 4Bring monitors and pages over from UptimeRobot, Better Stack or Statuspage.io.On-call · 13Rotations, overrides and escalation policies.Deploys · 3Deploy markers for incident correlation.Digest · 3Weekly digest settings and previews. #Agents
#Create a workspace + API key with no human in the loop
POST/api/v1/agent/bootstrap
Public — no keyMCP agent_bootstrapReturns 201
For autonomous agents. Returns an API key immediately and a claim URL. Give the claim URL to your human: unclaimed workspaces are deleted after 7 days, and email features unlock once claimed. Rate-limited per IP.
| Field | Type | Description |
|---|
agentNamerequired | string | Who you are, e.g. "claude-code" or "deploy-bot"max length 80 |
workspaceName | string | max length 80 |
curl -X POST https://upbutler.com/api/v1/agent/bootstrap \
-H "Content-Type: application/json" \
-d '{
"agentName": "..."
}'
#Plug in a service: monitor + status page component in one call
POST/api/v1/services
API key · writeMCP services_addReturns 201
The fastest path: creates a monitor for the URL (or a heartbeat when you pass periodSec), creates the status page if needed (statusPage = slug or name), and adds a component that follows the monitor. Returns everything you need, including heartbeat ping URLs.
| Field | Type | Description |
|---|
namerequired | string | Human-friendly name, e.g. "Search API"max length 120 |
description | string | null | null or "" clears itmax length 1,000 · nullable |
kind | string | Inferred when omitted: url → http, host+port → tcp, periodSec → heartbeathttptcpdnsheartbeatmanifestscriptbrowser |
url | string (url) | http/manifest: URL to checkmax length 2,000 |
method | string | GETHEADPOSTPUTPATCHDELETEOPTIONS |
headers | map<string, string> | |
body | string | null | null clears itmax length 100,000 · nullable |
followRedirects | boolean | |
expectedStatus | string | e.g. "200-299" (default), "200,204", "401"max length 100 |
keyword | string | http: response body must contain this textmax length 500 |
keywordAbsent | string | http: response body must NOT contain this textmax length 500 |
degradedAfterMs | integer | null | Mark degraded when slower than this (null clears)min 50 · max 120,000 · nullable |
sslExpiryDays | integer | null | Mark degraded when the TLS cert expires within N days (null clears)min 1 · max 365 · nullable |
host | string | tcp/dns hostmax length 255 |
port | integer | min 1 · max 65,535 |
recordType | string | AAAAACNAMEMXTXTNS |
expected | string[] | dns: values that must be presentmax 20 items |
periodSec | integer | heartbeat: expected ping intervalmin 30 · max 2,678,400 |
graceSec | integer | heartbeat: extra time before alertingmin 0 · max 86,400 |
code | string | script/browser: test codemax length 50,000 |
viewport | object | |
viewport.widthrequired | integer | min 320 · max 3,840 |
viewport.heightrequired | integer | min 240 · max 2,160 |
assertions | object[] | max 30 items |
assertions[].sourcerequired | string | statuslatencyheaderbodyjsonssl_days |
assertions[].path | string | max length 300 |
assertions[].oprequired | string | eqneqltltegtgtecontainsnot_containsmatchesexistsnot_exists |
assertions[].value | string | number | boolean | max length 2,000 |
assertions[].severity | string | downdegraded |
intervalSec | integer | Seconds between checks (default 60, limited by plan)min 10 · max 86,400 |
timeoutMs | integer | min 1,000 · max 120,000 |
failureThreshold | integer | Consecutive failures before DOWN (default 2)min 1 · max 10 |
recoveryThreshold | integer | min 1 · max 10 |
channelIds | string[] | Alert channels. Default: channels marked as defaultmax 50 items |
reminderMinutes | integer[] | max 10 items |
ai | boolean | AI incident analysis (default true) |
tags | string[] | max 20 items |
paused | boolean | |
regions | string[] | Check regions (GET /api/v1/regions). With several, a round only counts as DOWN when a majority of regions agree. Default: main region onlymax 10 items |
statusPage | string | Status page slug or id; created (by name) if it does not exist. Omit to only monitor.max length 100 |
group | string | Component group on the status page, e.g. "APIs"max length 80 |
componentName | string | Public name (defaults to name)max length 100 |
curl -X POST https://upbutler.com/api/v1/services \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Search API",
"url": "https://api.example.com/health",
"statusPage": "acme",
"group": "APIs"
}'
#Send a heartbeat (no API key needed — the token is the secret)
POST/api/v1/heartbeat/:token
Public — no keyMCP heartbeat_pingReturns 200
Call at least every periodSec. status=down (or POST to /hb/{token}/fail) reports an explicit failure and alerts immediately. Short form: GET/POST https://upbutler.com/hb/{token}.
| Field | Type | Description |
|---|
tokenrequiredpath | string | |
status | string | updowndegraded |
message | string | max length 500 |
durationMs | integer | How long the job tookmin 0 |
curl -X POST https://upbutler.com/api/v1/heartbeat/hb_Xf3kq9LmR2vT8wYzN4bC1dE7
#Push one component status by its push token (no API key needed)
POST/api/v1/push/:token
Public — no keyMCP components_pushReturns 200
| Field | Type | Description |
|---|
tokenrequiredpath | string | |
statusrequired | string | boolean | number | operational | degraded | partial_outage | major_outage | maintenance, or ok/up/fail/down/true/false |
message | string | max length 500 |
confirmed | boolean | Skip blip protection: the sender already confirmed this status |
observedAt | any | When this status was observed; re-sending the same observation does not count as a new confirmation |
curl -X POST https://upbutler.com/api/v1/push/push_Qm7vB2xK9pL4sT1nW8cZ3yH6 \
-H "Content-Type: application/json" \
-d '{
"status": "degraded",
"message": "p95 latency above 2s"
}'
#Identify the calling key
GET/api/v1/agent/whoami
API key · readMCP agent_whoamiReturns 200
No parameters.
curl https://upbutler.com/api/v1/agent/whoami \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Monitors
#List monitors
GET/api/v1/monitors
API key · readMCP monitors_listReturns 200
All monitors in the workspace with their current state and last check.
| Field | Type | Description |
|---|
statequery | string | updowndegradedpendingpaused |
tagquery | string | |
curl https://upbutler.com/api/v1/monitors \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Create a monitor
POST/api/v1/monitors
API key · writeMCP monitors_createReturns 201
Create an uptime monitor. Minimal input is {"name","url"}. Kinds: http (status/keyword/JSON/latency/TLS assertions), tcp, dns, heartbeat (your job pings us), manifest (one JSON endpoint reporting many components), script, browser.
| Field | Type | Description |
|---|
namerequired | string | Human-friendly name, e.g. "Search API"max length 120 |
description | string | null | null or "" clears itmax length 1,000 · nullable |
kind | string | Inferred when omitted: url → http, host+port → tcp, periodSec → heartbeathttptcpdnsheartbeatmanifestscriptbrowser |
url | string (url) | http/manifest: URL to checkmax length 2,000 |
method | string | GETHEADPOSTPUTPATCHDELETEOPTIONS |
headers | map<string, string> | |
body | string | null | null clears itmax length 100,000 · nullable |
followRedirects | boolean | |
expectedStatus | string | e.g. "200-299" (default), "200,204", "401"max length 100 |
keyword | string | http: response body must contain this textmax length 500 |
keywordAbsent | string | http: response body must NOT contain this textmax length 500 |
degradedAfterMs | integer | null | Mark degraded when slower than this (null clears)min 50 · max 120,000 · nullable |
sslExpiryDays | integer | null | Mark degraded when the TLS cert expires within N days (null clears)min 1 · max 365 · nullable |
host | string | tcp/dns hostmax length 255 |
port | integer | min 1 · max 65,535 |
recordType | string | AAAAACNAMEMXTXTNS |
expected | string[] | dns: values that must be presentmax 20 items |
periodSec | integer | heartbeat: expected ping intervalmin 30 · max 2,678,400 |
graceSec | integer | heartbeat: extra time before alertingmin 0 · max 86,400 |
code | string | script/browser: test codemax length 50,000 |
viewport | object | |
viewport.widthrequired | integer | min 320 · max 3,840 |
viewport.heightrequired | integer | min 240 · max 2,160 |
assertions | object[] | max 30 items |
assertions[].sourcerequired | string | statuslatencyheaderbodyjsonssl_days |
assertions[].path | string | max length 300 |
assertions[].oprequired | string | eqneqltltegtgtecontainsnot_containsmatchesexistsnot_exists |
assertions[].value | string | number | boolean | max length 2,000 |
assertions[].severity | string | downdegraded |
intervalSec | integer | Seconds between checks (default 60, limited by plan)min 10 · max 86,400 |
timeoutMs | integer | min 1,000 · max 120,000 |
failureThreshold | integer | Consecutive failures before DOWN (default 2)min 1 · max 10 |
recoveryThreshold | integer | min 1 · max 10 |
channelIds | string[] | Alert channels. Default: channels marked as defaultmax 50 items |
reminderMinutes | integer[] | max 10 items |
ai | boolean | AI incident analysis (default true) |
tags | string[] | max 20 items |
paused | boolean | |
regions | string[] | Check regions (GET /api/v1/regions). With several, a round only counts as DOWN when a majority of regions agree. Default: main region onlymax 10 items |
curl -X POST https://upbutler.com/api/v1/monitors \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Search API",
"url": "https://api.example.com/health",
"keyword": "\"ok\"",
"intervalSec": 60
}'
#Get a monitor with recent checks and stats
GET/api/v1/monitors/:id
API key · readMCP monitors_getReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | Monitor id (mon_...) |
checksquery | integer | min 0 · max 200 |
curl https://upbutler.com/api/v1/monitors/mon_0n3q8kz1m4hx7c2v9rt \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Update a monitor
PATCH/api/v1/monitors/:id
API key · writeMCP monitors_updateReturns 200
Partial update; any create field may be sent. Set paused=true/false to pause or resume.
| Field | Type | Description |
|---|
idrequiredpath | string | Monitor id (mon_...) |
name | string | Human-friendly name, e.g. "Search API"max length 120 |
description | string | null | null or "" clears itmax length 1,000 · nullable |
kind | string | Inferred when omitted: url → http, host+port → tcp, periodSec → heartbeathttptcpdnsheartbeatmanifestscriptbrowser |
url | string (url) | http/manifest: URL to checkmax length 2,000 |
method | string | GETHEADPOSTPUTPATCHDELETEOPTIONS |
headers | map<string, string> | |
body | string | null | null clears itmax length 100,000 · nullable |
followRedirects | boolean | |
expectedStatus | string | e.g. "200-299" (default), "200,204", "401"max length 100 |
keyword | string | http: response body must contain this textmax length 500 |
keywordAbsent | string | http: response body must NOT contain this textmax length 500 |
degradedAfterMs | integer | null | Mark degraded when slower than this (null clears)min 50 · max 120,000 · nullable |
sslExpiryDays | integer | null | Mark degraded when the TLS cert expires within N days (null clears)min 1 · max 365 · nullable |
host | string | tcp/dns hostmax length 255 |
port | integer | min 1 · max 65,535 |
recordType | string | AAAAACNAMEMXTXTNS |
expected | string[] | dns: values that must be presentmax 20 items |
periodSec | integer | heartbeat: expected ping intervalmin 30 · max 2,678,400 |
graceSec | integer | heartbeat: extra time before alertingmin 0 · max 86,400 |
code | string | script/browser: test codemax length 50,000 |
viewport | object | |
viewport.widthrequired | integer | min 320 · max 3,840 |
viewport.heightrequired | integer | min 240 · max 2,160 |
assertions | object[] | max 30 items |
assertions[].sourcerequired | string | statuslatencyheaderbodyjsonssl_days |
assertions[].path | string | max length 300 |
assertions[].oprequired | string | eqneqltltegtgtecontainsnot_containsmatchesexistsnot_exists |
assertions[].value | string | number | boolean | max length 2,000 |
assertions[].severity | string | downdegraded |
intervalSec | integer | Seconds between checks (default 60, limited by plan)min 10 · max 86,400 |
timeoutMs | integer | min 1,000 · max 120,000 |
failureThreshold | integer | Consecutive failures before DOWN (default 2)min 1 · max 10 |
recoveryThreshold | integer | min 1 · max 10 |
channelIds | string[] | Alert channels. Default: channels marked as defaultmax 50 items |
reminderMinutes | integer[] | max 10 items |
ai | boolean | AI incident analysis (default true) |
tags | string[] | max 20 items |
paused | boolean | |
regions | string[] | Check regions (GET /api/v1/regions). With several, a round only counts as DOWN when a majority of regions agree. Default: main region onlymax 10 items |
curl -X PATCH https://upbutler.com/api/v1/monitors/mon_0n3q8kz1m4hx7c2v9rt \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Delete a monitor and its history
DELETE/api/v1/monitors/:id
API key · writeMCP monitors_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | Monitor id (mon_...) |
curl -X DELETE https://upbutler.com/api/v1/monitors/mon_0n3q8kz1m4hx7c2v9rt \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Run a check right now
POST/api/v1/monitors/:id/check
API key · writeMCP monitors_checkReturns 200
Runs the monitor immediately and returns the full result with evidence. Does not change monitor state unless apply=true.
| Field | Type | Description |
|---|
idrequiredpath | string | Monitor id (mon_...) |
apply | boolean | Feed the result into the state machine (may open/resolve incidents) |
curl -X POST https://upbutler.com/api/v1/monitors/mon_0n3q8kz1m4hx7c2v9rt/check \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#List checks (raw results, 30 days)
GET/api/v1/monitors/:id/checks
API key · readMCP monitors_checksReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | Monitor id (mon_...) |
outcomequery | string | updegradeddown |
beforequery | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
limitquery | integer | min 1 · max 500 |
evidencequery | boolean | string | |
curl https://upbutler.com/api/v1/monitors/mon_0n3q8kz1m4hx7c2v9rt/checks \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Get one check with full evidence
GET/api/v1/checks/:id
API key · readMCP checks_getReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl https://upbutler.com/api/v1/checks/chk_0n3q9a10e9n3p5s7hz2 \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#List check regions and probe health
GET/api/v1/regions
API key · readMCP regions_listReturns 200
Regions monitors can be checked from (use the ids in a monitor's "regions"). With several regions a round only counts as DOWN when a majority of the reporting regions agree; regions whose probe is unhealthy are skipped, never counted as failures.
No parameters.
curl https://upbutler.com/api/v1/regions \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Per-region latency and failures for a monitor
GET/api/v1/monitors/:id/regions
API key · readMCP monitors_regionsReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | Monitor id (mon_...) |
hoursquery | integer | min 1 · max 168 |
curl https://upbutler.com/api/v1/monitors/mon_0n3q8kz1m4hx7c2v9rt/regions \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Status pages
#List status pages
GET/api/v1/pages
API key · readMCP pages_listReturns 200
No parameters.
curl https://upbutler.com/api/v1/pages \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Create a status page
POST/api/v1/pages
API key · writeMCP pages_createReturns 201
Theme presets: midnight, grid, daylight, paper. Add components afterwards with POST /pages/{pageId}/components.
| Field | Type | Description |
|---|
namerequired | string | max length 100 |
slug | string | pattern ^[a-z0-9](?:[a-z0-9-]{1,46}[a-z0-9])?$ |
description | string | max length 500 |
customDomain | string | null | pattern ^(?=.{4,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$ · nullable |
visibility | string | publicprivate |
theme | object | |
theme.preset | string | max length 30 |
theme.mode | string | darklight |
theme.accent | string | pattern ^#[0-9a-fA-F]{6}$ |
theme.tokens | map<string, string> | |
theme.fontSans | string | max length 40 |
theme.fontMono | string | max length 40 |
theme.radius | integer | min 0 · max 24 |
theme.customCss | string | max length 50,000 |
branding | object | |
branding.logoUrl | string | null | max length 1,000 · nullable |
branding.logoDarkUrl | string | null | max length 1,000 · nullable |
branding.logoText | string | null | max length 60 · nullable |
branding.faviconUrl | string | null | max length 1,000 · nullable |
branding.websiteUrl | string (url) | null | max length 500 · nullable |
branding.supportUrl | string (url) | null | max length 500 · nullable |
branding.headerLinks | object[] | max 8 items |
branding.headerLinks[].labelrequired | string | max length 60 |
branding.headerLinks[].urlrequired | string (url) | max length 500 |
branding.footerLinks | object[] | max 20 items |
branding.footerLinks[].labelrequired | string | max length 60 |
branding.footerLinks[].urlrequired | string (url) | max length 500 |
branding.footerText | string | null | max length 300 · nullable |
branding.hidePoweredBy | boolean | |
settings | object | |
settings.uptimeDays | integer | min 7 · max 90 |
settings.showUptimePercent | boolean | |
settings.showResponseTimes | boolean | Allow public response-time charts (components opt in with showResponseTimes) |
settings.language | string | Public page + subscriber email language; auto = visitor Accept-Languageautoendefresitptnlelpltrja |
settings.autoIncidents | boolean | |
settings.incidentMinStatus | string | Lowest component status that opens an automatic incidentdegradedpartial_outagemajor_outage |
settings.aiPublicUpdates | boolean | |
settings.aiGuidelines | string | Rules for AI-written public text, e.g. "Never mention internal infrastructure"max length 2,000 |
settings.aiAvoidTerms | string[] | AI public text containing any of these is replaced by a neutral templatemax 50 items |
settings.subscriptions | object | |
settings.subscriptions.email | boolean | |
settings.subscriptions.webhook | boolean | |
settings.subscriptions.slack | boolean | |
settings.subscriptions.rss | boolean | |
settings.timezone | string | max length 60 |
seo | object | |
seo.title | string | max length 120 |
seo.description | string | max length 300 |
seo.noindex | boolean | |
curl -X POST https://upbutler.com/api/v1/pages \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Status",
"slug": "acme",
"theme": {
"preset": "midnight",
"accent": "#22c55e"
}
}'
#Get a status page with components
GET/api/v1/pages/:pageId
API key · readMCP pages_getReturns 200
| Field | Type | Description |
|---|
pageIdrequiredpath | string | Status page id (pg_...) or slug |
curl https://upbutler.com/api/v1/pages/pg_0n3q8kz0b2fd81mka5e \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Update page settings, theme, branding or domain
PATCH/api/v1/pages/:pageId
API key · writeMCP pages_updateReturns 200
| Field | Type | Description |
|---|
name | string | max length 100 |
slug | string | pattern ^[a-z0-9](?:[a-z0-9-]{1,46}[a-z0-9])?$ |
description | string | max length 500 |
customDomain | string | null | pattern ^(?=.{4,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$ · nullable |
visibility | string | publicprivate |
theme | object | |
theme.preset | string | max length 30 |
theme.mode | string | darklight |
theme.accent | string | pattern ^#[0-9a-fA-F]{6}$ |
theme.tokens | map<string, string> | |
theme.fontSans | string | max length 40 |
theme.fontMono | string | max length 40 |
theme.radius | integer | min 0 · max 24 |
theme.customCss | string | max length 50,000 |
branding | object | |
branding.logoUrl | string | null | max length 1,000 · nullable |
branding.logoDarkUrl | string | null | max length 1,000 · nullable |
branding.logoText | string | null | max length 60 · nullable |
branding.faviconUrl | string | null | max length 1,000 · nullable |
branding.websiteUrl | string (url) | null | max length 500 · nullable |
branding.supportUrl | string (url) | null | max length 500 · nullable |
branding.headerLinks | object[] | max 8 items |
branding.headerLinks[].labelrequired | string | max length 60 |
branding.headerLinks[].urlrequired | string (url) | max length 500 |
branding.footerLinks | object[] | max 20 items |
branding.footerLinks[].labelrequired | string | max length 60 |
branding.footerLinks[].urlrequired | string (url) | max length 500 |
branding.footerText | string | null | max length 300 · nullable |
branding.hidePoweredBy | boolean | |
settings | object | |
settings.uptimeDays | integer | min 7 · max 90 |
settings.showUptimePercent | boolean | |
settings.showResponseTimes | boolean | Allow public response-time charts (components opt in with showResponseTimes) |
settings.language | string | Public page + subscriber email language; auto = visitor Accept-Languageautoendefresitptnlelpltrja |
settings.autoIncidents | boolean | |
settings.incidentMinStatus | string | Lowest component status that opens an automatic incidentdegradedpartial_outagemajor_outage |
settings.aiPublicUpdates | boolean | |
settings.aiGuidelines | string | Rules for AI-written public text, e.g. "Never mention internal infrastructure"max length 2,000 |
settings.aiAvoidTerms | string[] | AI public text containing any of these is replaced by a neutral templatemax 50 items |
settings.subscriptions | object | |
settings.subscriptions.email | boolean | |
settings.subscriptions.webhook | boolean | |
settings.subscriptions.slack | boolean | |
settings.subscriptions.rss | boolean | |
settings.timezone | string | max length 60 |
seo | object | |
seo.title | string | max length 120 |
seo.description | string | max length 300 |
seo.noindex | boolean | |
pageIdrequiredpath | string | Status page id (pg_...) or slug |
curl -X PATCH https://upbutler.com/api/v1/pages/pg_0n3q8kz0b2fd81mka5e \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Delete a status page, its components and subscribers
DELETE/api/v1/pages/:pageId
API key · writeMCP pages_deleteReturns 200
| Field | Type | Description |
|---|
pageIdrequiredpath | string | Status page id (pg_...) or slug |
curl -X DELETE https://upbutler.com/api/v1/pages/pg_0n3q8kz0b2fd81mka5e \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Check the custom domain DNS now
POST/api/v1/pages/:pageId/domain/verify
API key · writeMCP pages_verifyDomainReturns 200
Verified when the domain CNAMEs to the target shown in pages.get dns.value (or resolves to the same IPs).
| Field | Type | Description |
|---|
pageIdrequiredpath | string | Status page id (pg_...) or slug |
curl -X POST https://upbutler.com/api/v1/pages/pg_0n3q8kz0b2fd81mka5e/domain/verify \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Get the rendered public status data (as visitors see it)
GET/api/v1/pages/:pageId/preview
API key · readMCP pages_previewReturns 200
| Field | Type | Description |
|---|
pageIdrequiredpath | string | Status page id (pg_...) or slug |
curl https://upbutler.com/api/v1/pages/pg_0n3q8kz0b2fd81mka5e/preview \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Replace the ordered list of component groups
PUT/api/v1/pages/:pageId/groups
API key · writeMCP pages_groupsReturns 200
| Field | Type | Description |
|---|
pageIdrequiredpath | string | Status page id (pg_...) or slug |
groupsrequired | object[] | |
groups[].id | string | |
groups[].namerequired | string | max length 80 |
groups[].description | string | max length 300 |
groups[].collapsed | boolean | |
curl -X PUT https://upbutler.com/api/v1/pages/pg_0n3q8kz0b2fd81mka5e/groups \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"groups": []
}'
#List subscribers of a status page
GET/api/v1/pages/:pageId/subscribers
API key · readMCP pages_subscribersReturns 200
| Field | Type | Description |
|---|
pageIdrequiredpath | string | Status page id (pg_...) or slug |
statusquery | string | pendingactiveunsubscribeddisabled |
limitquery | integer | min 1 · max 1,000 |
curl https://upbutler.com/api/v1/pages/pg_0n3q8kz0b2fd81mka5e/subscribers \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Remove a subscriber
DELETE/api/v1/subscribers/:id
API key · writeMCP subscribers_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/subscribers/sub_0n3q9b40t2m8w6k1c5v \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Components
#Add a component to a status page
POST/api/v1/pages/:pageId/components
API key · writeMCP components_createReturns 201
A component is a row on the status page. Its status comes from one of: monitorIds (follows monitors), push=true (you POST statuses to its push URL), manifest {monitorId,key} (read from a manifest monitor), or manual (default).
| Field | Type | Description |
|---|
pageIdrequiredpath | string | Status page id (pg_...) or slug |
namerequired | string | max length 100 |
key | string | Stable machine key used by pushes and manifests (default: slug of name)pattern ^[a-z0-9][a-z0-9_.-]{0,62}$ |
description | string | max length 500 |
group | string | Group name or id; created if it does not existmax length 80 |
monitorIds | string[] | Status follows these monitorsmax 20 items |
aggregate | string | worstmajority |
push | boolean | Status is pushed via the component push URL |
pushTtlSec | integer | null | Become "unknown" when no push arrives for this long (null clears it)min 60 · max 604,800 · nullable |
manual | boolean | Switch the component to manual status (set via overrides/incidents) |
manifest | object | Status read from a manifest monitor key |
manifest.monitorIdrequired | string | |
manifest.keyrequired | string | max length 120 |
showUptime | boolean | |
showResponseTimes | boolean | Public response-time chart (monitor-backed components only; page setting showResponseTimes must be on) |
hidden | boolean | |
order | integer | min 0 · max 10,000 |
confirmations | integer | Push/manifest: consecutive fresh bad reports before a worse status shows (default 2; 1 = immediate)min 1 · max 10 |
curl -X POST https://upbutler.com/api/v1/pages/acme/components \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Search API",
"group": "APIs",
"monitorIds": [
"mon_..."
]
}'
#Update a component (name, group, source, visibility)
PATCH/api/v1/components/:id
API key · writeMCP components_updateReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
name | string | max length 100 |
key | string | Stable machine key used by pushes and manifests (default: slug of name)pattern ^[a-z0-9][a-z0-9_.-]{0,62}$ |
description | string | max length 500 |
group | string | Group name or id; created if it does not existmax length 80 |
monitorIds | string[] | Status follows these monitorsmax 20 items |
aggregate | string | worstmajority |
push | boolean | Status is pushed via the component push URL |
pushTtlSec | integer | null | Become "unknown" when no push arrives for this long (null clears it)min 60 · max 604,800 · nullable |
manual | boolean | Switch the component to manual status (set via overrides/incidents) |
manifest | object | Status read from a manifest monitor key |
manifest.monitorIdrequired | string | |
manifest.keyrequired | string | max length 120 |
showUptime | boolean | |
showResponseTimes | boolean | Public response-time chart (monitor-backed components only; page setting showResponseTimes must be on) |
hidden | boolean | |
order | integer | min 0 · max 10,000 |
confirmations | integer | Push/manifest: consecutive fresh bad reports before a worse status shows (default 2; 1 = immediate)min 1 · max 10 |
curl -X PATCH https://upbutler.com/api/v1/components/cmp_0n3q8kz2p7wd4yx0s3a \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Delete a component
DELETE/api/v1/components/:id
API key · writeMCP components_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/components/cmp_0n3q8kz2p7wd4yx0s3a \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Manually set (or clear) a component status
POST/api/v1/components/:id/override
API key · writeMCP components_overrideReturns 200
Overrides win over automatic status until cleared with status=null. For outages prefer creating an incident, which also notifies subscribers.
| Field | Type | Description |
|---|
idrequiredpath | string | |
statusrequired | string | null | operationaldegradedpartial_outagemajor_outagemaintenancenullable |
reason | string | max length 300 |
curl -X POST https://upbutler.com/api/v1/components/cmp_0n3q8kz2p7wd4yx0s3a/override \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "operational"
}'
#Push statuses for many components at once
POST/api/v1/pages/:pageId/status
API key · writeMCP pages_pushReturns 200
Body: {"statuses": {"<component key>": "operational" | {"status": "major_outage", "message": "..."}}}. Accepts ok/up/fail/down/true/false too. Failing components open (or join) an automatic incident when the page has autoIncidents on; recovery resolves it.
| Field | Type | Description |
|---|
pageIdrequiredpath | string | Status page id (pg_...) or slug |
statusesrequired | map<string, any> | |
curl -X POST https://upbutler.com/api/v1/pages/acme/status \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"statuses": {
"search": "operational",
"billing": {
"status": "degraded",
"message": "Stripe latency"
}
}
}'
#Incidents
#List incidents and maintenance
GET/api/v1/incidents
API key · readMCP incidents_listReturns 200
| Field | Type | Description |
|---|
openquery | boolean | string | Only unresolved |
kindquery | string | incidentmaintenance |
pageIdquery | string | |
monitorIdquery | string | |
limitquery | integer | min 1 · max 200 |
curl https://upbutler.com/api/v1/incidents \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Get an incident with its timeline and AI reports
GET/api/v1/incidents/:id
API key · readMCP incidents_getReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Report an incident
POST/api/v1/incidents
API key · writeMCP incidents_createReturns 201
Declare an incident (agents: use this when you detect a problem yourself). Affected components switch to the given status and page subscribers are notified. Set polish=true to have AI rewrite rough notes into a clear public update.
| Field | Type | Description |
|---|
titlerequired | string | max length 200 |
messagerequired | string | First public updatemax length 10,000 |
status | string | investigatingidentifiedmonitoring |
impact | string | noneminormajorcritical |
pageIds | string[] | max 20 items |
components | object[] | Affected components and their status during the incidentmax 200 items |
components[].componentIdrequired | string | |
components[].statusrequired | string | operationaldegradedpartial_outagemajor_outagemaintenance |
public | boolean | Show on status pages (default: true when pages/components are given) |
polish | boolean | |
notify | boolean | Notify subscribers (default true) |
curl -X POST https://upbutler.com/api/v1/incidents \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Elevated API errors",
"message": "We are seeing 5xx errors on search and are investigating.",
"components": [
{
"componentId": "cmp_...",
"status": "partial_outage"
}
]
}'
#Post an incident update
POST/api/v1/incidents/:id/updates
API key · writeMCP incidents_updateReturns 200
Adds a timeline update, optionally changing status and component impact. status=resolved resolves the incident.
| Field | Type | Description |
|---|
idrequiredpath | string | |
messagerequired | string | max length 10,000 |
status | string | investigatingidentifiedmonitoringresolvedscheduledin_progresscompleted |
components | object[] | Affected components and their status during the incidentmax 200 items |
components[].componentIdrequired | string | |
components[].statusrequired | string | operationaldegradedpartial_outagemajor_outagemaintenance |
public | boolean | false = internal note (not shown or sent to subscribers) |
polish | boolean | |
notify | boolean | |
curl -X POST https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/updates \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "We are looking into it."
}'
#Resolve an incident
POST/api/v1/incidents/:id/resolve
API key · writeMCP incidents_resolveReturns 200
Without a message, UpButler writes the resolution note (AI recovery summary when available).
| Field | Type | Description |
|---|
idrequiredpath | string | |
message | string | max length 10,000 |
polish | boolean | |
curl -X POST https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/resolve \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Generate (or regenerate) the AI report for an incident
POST/api/v1/incidents/:id/analyze
API key · writeMCP incidents_analyzeReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X POST https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/analyze \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Schedule maintenance
POST/api/v1/maintenance
API key · writeMCP maintenance_createReturns 201
Components show "Under maintenance" during the window; it starts and completes automatically. Subscribers are notified.
| Field | Type | Description |
|---|
titlerequired | string | max length 200 |
messagerequired | string | max length 10,000 |
scheduledStartrequired | any | |
scheduledEndrequired | any | |
pageIds | string[] | max 20 items |
componentIds | string[] | max 200 items |
notify | boolean | |
curl -X POST https://upbutler.com/api/v1/maintenance \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Elevated API errors",
"message": "We are looking into it.",
"scheduledStart": "2026-11-02T22:00:00Z",
"scheduledEnd": "2026-11-02T23:00:00Z"
}'
#Acknowledge an incident or a down monitor
POST/api/v1/incidents/:id/ack
API key · writeMCP incidents_ackReturns 200
Take ownership: stops "still down" reminders and escalation, records an internal timeline entry and emits incident.acknowledged to the channels that were alerted. `id` may be an incident id or a monitor id (acknowledges its open incident). Idempotent.
| Field | Type | Description |
|---|
idrequiredpath | string | Incident id (inc_…) or monitor id (mon_…) |
note | string | e.g. "Looking into it, rolling back deploy"max length 1,000 |
curl -X POST https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/ack \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"note": "On it, rolling back the last deploy"
}'
#Remove an acknowledgement
POST/api/v1/incidents/:id/unack
API key · writeMCP incidents_unackReturns 200
Reminders and escalation resume where they stopped.
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X POST https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/unack \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Draft a postmortem with AI
POST/api/v1/incidents/:id/postmortem
API key · writeMCP incidents_postmortemReturns 200
Writes a blameless markdown postmortem (summary, impact, timeline from updates, checks and deploy markers, root-cause hypotheses, contributing factors, what went well/poorly, action items) plus a customer-safe summary, and stores it as a new version. Uses one AI report. When AI is unavailable the 503 response carries a template draft in error.details.template.
| Field | Type | Description |
|---|
idrequiredpath | string | |
mode | string | template = return an unsaved fill-in-the-blanks draft without using AIaitemplate |
curl -X POST https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/postmortem \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Get an incident's postmortem
GET/api/v1/incidents/:id/postmortem
API key · readMCP incidents_postmortem_getReturns 200
Current markdown, the public summary, publish state and the version list (history=true includes every version's markdown). 404 when none exists yet.
| Field | Type | Description |
|---|
idrequiredpath | string | |
historyquery | boolean | string | |
curl https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/postmortem \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Save an edited postmortem (new version)
PUT/api/v1/incidents/:id/postmortem
API key · writeMCP incidents_postmortem_saveReturns 200
Send baseVersion (the version you edited) to get a 409 instead of overwriting someone else's changes.
| Field | Type | Description |
|---|
idrequiredpath | string | |
markdownrequired | string | max length 60,000 |
publicSummary | string | Customer-safe text used by publishmax length 5,000 |
baseVersion | integer | min 1 |
curl -X PUT https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/postmortem \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"markdown": "..."
}'
#Publish a post-incident report to status pages
POST/api/v1/incidents/:id/postmortem/publish
API key · writeMCP incidents_postmortem_publishReturns 200
Posts body (default: the postmortem's public summary) as a public update on the resolved incident and notifies subscribers. The text must pass the page's AI policy and may not contain hostnames, IPs or error output.
| Field | Type | Description |
|---|
idrequiredpath | string | |
body | string | max length 10,000 |
notify | boolean | |
curl -X POST https://upbutler.com/api/v1/incidents/inc_0n3q9a11v8k2h5n0qzc/postmortem/publish \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#List incident templates
GET/api/v1/incident-templates
API key · readMCP templates_listReturns 200
Reusable title/status/impact/message presets. Bodies support {{component}}, {{duration}}, {{status_page}} and {{title}}. New workspaces start with sensible defaults.
No parameters.
curl https://upbutler.com/api/v1/incident-templates \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Create an incident template
POST/api/v1/incident-templates
API key · writeMCP templates_createReturns 201
| Field | Type | Description |
|---|
namerequired | string | Shown in the "Use template" pickermax length 80 |
kind | string | Default incidentincidentmaintenance |
titlerequired | string | Incident title; placeholders allowedmax length 200 |
status | string | investigatingidentifiedmonitoringresolvedscheduledin_progresscompleted |
impact | string | noneminormajorcriticalmaintenance |
bodyrequired | string | Update text. Placeholders: {{component}}, {{duration}}, {{status_page}}, {{title}}max length 10,000 |
componentIds | string[] | Components affected by defaultmax 200 items |
componentStatus | string | Status the default components get (default partial_outage)operationaldegradedpartial_outagemajor_outagemaintenance |
order | integer | min 0 · max 10,000 |
curl -X POST https://upbutler.com/api/v1/incident-templates \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Payment provider outage",
"title": "Payments delayed on {{component}}",
"status": "identified",
"impact": "major",
"body": "Our payment provider is having issues. {{component}} payments may be delayed; no charges are lost."
}'
#Update an incident template
PATCH/api/v1/incident-templates/:id
API key · writeMCP templates_updateReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
name | string | Shown in the "Use template" pickermax length 80 |
kind | string | Default incidentincidentmaintenance |
title | string | Incident title; placeholders allowedmax length 200 |
status | string | investigatingidentifiedmonitoringresolvedscheduledin_progresscompleted |
impact | string | noneminormajorcriticalmaintenance |
body | string | Update text. Placeholders: {{component}}, {{duration}}, {{status_page}}, {{title}}max length 10,000 |
componentIds | string[] | Components affected by defaultmax 200 items |
componentStatus | string | Status the default components get (default partial_outage)operationaldegradedpartial_outagemajor_outagemaintenance |
order | integer | min 0 · max 10,000 |
curl -X PATCH https://upbutler.com/api/v1/incident-templates/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Delete an incident template
DELETE/api/v1/incident-templates/:id
API key · writeMCP templates_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/incident-templates/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Fill in a template
POST/api/v1/incident-templates/:id/render
API key · readMCP templates_renderReturns 200
Returns title, message, status, impact and components ready for POST /incidents or POST /incidents/{id}/updates. With incidentId, the incident's components and duration fill the placeholders; otherwise componentIds (or the template defaults) do.
| Field | Type | Description |
|---|
idrequiredpath | string | |
incidentId | string | |
componentIds | string[] | max 200 items |
curl -X POST https://upbutler.com/api/v1/incident-templates/id_.../render \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Alerts
#List alert channels
GET/api/v1/channels
API key · readMCP channels_listReturns 200
No parameters.
curl https://upbutler.com/api/v1/channels \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Create an alert channel
POST/api/v1/channels
API key · writeMCP channels_createReturns 201
Where your team (or your agent) gets alerted. Webhook channels receive Standard Webhooks-signed JSON (headers webhook-id, webhook-timestamp, webhook-signature); the signing secret is returned once in the response.
| Field | Type | Description |
|---|
namerequired | string | max length 80 |
typerequired | string | emailwebhookslackdiscordtelegram |
emails | string (email)[] | email: recipientsmax 20 items |
url | string (url) | webhook/slack/discord: URLmax length 1,000 |
headers | map<string, string> | webhook: extra headers |
botToken | string | telegram: bot tokenmax length 200 |
chatId | string | telegram: chat idmax length 100 |
events | string[] | Event types to receive (default: alerts). One of: monitor.down, monitor.up, monitor.degraded, monitor.reminder, incident.created, incident.updated, incident.resolved, maintenance.scheduled, maintenance.started, maintenance.updated, maintenance.completed, incident.acknowledged, incident.escalated, incident.unacknowledged, component.status_changed, monitor.created, monitor.deleted, deploy.created, digest.weekly, test.ping, or "*"max 30 items |
isDefault | boolean | Attach to new monitors automatically (default true) |
enabled | boolean | |
curl -X POST https://upbutler.com/api/v1/channels \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Ops agent",
"type": "webhook",
"url": "https://agent.example.com/hooks/upbutler"
}'
#Update an alert channel
PATCH/api/v1/channels/:id
API key · writeMCP channels_updateReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
name | string | max length 80 |
type | string | emailwebhookslackdiscordtelegram |
emails | string (email)[] | email: recipientsmax 20 items |
url | string (url) | webhook/slack/discord: URLmax length 1,000 |
headers | map<string, string> | webhook: extra headers |
botToken | string | telegram: bot tokenmax length 200 |
chatId | string | telegram: chat idmax length 100 |
events | string[] | Event types to receive (default: alerts). One of: monitor.down, monitor.up, monitor.degraded, monitor.reminder, incident.created, incident.updated, incident.resolved, maintenance.scheduled, maintenance.started, maintenance.updated, maintenance.completed, incident.acknowledged, incident.escalated, incident.unacknowledged, component.status_changed, monitor.created, monitor.deleted, deploy.created, digest.weekly, test.ping, or "*"max 30 items |
isDefault | boolean | Attach to new monitors automatically (default true) |
enabled | boolean | |
rotateSecret | boolean | |
curl -X PATCH https://upbutler.com/api/v1/channels/ch_0n3q8kz3j6d0q2b5ny8 \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Delete an alert channel
DELETE/api/v1/channels/:id
API key · writeMCP channels_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/channels/ch_0n3q8kz3j6d0q2b5ny8 \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Send a test notification
POST/api/v1/channels/:id/test
API key · writeMCP channels_testReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X POST https://upbutler.com/api/v1/channels/ch_0n3q8kz3j6d0q2b5ny8/test \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Public status
#Public status of a page (no auth)
GET/api/v1/public/pages/:slug
Public — no keyMCP public_statusReturns 200
Overall status, components with 90-day uptime, active incidents and maintenance. Safe to poll every 30s.
| Field | Type | Description |
|---|
slugrequiredpath | string | |
historyquery | boolean | string | Include per-day uptime bars (default true) |
curl https://upbutler.com/api/v1/public/pages/acme
#Public incident history of a page
GET/api/v1/public/pages/:slug/incidents
Public — no keyMCP public_incidentsReturns 200
| Field | Type | Description |
|---|
slugrequiredpath | string | |
limitquery | integer | min 1 · max 100 |
beforequery | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
curl https://upbutler.com/api/v1/public/pages/acme/incidents
#One public incident with its updates
GET/api/v1/public/pages/:slug/incidents/:id
Public — no keyMCP public_incidentReturns 200
| Field | Type | Description |
|---|
slugrequiredpath | string | |
idrequiredpath | string | |
curl https://upbutler.com/api/v1/public/pages/acme/incidents/inc_0n3q9a11v8k2h5n0qzc
#Subscribe to a status page (email, webhook, Slack or Discord)
POST/api/v1/public/pages/:slug/subscribers
Public — no keyMCP public_subscribeReturns 201
Agents: subscribe with {"type":"webhook","url":"https://your-agent/hook"} to receive signed incident.*, maintenance.* and component.status_changed events and automate downtime handling. We first POST {"type":"subscription.verify","challenge":"..."} and your endpoint must echo the challenge. The response contains the signing secret (Standard Webhooks) and a manage token for unsubscribing. Optionally limit to components (ids or keys).
| Field | Type | Description |
|---|
slugrequiredpath | string | |
typerequired | string | emailwebhookslackdiscord |
email | string (email) | pattern ^(?:[A-Za-z0-9_'+\-]+\.)*[A-Za-z0-9_'+\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$ |
url | string (url) | max length 1,000 |
components | string[] | Component ids or keys; omit for everythingmax 200 items |
agent | string | Name of the subscribing agent (shown to the page owner)max length 80 |
incident | string | Incident id: only that incident's updates, until it is resolved ("subscribe to this incident")max length 60 |
language | string | Email language (en, de, fr, es, it, pt, nl, el, pl, tr, ja); default = page language or Accept-Languagemax length 10 |
curl -X POST https://upbutler.com/api/v1/public/pages/fetchlayer/subscribers \
-H "Content-Type: application/json" \
-d '{
"type": "webhook",
"url": "https://my-agent.example.com/upbutler",
"components": [
"reddit"
],
"agent": "scraper-orchestrator"
}'
#View a subscription (requires its manage token)
GET/api/v1/public/subscribers/:id
Public — no keyMCP public_subscriber_getReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
tokenrequiredquery | string | |
curl "https://upbutler.com/api/v1/public/subscribers/sub_0n3q9b40t2m8w6k1c5v?token=..."
#Change which components a subscription follows (requires the manage token)
PATCH/api/v1/public/subscribers/:id
Public — no keyMCP public_subscriber_updateReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
tokenrequired | string | |
componentsrequired | string[] | Component ids or keys; [] = everythingmax 200 items |
curl -X PATCH https://upbutler.com/api/v1/public/subscribers/sub_0n3q9b40t2m8w6k1c5v \
-H "Content-Type: application/json" \
-d '{
"token": "...",
"components": "..."
}'
#Unsubscribe (requires the manage token)
DELETE/api/v1/public/subscribers/:id
Public — no keyMCP public_unsubscribeReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
tokenrequiredquery | string | |
curl -X DELETE "https://upbutler.com/api/v1/public/subscribers/sub_0n3q9b40t2m8w6k1c5v?token=..."
#Public response-time series of a component (p50/p95)
GET/api/v1/public/pages/:slug/components/:component/response-times
Public — no keyMCP public_responseTimesReturns 200
Only for components the page owner published (page settings.showResponseTimes + component showResponseTimes, monitor-backed). 24h = 30-min buckets and 7d = 3-hour buckets with p50/p95 in ms from raw checks; 30d = daily averages (p95 null). Values are averaged across the component's monitors.
| Field | Type | Description |
|---|
slugrequiredpath | string | |
componentrequiredpath | string | Component key or id |
rangequery | string | 24h (default), 7d or 30d24h7d30d |
curl "https://upbutler.com/api/v1/public/pages/fetchlayer/components/api/response-times?range=7d"
#Workspace
#Current workspace, plan, limits and usage
GET/api/v1/workspace
API key · readMCP workspace_getReturns 200
Useful first call for agents: shows what the key can do and how much quota is left.
No parameters.
curl https://upbutler.com/api/v1/workspace \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Rename the workspace
PATCH/api/v1/workspace
API key · writeMCP workspace_updateReturns 200
| Field | Type | Description |
|---|
namerequired | string | max length 80 |
curl -X PATCH https://upbutler.com/api/v1/workspace \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Search API"
}'
#List workspace members and pending invites
GET/api/v1/members
API key · readMCP members_listReturns 200
No parameters.
curl https://upbutler.com/api/v1/members \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Invite a teammate by email
POST/api/v1/members/invites
API key · writeREST onlyReturns 200
| Field | Type | Description |
|---|
emailrequired | string (email) | pattern ^(?:[A-Za-z0-9_'+\-]+\.)*[A-Za-z0-9_'+\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$ |
role | string | adminmember |
curl -X POST https://upbutler.com/api/v1/members/invites \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]"
}'
#Revoke a pending invite
DELETE/api/v1/members/invites/:id
API key · writeREST onlyReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/members/invites/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Remove a member
DELETE/api/v1/members/:userId
API key · writeREST onlyReturns 200
| Field | Type | Description |
|---|
userIdrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/members/usr_0n3q8jy7w2e4r6t8y0u \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#List API keys
GET/api/v1/keys
API key · readMCP keys_listReturns 200
No parameters.
curl https://upbutler.com/api/v1/keys \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Create an API key
POST/api/v1/keys
API key · writeMCP keys_createReturns 201
The secret is returned once. Give agents their own key (with agent set) so their actions are attributed in incident timelines.
| Field | Type | Description |
|---|
namerequired | string | max length 80 |
scopes | string[] | readwrite |
agent | string | Name of the agent using this key, e.g. "deploy-bot"max length 80 |
expiresInDays | integer | min 1 · max 3,650 |
curl -X POST https://upbutler.com/api/v1/keys \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Search API"
}'
#Revoke an API key
DELETE/api/v1/keys/:id
API key · writeMCP keys_revokeReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/keys/key_0n3q8jy9x1c4v7b2n6m \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Require two-factor authentication for every member (owners only)
PATCH/api/v1/workspace/security
API key · writeREST onlyReturns 200
| Field | Type | Description |
|---|
require2farequired | boolean | |
curl -X PATCH https://upbutler.com/api/v1/workspace/security \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"require2fa": true
}'
#Audit log: sign-ins, 2FA changes, keys, members, billing, deletions, domains
GET/api/v1/audit
API key · readMCP audit_listReturns 200
Newest first, kept 400 days. Filter by action (exact like "api_key.created" or a prefix like "auth" / "member."), actor id or time range; page with ?before=<next>. Owners and admins (or keys with the write scope).
| Field | Type | Description |
|---|
actionquery | string | max length 60 |
actorIdquery | string | max length 60 |
fromquery | any | |
toquery | any | |
beforequery | string | max length 60 |
limitquery | integer | min 1 · max 200 |
curl https://upbutler.com/api/v1/audit \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Events
#Poll the event stream
GET/api/v1/events
API key · readMCP events_listReturns 200
Every state change in the workspace (monitor.down/up/degraded, incident.*, maintenance.*, component.status_changed …), newest first. Agents without a public webhook endpoint can poll with ?after=<last event id> to get only new events (oldest first). For push instead of polling, open GET /api/v1/stream (Server-Sent Events, same auth; resume with Last-Event-ID; ?types= filter; ?checks=1 for live check results).
| Field | Type | Description |
|---|
afterquery | string | Return events after this id, oldest first |
typesquery | string | Comma-separated event types, e.g. "monitor.down,monitor.up" |
limitquery | integer | min 1 · max 500 |
curl https://upbutler.com/api/v1/events \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Billing
#Available plans and limits
GET/api/v1/plans
Public — no keyMCP plans_listReturns 200
No parameters.
curl https://upbutler.com/api/v1/plans
#Start a checkout to upgrade the workspace
POST/api/v1/billing/checkout
API key · writeMCP billing_checkoutReturns 200
Returns a Polar checkout URL. Agents: hand this URL to your human — payment needs a person.
| Field | Type | Description |
|---|
planrequired | string | starterprobusiness |
interval | string | monthyear |
curl -X POST https://upbutler.com/api/v1/billing/checkout \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"plan": "pro",
"interval": "month"
}'
#Open the billing portal (invoices, payment method, cancel)
POST/api/v1/billing/portal
API key · writeREST onlyReturns 200
No parameters.
curl -X POST https://upbutler.com/api/v1/billing/portal \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Import
#Dry run: what an import would create
POST/api/v1/import/preview
API key · writeMCP import_previewReturns 200
Reads your UptimeRobot, Better Stack or Statuspage.io account and returns every item with action create | exists (already imported) | skip (with reason), plus plan-limit warnings. Nothing is written. Statuspage.io works with just a public URL.
| Field | Type | Description |
|---|
sourcerequired | string | Where to import fromuptimerobotbetterstackstatuspage |
apiKey | string | UptimeRobot read-only API key, Better Stack Uptime API token, or Statuspage.io API key. Used for this request only and never stored.min length 4 · max length 500 |
pageId | string | Statuspage.io page id (with apiKey)max length 100 |
url | string | Statuspage.io: any public status page URL (no key needed), e.g. https://www.githubstatus.commax length 500 |
monitors | boolean | Import monitors and heartbeats (default true) |
channels | boolean | Import alert contacts as alert channels (default true) |
pages | boolean | Import status pages, groups and components (default true) |
incidents | boolean | Statuspage.io: import past incidents and maintenance (default true) |
mirror | boolean | Statuspage.io: add a manifest monitor that keeps mirroring their components.json (default false) |
targetPageId | string | Import components into this existing status page instead of creating one |
exclude | string[] | Refs from the preview ("monitor:123") to leave outmax 2000 items |
curl -X POST https://upbutler.com/api/v1/import/preview \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "statuspage",
"url": "https://www.githubstatus.com",
"mirror": true
}'
#Run an import (background job)
POST/api/v1/import
API key · writeMCP import_applyReturns 202
Starts the import and returns the job right away; poll import.status. Idempotent: re-running creates only what is new. Credentials are kept in memory for the job and never stored.
| Field | Type | Description |
|---|
sourcerequired | string | Where to import fromuptimerobotbetterstackstatuspage |
apiKey | string | UptimeRobot read-only API key, Better Stack Uptime API token, or Statuspage.io API key. Used for this request only and never stored.min length 4 · max length 500 |
pageId | string | Statuspage.io page id (with apiKey)max length 100 |
url | string | Statuspage.io: any public status page URL (no key needed), e.g. https://www.githubstatus.commax length 500 |
monitors | boolean | Import monitors and heartbeats (default true) |
channels | boolean | Import alert contacts as alert channels (default true) |
pages | boolean | Import status pages, groups and components (default true) |
incidents | boolean | Statuspage.io: import past incidents and maintenance (default true) |
mirror | boolean | Statuspage.io: add a manifest monitor that keeps mirroring their components.json (default false) |
targetPageId | string | Import components into this existing status page instead of creating one |
exclude | string[] | Refs from the preview ("monitor:123") to leave outmax 2000 items |
curl -X POST https://upbutler.com/api/v1/import \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "uptimerobot",
"apiKey": "ur123456-..."
}'
#Progress and result of an import job
GET/api/v1/import/jobs/:id
API key · readMCP import_statusReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | Import job id (imp_...) |
curl https://upbutler.com/api/v1/import/jobs/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Recent import jobs
GET/api/v1/import/jobs
API key · readMCP import_jobsReturns 200
| Field | Type | Description |
|---|
limitquery | integer | min 1 · max 100 |
curl https://upbutler.com/api/v1/import/jobs \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#On-call
#Who is on call right now
GET/api/v1/oncall/current
API key · readMCP oncall_currentReturns 200
For every schedule (or one with scheduleId): the person on call now, until when, and whether it is an override. Agents: use this to decide whom to tell about a problem.
| Field | Type | Description |
|---|
scheduleIdquery | string | |
curl https://upbutler.com/api/v1/oncall/current \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#List on-call schedules
GET/api/v1/oncall/schedules
API key · readMCP oncall_schedules_listReturns 200
| Field | Type | Description |
|---|
daysquery | integer | Include upcoming shifts for this many daysmin 0 · max 42 |
curl https://upbutler.com/api/v1/oncall/schedules \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Get a schedule with upcoming shifts
GET/api/v1/oncall/schedules/:id
API key · readMCP oncall_schedules_getReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
daysquery | integer | Default 14min 1 · max 42 |
curl https://upbutler.com/api/v1/oncall/schedules/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Create a weekly on-call rotation (Business plan)
POST/api/v1/oncall/schedules
API key · writeMCP oncall_schedules_createReturns 201
| Field | Type | Description |
|---|
namerequired | string | max length 80 |
timezonerequired | string | IANA timezone, e.g. "Europe/Berlin"max length 64 |
handoffDayrequired | integer | Handoff weekday: 0 = Monday … 6 = Sundaymin 0 · max 6 |
handoffTimerequired | string | Local handoff time "HH:MM" (24h)pattern ^\d{1,2}:\d{2}$ |
participantsrequired | string[] | Ordered member user ids; each is on call for one weekmax 50 items |
startDay | string | Local date whose rotation week the first participant takes (default: the current week)pattern ^\d{4}-\d{2}-\d{2}$ |
curl -X POST https://upbutler.com/api/v1/oncall/schedules \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Primary",
"timezone": "Europe/Berlin",
"handoffDay": 0,
"handoffTime": "09:00",
"participants": [
"usr_…",
"usr_…"
]
}'
#Update a schedule
PATCH/api/v1/oncall/schedules/:id
API key · writeMCP oncall_schedules_updateReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
name | string | max length 80 |
timezone | string | IANA timezone, e.g. "Europe/Berlin"max length 64 |
handoffDay | integer | Handoff weekday: 0 = Monday … 6 = Sundaymin 0 · max 6 |
handoffTime | string | Local handoff time "HH:MM" (24h)pattern ^\d{1,2}:\d{2}$ |
participants | string[] | Ordered member user ids; each is on call for one weekmax 50 items |
startDay | string | Local date whose rotation week the first participant takes (default: the current week)pattern ^\d{4}-\d{2}-\d{2}$ |
curl -X PATCH https://upbutler.com/api/v1/oncall/schedules/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Delete a schedule
DELETE/api/v1/oncall/schedules/:id
API key · writeMCP oncall_schedules_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/oncall/schedules/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Put someone on call for a period (override)
POST/api/v1/oncall/schedules/:id/overrides
API key · writeMCP oncall_overrides_createReturns 201
Overrides win over the rotation; the most recently created one wins when they overlap.
| Field | Type | Description |
|---|
idrequiredpath | string | |
userIdrequired | string | |
startrequired | any | |
endrequired | any | |
note | string | max length 200 |
curl -X POST https://upbutler.com/api/v1/oncall/schedules/id_.../overrides \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"userId": "...",
"start": {},
"end": {}
}'
#Remove an override
DELETE/api/v1/oncall/schedules/:id/overrides/:overrideId
API key · writeMCP oncall_overrides_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
overrideIdrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/oncall/schedules/id_.../overrides/<overrideId> \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Members with their paging contact status
GET/api/v1/oncall/members
API key · readMCP oncall_membersReturns 200
No parameters.
curl https://upbutler.com/api/v1/oncall/members \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#List escalation policies
GET/api/v1/escalation-policies
API key · readMCP escalation_listReturns 200
No parameters.
curl https://upbutler.com/api/v1/escalation-policies \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Create an escalation policy (Business plan)
POST/api/v1/escalation-policies
API key · writeMCP escalation_createReturns 201
Ordered levels: level 1 is paged as soon as an incident opens; each next level after `afterMinutes` if nobody acknowledged. Applies to incidents of `monitorIds`/`pageIds`, or to everything when isDefault. Without any policy, alerts follow each monitor's channels and reminders.
| Field | Type | Description |
|---|
namerequired | string | max length 80 |
isDefault | boolean | Use for incidents no monitor/page-specific policy claims (the first policy becomes default) |
monitorIds | string[] | max 250 items |
pageIds | string[] | max 20 items |
levelsrequired | object[] | max 10 items |
levels[].afterMinutesrequired | integer | Wait after the previous level (ignored for level 1)min 0 · max 1,440 |
levels[].targetsrequired | object[] | max 20 items |
levels[].targets[].typerequired | "channel" | |
levels[].targets[].idrequired | string | Alert channel id |
repeat | integer | Repeat the whole chain this many times while unacknowledgedmin 0 · max 5 |
repeatAfterMinutes | integer | min 1 · max 1,440 |
curl -X POST https://upbutler.com/api/v1/escalation-policies \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Default",
"levels": [
{
"afterMinutes": 0,
"targets": [
{
"type": "schedule",
"id": "sch_…"
}
]
},
{
"afterMinutes": 15,
"targets": [
{
"type": "channel",
"id": "ch_…"
}
]
}
],
"repeat": 1
}'
#Update an escalation policy
PATCH/api/v1/escalation-policies/:id
API key · writeMCP escalation_updateReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
name | string | max length 80 |
isDefault | boolean | Use for incidents no monitor/page-specific policy claims (the first policy becomes default) |
monitorIds | string[] | max 250 items |
pageIds | string[] | max 20 items |
levels | object[] | max 10 items |
levels[].afterMinutesrequired | integer | Wait after the previous level (ignored for level 1)min 0 · max 1,440 |
levels[].targetsrequired | object[] | max 20 items |
levels[].targets[].typerequired | "channel" | |
levels[].targets[].idrequired | string | Alert channel id |
repeat | integer | Repeat the whole chain this many times while unacknowledgedmin 0 · max 5 |
repeatAfterMinutes | integer | min 1 · max 1,440 |
curl -X PATCH https://upbutler.com/api/v1/escalation-policies/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Delete an escalation policy
DELETE/api/v1/escalation-policies/:id
API key · writeMCP escalation_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/escalation-policies/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Deploys
#Record a deploy
POST/api/v1/deploys
API key · writeMCP deploys_createReturns 201
Mark a release so incidents can be correlated with it (AI reports, charts, incident timelines). Minimal input {"version":"1.4.2"} applies to the whole workspace; narrow it with monitorIds, service (matches monitor tags/names) or pageId. Emits deploy.created.
| Field | Type | Description |
|---|
version | string | Release version or tag, e.g. "1.4.2"max length 100 |
commit | string | Commit SHA (shown shortened)max length 80 |
url | string (url) | Link to the release, CI run or PRmax length 2,000 |
environment | string | e.g. "production", "staging"max length 40 |
description | string | max length 2,000 |
service | string | Service name; monitors tagged or named like this are linked automaticallymax length 120 |
monitorIds | string[] | Limit the deploy to these monitors (default: whole workspace)max 100 items |
monitorId | string | max length 60 |
pageId | string | Limit the deploy to one status pagemax length 60 |
pageIds | string[] | max 100 items |
at | string (date-time) | When it went out (ISO 8601, default now)pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$ |
curl -X POST https://upbutler.com/api/v1/deploys \
-H "Authorization: Bearer $UPBUTLER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": "1.4.2",
"commit": "abc1234def",
"environment": "production",
"service": "api"
}'
#List deploys
GET/api/v1/deploys
API key · readMCP deploys_listReturns 200
Newest first. monitorId/pageId include workspace-wide deploys; incidentId returns the deploys from the hour before the incident through its end.
| Field | Type | Description |
|---|
monitorIdquery | string | |
pageIdquery | string | |
incidentIdquery | string | |
environmentquery | string | |
sincequery | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$ |
untilquery | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$ |
limitquery | integer | min 1 · max 500 |
curl https://upbutler.com/api/v1/deploys \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Delete a deploy marker
DELETE/api/v1/deploys/:id
API key · writeMCP deploys_deleteReturns 200
| Field | Type | Description |
|---|
idrequiredpath | string | |
curl -X DELETE https://upbutler.com/api/v1/deploys/id_... \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Digest
#Weekly digest settings
GET/api/v1/digest/settings
API key · readMCP digest_settingsReturns 200
Workspace timezone, who receives the Monday 08:00 email, when the next one goes out and the last runs. Webhook channels subscribed to "digest.weekly" get the full JSON.
No parameters.
curl https://upbutler.com/api/v1/digest/settings \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Change the workspace timezone or your weekly digest opt-in
PATCH/api/v1/digest/settings
API key · writeMCP digest_settings_updateReturns 200
subscribed applies to the signed-in member (owners are subscribed by default). timezone (IANA, e.g. "Europe/Berlin") needs owner/admin and also sets when Monday 08:00 is.
| Field | Type | Description |
|---|
subscribed | boolean | |
timezone | string | max length 60 |
curl -X PATCH https://upbutler.com/api/v1/digest/settings \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Build the weekly digest on demand
POST/api/v1/digest/preview
API key · readMCP digest_previewReturns 200
Returns the digest JSON (same shape as the digest.weekly event) and, with format=html, the rendered email. period=last_week is exactly what Monday's email covers; last_7_days is rolling. ai=true writes the "what to look at" section with AI (uses one AI report from the monthly quota); otherwise a rule-based version is returned.
| Field | Type | Description |
|---|
period | string | last_weeklast_7_days |
ai | boolean | |
format | string | jsonhtml |
curl -X POST https://upbutler.com/api/v1/digest/preview \
-H "Authorization: Bearer $UPBUTLER_API_KEY"
#Dashboard-only
These need a signed-in user session (the dashboard cookie) and aren't available with API keys or over MCP:
- GET
/api/v1/me/workspaces: Workspaces of the signed-in user - POST
/api/v1/me/workspaces: Create another workspace - POST
/api/v1/me/workspaces/:id/switch: Switch the dashboard to another workspace - GET
/api/v1/me/contact: Your paging contact profile - PATCH
/api/v1/me/contact: Update your paging contact profile - GET
/api/v1/me/security: Two-factor status, connected sign-in providers and active sessions - DELETE
/api/v1/me/sessions/:id: Sign out one session - POST
/api/v1/me/sessions/revoke-others: Sign out every other session - POST
/api/v1/me/2fa/setup: Start two-factor enrolment (returns secret, otpauth URI and QR SVG) - POST
/api/v1/me/2fa/enable: Confirm enrolment with a code; returns 10 one-time recovery codes - POST
/api/v1/me/2fa/disable: Turn off two-factor authentication - POST
/api/v1/me/2fa/recovery-codes: Replace all recovery codes (old ones stop working) - DELETE
/api/v1/me/identities/:provider: Disconnect a Google or GitHub sign-in