Status pages
Subscribers
Subscribers follow a status page. People subscribe by email or chat, and agents subscribe with webhooks, including agents at other companies that depend on you.
What subscribers receive
| Event | Email, Slack, Discord | Webhook |
|---|---|---|
incident.created · incident.updated · incident.resolved | Yes | Yes |
maintenance.scheduled · maintenance.started · maintenance.updated · maintenance.completed | Yes | Yes |
component.status_changed | No (too noisy for people) | Yes |
Only public incidents and public updates are sent. Internal notes never are. Senders can skip subscribers for one incident or update with notify: false.
Email (double opt-in)
curl -X POST https://upbutler.com/api/v1/public/pages/acme/subscribers \
-H "Content-Type: application/json" \
-d '{"type": "email", "email": "[email protected]", "components": ["search-api", "billing"]}'
# → 201 { "id": "sub_0n3q9b40t2m8w6k1c5v", "status": "pending", "message": "Check your inbox to confirm the subscription." }We email a confirmation link, sent from the page's name. The subscription only activates once it is clicked. Subscribing again with an active address just updates its component filter. Every notification includes a one-click unsubscribe link (List-Unsubscribe headers included). Emails count toward the page owner's monthly email quota.
| Plan | Email subscribers per page |
|---|---|
| Free | 25 |
| Starter | 500 |
| Pro | 5,000 |
| Business | 25,000 |
At the cap, new email sign-ups are refused with 402 plan_limit. After a downgrade, subscribers above the new cap are kept and still notified (the monthly email quota still applies), but new sign-ups stay blocked until the page is under the cap again.
Webhook subscriptions
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"
}'{
"id": "sub_0n3q9b40t2m8w6k1c5v",
"status": "active",
"message": "Webhook subscription active.",
"signingSecret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw",
"manageToken": "3f9a1c7e2b8d4f6a0c5e9b1d7f3a8c2e6b4d0f9a",
"manageUrl": "https://upbutler.com/api/v1/public/subscribers/sub_0n3q9b40t2m8w6k1c5v?token=3f9a1c7e2b8d4f6a0c5e9b1d7f3a8c2e6b4d0f9a"
}During this call your endpoint receives a subscription.verify challenge and must echo it. See the handshake. Store signingSecret to verify deliveries, and manageToken to manage the subscription later. Both are shown only once. agent names your agent to the page owner. A page can have up to 1,000 active webhook and chat subscribers.
Slack and Discord
curl -X POST https://upbutler.com/api/v1/public/pages/acme/subscribers \
-H "Content-Type: application/json" \
-d '{"type": "slack", "url": "https://hooks.slack.com/services/T000/B000/XXXX"}'Pass a Slack incoming-webhook URL (type: "slack") or a Discord webhook URL (type: "discord"). We post a “Subscribed to Acme Status” message right away to check the URL works, then post incident and maintenance updates prefixed with the page name. Both types are controlled by the page's slack subscription setting.
RSS and Atom
When the page's rss setting is on, anyone can follow it in a feed reader at /s/<slug>/feed.rss or /s/<slug>/feed.atom. No sign-up needed. A machine-readable summary is also available at /s/<slug>/status.json, or use the public JSON API.
Component filters
Pass components (ids or keys, up to 200) to only hear about what you use. A filtered subscriber gets incidents that affect at least one of its components. Incidents that list no components are page-wide and go to everyone. If none of the given components exist, the call fails with 422. Leave the filter out to get everything. Find ids and keys in GET /api/v1/public/pages/:slug.
Managing and unsubscribing
Each subscription has a manage token, returned on creation for webhook, Slack and Discord subscriptions and embedded in every email's unsubscribe link and every webhook payload (subscription.manage).
# View
curl "https://upbutler.com/api/v1/public/subscribers/sub_0n3q9b40t2m8w6k1c5v?token=3f9a1c7e2b8d4f6a0c5e9b1d7f3a8c2e6b4d0f9a"
# Unsubscribe
curl -X DELETE "https://upbutler.com/api/v1/public/subscribers/sub_0n3q9b40t2m8w6k1c5v?token=3f9a1c7e2b8d4f6a0c5e9b1d7f3a8c2e6b4d0f9a"
# → { "unsubscribed": true, "id": "sub_0n3q9b40t2m8w6k1c5v" }A webhook endpoint can also unsubscribe itself by answering any delivery with 410 Gone. Page owners see and remove subscribers with GET /pages/:pageId/subscribers (filter by status: pending, active, unsubscribed, disabled) and DELETE /subscribers/:id.
Agents following other companies
If a vendor you depend on runs its status page on UpButler, your agent can subscribe without an account or API key, over REST as above or with the MCP tool public_subscribe:
// MCP tools/call (no API key needed for public tools)
{
"name": "public_subscribe",
"arguments": {
"slug": "fetchlayer",
"type": "webhook",
"url": "https://my-agent.example.com/upbutler",
"components": ["reddit", "twitter"],
"agent": "scraper-orchestrator"
}
}From then on, your agent gets component.status_changed the moment a component flips, and incident.* with human-written (or AI-polished) updates. Use them to pause jobs, switch providers or warn your own users. Subscribing is rate-limited to 20 attempts per hour per IP address.
Page owners decide which types are allowed through settings.subscriptions. A disabled type returns 403 forbidden.