# Spectate
> Complete documentation for Large Language Models
---
## Document: Quickstart
Create an account, add an HTTPS monitor, get its alerts by email and show it on a public status page.
URL: /quickstart
# Quickstart
This guide takes a new Spectate account to a working setup. At the end, Spectate checks one website, sends you an email when the website goes down, and shows its status on a public status page. You do every step in the dashboard at [app.spectate.net](https://app.spectate.net).
## Create an account
1. Open [app.spectate.net/register](https://app.spectate.net/register).
2. Enter your name, email address and password.
3. Select **Create account**.
4. Open the email from Spectate and select the verification link.
To sign up with GitHub, Google or Microsoft, select the provider above the form instead.
Spectate creates a team for you with your name, for example "Ada Lovelace's Team". The team starts a 14-day trial with the limits of the Team plan. You do not need a payment card for the trial. To change the name of the team, go to **Team** and edit **Team name**. See [Teams and roles](/account/teams-and-roles) and [Plans and billing](/account/plans-and-billing).
The dashboard opens on **Overview** with a setup checklist. The checklist shows which of the steps below are done.
## Add an HTTPS monitor
A [monitor](/monitors/introduction) checks one target from one region, at a fixed interval.
1. In the sidebar, select **Monitors**.
2. Select **Create monitor**.
3. Under **Type**, select **HTTPS**.
4. In **Target**, enter the address without `https://`, for example `example.com/health`.
5. Check the **Name**. Spectate fills it in from the target.
6. Under **Interval**, select how often Spectate checks the target. The default is 5 minutes.
7. Under **Primary region**, select the region nearest to your users. The default is **Europe**.
8. Select **Create and start**.
The monitor is pending until its first check. After a successful check, the monitor is up. For HTTPS monitors, the dialog also turns on [certificate checks](/monitors/certificates).
The shortest interval depends on the plan: 60 seconds on Starter, 30 seconds on Team and Business. The trial allows 30 seconds.
## Send alerts to your email address
A new team has no [channels](/alerting/channels) and no [escalation paths](/alerting/escalation-paths). Until you add them, an alert notifies nobody. The monitor settings show the warning "No team default path yet".
Add an email channel first:
1. In the sidebar, select **Alerting**.
2. Under **Channels**, select **New channel**.
3. Select **Email**.
4. In **Name**, enter a name, for example `My email`.
5. In **Email address**, enter the address that must get the alerts.
6. Select **Create channel**.
7. On the new channel, select **Send test**.
Spectate sends a test email to the address. If it does not arrive, look in your spam folder.
Then add an escalation path and make it the team default:
1. On the **Alerting** page, select **New path**.
2. In **Name**, enter a name, for example `Default`.
3. Keep **Enabled** selected.
4. Select **Use as team default**.
5. Select **Create and open builder**.
The builder opens with one step. This step sends each alert to your email channel at once. Alerts from monitors without their own escalation paths now follow this path.
When a check fails, Spectate checks the target again about 5 seconds later. If that check also fails, the monitor is down. Spectate then fires a critical alert, and the escalation path sends you an email. When a later check succeeds, Spectate resolves the alert and sends a resolved email.
### Test the alert
To see a real alert, make the monitor fail on purpose:
1. Open the monitor.
2. Select the **Settings** tab.
3. Under **Availability**, set **Expected status** to `500`.
4. Select **Save changes**.
At the next check, the website answers with a status code that is not `500`. Spectate confirms the failure and sends the alert email. Then clear **Expected status** and select **Save changes** again. Without a value, every status code from 200 to 399 counts as up.
## Create a status page
A [status page](/status-pages/introduction) shows your customers which parts of your service work.
1. In the sidebar, select **Status pages**.
2. Select **Create status page**.
3. In **Name**, enter the name your customers know, for example `Acme`.
4. Check the **Slug**. The slug is part of the public URL, `https://SLUG.spectate.page`.
5. Under **Visibility**, keep **Public**.
6. Select **Create status page**.
The dashboard opens the new status page. Now add the monitor as a [component](/status-pages/components):
1. Select the **Components** tab.
2. Select **Add component**.
3. In **Name**, enter the name that visitors see, for example `Website`.
4. In **Linked monitor**, select your HTTPS monitor.
5. Select **Create component**.
Open `https://SLUG.spectate.page` to see the page. The component shows the uptime of the linked monitor.
A linked monitor does not change the component status on its own. The status comes from status page incidents and maintenance. To let the monitor open and resolve a public incident, go to the **Settings** tab of the status page. Under **Automation**, select **Open and resolve incidents from linked monitors**.
## Related
- [Concepts](/concepts): how monitors, alerts, escalation paths, incidents and status pages work together.
- [HTTP and HTTPS monitors](/monitors/http): status codes, keywords, headers and authentication.
- [Locations and checks](/monitors/locations-and-checks): regions, rechecks and the IP addresses of the checkers.
---
## Document: Introduction
What Spectate monitors, how it alerts your team, and where to start in these docs.
URL: /introduction
# Introduction
Spectate watches your websites, APIs, servers and domains. When something breaks, it alerts the right person, helps your team work on the incident, and tells your customers on a status page. Spectate is made and hosted in the EU.
## What Spectate does
| Part | What it does |
|---|---|
| [Uptime monitors](/monitors/introduction) | Check websites, APIs, servers, DNS and mail servers from four regions, every 30 or 60 seconds depending on the plan. |
| [Hosts](/hosts/introduction) | Collect CPU, memory, disk and network metrics from your servers with a small agent. |
| [Domains](/domains/introduction) | Warn before a domain registration or its DNS setup causes downtime. |
| [Alerts](/alerting/alerts) | Turn failures into alerts, and send them to people through [escalation paths](/alerting/escalation-paths) and [channels](/alerting/channels). |
| [On-call](/alerting/on-call) | Decide who is on call, with rotations and overrides. |
| [Incidents](/incidents/introduction) | Give the team one place to work on a problem: updates, roles, a timeline and a postmortem. |
| [Status pages](/status-pages/introduction) | Tell your customers what is up and what is down, on your own domain. |
## Start here
Add a monitor, get an alert and publish a status page.
How monitors, alerts, incidents and status pages work together.
Manage everything in your team with the public REST API.
Ask an AI assistant about incidents and let it work in Spectate.
## For developers and AI tools
- The [public API](/developers/api) at `https://api.spectate.net/v1` manages monitors, alerts, incidents, status pages and the team. It uses [team API tokens](/developers/api-tokens).
- The [MCP server](/developers/mcp) at `https://api.spectate.net/mcp` lets AI assistants such as Claude, ChatGPT and Cursor work in Spectate as you.
- Every page of these docs is also available as Markdown. Add `.md` to the URL, for example [/introduction.md](/introduction.md). [llms.txt](/llms.txt) lists all pages, and [llms-full.txt](/llms-full.txt) has all of them in one file.
## Get help
Send an email to [help@spectate.net](mailto:help@spectate.net), or open a support ticket in the dashboard under **Support**. The [service status](https://status.spectate.net) page shows whether Spectate itself has a problem.
---
## Document: Concepts
How monitors, checks, alerts, escalation paths, incidents and status pages work together, and how teams, roles, projects and regions fit in.
URL: /concepts
# Concepts
Spectate turns a failed check into an alert, and an escalation path decides who gets the alert. People work on bigger problems in an incident and tell customers on a status page. This page explains each part and how one leads to the next.
## From a failed check to a status page
1. A **monitor** watches one target, for example `https://example.com/health`, from one region.
2. A **check** is one run of a monitor. Spectate runs a check at each interval, for example every 60 seconds.
3. If a check fails, Spectate checks again about 5 seconds later from the same region. If that check also fails, the monitor is down.
4. Spectate fires an **alert**: "Website is down", with the severity `critical`.
5. The alert follows one or more **escalation paths**. A path is a list of steps: notify a [channel](/alerting/channels), page the person [on call](/alerting/on-call), wait, or create an incident.
6. A **channel** delivers the notification: email, Slack, Discord, Microsoft Teams, Telegram, webhook, Pushover, SMS or a voice call.
7. A person acknowledges the alert. Escalation stops, and the next steps do not run.
8. If the problem needs more work, the team declares an **incident**, or an escalation step creates one.
9. The team publishes the incident on a **status page**, and subscribers get an email.
10. When a check succeeds again, Spectate resolves the alert and sends a resolved notification.
Monitors are one source of alerts. [Hosts](/hosts/introduction), [domains](/domains/introduction), status pages and [alert sources](/alerting/alert-sources) such as Grafana or Sentry also fire alerts. All alerts follow escalation paths in the same way.
## Alerts and incidents
An alert and an incident are different things in Spectate. An alert is a signal from a machine. An incident is the work of people.
| | Alert | Incident |
|---|---|---|
| Starts when | A monitor, host, domain, status page or alert source finds a problem | A member declares it, or an escalation step creates it |
| States | `firing`, `resolved`. A firing alert can also be acknowledged. | `investigating`, `identified`, `monitoring`, `resolved` |
| Ends when | The source recovers, or a member resolves it by hand | A member resolves it |
| Has | A severity, an escalation log, the check result that caused it | Updates, roles, a timeline and a postmortem |
Not every alert needs an incident. A certificate that expires in 14 days is an alert. A checkout page that is down for all customers is an incident.
Spectate deduplicates alerts. While an alert for a problem is firing, the same problem does not fire a second alert. Each alert runs from a copy of its escalation path, made when the alert fires. If you change a path, only new alerts use the change.
Severities, from high to low: `critical`, `high`, `medium`, `low`. See [Alerts](/alerting/alerts) and [Incidents](/incidents/introduction).
## Which escalation paths an alert follows
Spectate looks for escalation paths in this order and uses the first level that has paths:
1. The paths set on the monitor, host, domain or status page itself.
2. The paths of its [project](/account/projects).
3. The team default path.
If none of these exist, the alert notifies nobody. The alert still shows on the **Alerts** page. Spectate skips a disabled path. In the dashboard, the **Alerting** section of a monitor shows which paths its alerts follow.
## Teams, members and roles
All data belongs to a **team**: monitors, hosts, alerts, incidents, status pages and the plan. A person can be a **member** of more than one team, with one role in each team.
| Role | Can do |
|---|---|
| Owner | Everything, including billing and deleting the team. Each team has one owner. |
| Manager | Everything except billing and deleting the team. |
| Admin | Configure monitoring, alerting, incidents and status pages. Cannot manage members, team settings or API tokens. |
| Member | Read everything. Create and change monitors and incidents. Acknowledge and resolve alerts. |
| Billing | Billing and support only. |
See [Teams and roles](/account/teams-and-roles) and [Members](/account/members).
## Projects
A **project** groups monitors, hosts and domains, for example `Production` and `Staging`. A project can have its own escalation paths. Resources in the project follow those paths, unless a resource sets its own paths.
Every team has a default project. New monitors and hosts join it when you do not select another project. You cannot delete the default project. See [Projects](/account/projects).
## Regions
Spectate runs checks from four regions:
| Region | Value in the API |
|---|---|
| Europe | `eu` |
| North America | `us` |
| Asia | `as` |
| Oceania | `oc` |
Each monitor has one primary region. All its checks, rechecks, response times and uptime come from that region. See [Locations and checks](/monitors/locations-and-checks).
---
## Document: Subscribers
Let visitors subscribe to a status page by email with double opt-in, see what they receive and in which language, and manage subscribers and plan limits.
URL: /status-pages/subscribers
# Subscribers
Subscribers get an email when you publish an incident or schedule maintenance on a [status page](/status-pages/introduction). Visitors subscribe on the public page and confirm their address with a link (double opt-in). Only confirmed subscribers get emails.
## How visitors subscribe
1. The visitor selects **Subscribe** in the header of the status page.
2. The visitor types an email address and selects **Subscribe**.
3. Spectate sends an email with the subject "Confirm your subscription to `` status updates".
4. The visitor selects **Confirm subscription** in the email. The link works for 7 days.
After step 4, the subscription is confirmed. Until then, it is pending and gets no updates. If the link expired, the visitor can subscribe again to get a new link.
The public page never shows if an address is already subscribed. To prevent abuse, Spectate accepts 10 subscribe requests per IP address per minute. It sends at most 3 confirmation emails per address per hour.
The **Subscribe** dialog also has an **RSS / Atom** tab with the [feed URLs](/status-pages/introduction#feeds) of the page.
## Turn subscriptions on or off
Subscriptions are on by default. To turn them off, go to **Settings → Display** and clear **Subscriptions**. The **Subscribe** button then disappears, and Spectate accepts no new subscribers. Existing subscribers continue to get emails.
## What subscribers get
Spectate sends one email per event to each confirmed subscriber.
| Event | When | Subject starts with |
|---|---|---|
| `incident_created` | You publish an [incident](/status-pages/incidents). | New incident |
| `incident_updated` | You post an update. | Incident update |
| `incident_resolved` | You resolve an incident. | Resolved |
| `incident_writeup_published` | You first publish a write-up and select **Email subscribers the write-up**. | Write-up |
| `maintenance_scheduled` | You schedule [maintenance](/status-pages/maintenance). | Scheduled maintenance |
| `maintenance_started` | A maintenance starts. | Maintenance in progress |
| `maintenance_completed` | A maintenance completes. | Maintenance completed |
The subject has the form `[] : `. The email shows the status, the impact, the affected components and the update text. A button opens the incident or maintenance on the status page. The sender name is the name of the status page.
The email uses the logo, name and brand colour of the page. Email clients do not show SVG images, so an email from a page with an SVG logo shows the page name instead.
When you publish, **Notify subscribers by email** is selected. Clear it to change the page without an email. Edits, deletes and changes to the impact timeline never send an email.
Subscribers of [private pages](/status-pages/access) also get emails. To subscribe to a private page, the visitor must first open the page.
## Email languages
Spectate sends emails in the language that the visitor saw when they subscribed. A confirmed subscription keeps its language. If Spectate does not know the language, it uses the page language. Supported languages are English, Dutch, German, French, Spanish and Italian. See [languages](/status-pages/appearance#languages).
Spectate translates its own text: the subject, labels, dates, buttons and footer. Your incident titles, updates and component names stay as you wrote them. Dates show in UTC.
## Unsubscribe
Every email has an **Unsubscribe** link. The link opens a page on the status page domain with an **Unsubscribe** button. Email clients that support one-click unsubscribe (the `List-Unsubscribe` header) can also remove the subscription without the page. Unsubscribing deletes the subscription.
## Manage subscribers
The **Subscribers** tab of the status page lists all subscribers.
- The top of the tab shows the number of **Confirmed** and **Pending** subscribers, and **New in the last 30 days**.
- Filter by address, or by state: **All**, **Confirmed** or **Pending**.
- The table shows each **Subscriber**, its **Channel**, **Language**, **State** and when it **Subscribed**.
- Select **Remove** to delete a subscriber. Spectate does not email the subscriber.
Owners, managers and admins can remove subscribers. Members can see the list. You cannot add subscribers by hand: each person subscribes and confirms on the public page.
## Plan limits
The limit is the number of confirmed subscribers of all status pages of the team together. Pending subscriptions do not count.
| Plan | Confirmed subscribers |
|---|---|
| Starter | 250 |
| Team | 2,500 |
| Business | 25,000 |
During the 14-day trial, the Team limit applies. When the team reaches its limit, the **Subscribe** button disappears and pending subscribers cannot confirm. Existing subscribers continue to get emails. See the [pricing page](https://spectate.net/pricing).
## Related
- [Status page incidents](/status-pages/incidents)
- [Status page subscribers in the API reference](/api-reference/status-page-subscribers)
---
## Document: Scheduled maintenance
Announce planned work on a status page, choose the affected components, and let Spectate start and complete the maintenance on schedule.
URL: /status-pages/maintenance
# Scheduled maintenance
Scheduled maintenance tells your customers about planned work before it starts. While a maintenance is in progress, its components show **Maintenance** on the [status page](/status-pages/introduction). Spectate can start and complete it on schedule and email your subscribers at each step.
## Statuses
| Status | Value | Dashboard label | Meaning |
|---|---|---|---|
| Scheduled | `scheduled` | Scheduled | Announced, not started yet. |
| In progress | `in_progress` | In progress | The work is going on. Its components show as under maintenance. |
| Completed | `completed` | Done | The work is over. |
## Schedule maintenance
Owners, managers and admins can schedule maintenance.
1. In the dashboard, open the status page and go to the **Maintenance** tab.
2. Select **Schedule maintenance**.
3. Type a **Title**, for example `Database upgrade`.
4. Optional: type a **Description**, for example `Expect up to 5 minutes of read-only mode.`
5. Set **Starts at**. It must be in the future.
6. Optional: set a **Planned end**.
7. Select the mode: **Automatic** or **Manual**.
8. Under **Affected components**, select the components.
9. Optional: clear **Notify subscribers by email**.
10. Select **Schedule maintenance**.
The dashboard shows times in your own time zone. To affect components, the page must have [components](/status-pages/components) first.
## Automatic and manual mode
| Mode | Start | End |
|---|---|---|
| **Automatic** (default) | Spectate starts it at **Starts at**. | Spectate completes it at **Planned end**. Without a planned end, you complete it yourself. |
| **Manual** | You set it to **In progress**. | You set it to **Done**. |
Spectate checks for maintenance to start or complete every minute. A manual maintenance stays in progress after its planned end until you set it to **Done**. If you switch a manual maintenance to automatic, Spectate applies a start or end that is already past within a minute.
A planned end is optional because the end of the work is often not known.
## Change the status by hand
Each maintenance on the **Maintenance** tab has a status control with **Scheduled**, **In progress** and **Done**. Select a status to change it, also for an automatic maintenance.
## Edit or delete a maintenance
Point at a maintenance on the **Maintenance** tab. Select **Edit** to change the title, description, times, mode or components. You can change **Starts at** only before the maintenance starts. Edits do not email subscribers.
Select **Delete** to remove the maintenance. This is how you cancel it. Deleting does not email subscribers. To tell subscribers that you cancelled the work, post an incident or complete the maintenance instead.
## Component status during maintenance
From its start until it is completed, a maintenance puts its components in `under_maintenance`. An incident impact is worse than maintenance. If an incident affects the same component, the component shows the incident impact.
In the uptime bars, maintenance counts as up. It does not lower the uptime of a component.
## How visitors see maintenance
- **Before the start.** The page shows the maintenance with the time until it starts.
- **During the work.** The maintenance shows under **Happening now**, with the time remaining until the planned end. If the planned end has passed, the page shows **Running over**.
- **After the end.** The maintenance shows as completed, with how long the work took.
Each maintenance has its own page at `/maintenances/`, with the window, the planned end, the components and the description.
To hide maintenance from the public page, clear **Scheduled maintenance** in **Settings → Display**.
## Subscriber emails
Spectate emails confirmed [subscribers](/status-pages/subscribers) at three moments:
| Event | Email |
|---|---|
| You schedule the maintenance | Scheduled maintenance |
| The maintenance starts | Maintenance in progress |
| The maintenance completes | Maintenance completed |
If you clear **Notify subscribers by email** when you schedule, Spectate does not send the "Scheduled maintenance" email. Automatic starts and ends always send an email. Edits and deletes never send an email.
## Feeds
The [RSS and Atom feeds](/status-pages/introduction#feeds) of the page contain scheduled, in progress and completed maintenance, together with the incidents. Spectate adds a maintenance to the feeds when you schedule it. Its place in the feed is the time you scheduled it, not its start time.
Each maintenance item has:
| Part | Content |
|---|---|
| Title | "Scheduled maintenance:" and the title of the maintenance |
| Link | The page of the maintenance, `/maintenances/` |
| Content | The status, the window from **Starts at** to **Planned end**, the completion time, the affected components and the description |
Times in the feed are in UTC. When the status changes, the Atom entry gets a new `updated` time. The ID of the item does not change. To remove maintenance from the feeds, clear **Scheduled maintenance** in **Settings → Display**.
## Related
- [Components and their status](/status-pages/components)
- [Scheduled maintenance in the API reference](/api-reference/scheduled-maintenance)
---
## Document: Status page JSON API
Read the status of any Spectate status page as JSON in the Atlassian Statuspage v2 format, for status aggregators, chat bots and dashboards.
URL: /status-pages/json-api
# Status page JSON API
Every Spectate status page serves its status as JSON in the Atlassian Statuspage v2 format. Tools that read Statuspage pages, such as status aggregators, chat bots and dashboards, can read a Spectate page without changes. The API is read-only, needs no token for public pages, and any website can call it.
## Endpoints
All endpoints are on the domain of the page: the default address `https://.spectate.page`, or the [custom domain](/status-pages/custom-domains).
| Endpoint | Returns |
|---|---|
| `GET /api/v2/summary.json` | The page, all components, unresolved incidents, maintenance in progress and upcoming, and the overall status. |
| `GET /api/v2/status.json` | The page and the overall status. |
| `GET /api/v2/components.json` | The page and all components. |
| `GET /api/v2/incidents.json` | The page and the 50 newest incidents. |
| `GET /api/v2/incidents/unresolved.json` | The page and the incidents that are not resolved. |
| `GET /api/v2/scheduled-maintenances.json` | The page and the 50 maintenances with the latest start. |
| `GET /api/v2/scheduled-maintenances/upcoming.json` | The page and the maintenances with the status `scheduled`. |
| `GET /api/v2/scheduled-maintenances/active.json` | The page and the maintenances with the status `in_progress`. |
The **Overview** tab of the status page in the dashboard shows the `summary.json` URL of the page.
## Example
```bash
curl https://acme.spectate.page/api/v2/status.json
```
```json
{
"page": {
"id": "9b2f6d1e-4c3a-4f7e-8a51-2d0c9e7b6a14",
"name": "Acme Cloud",
"url": "https://acme.spectate.page",
"time_zone": "Etc/UTC",
"updated_at": "2026-10-27T09:41:12Z"
},
"status": {
"indicator": "major",
"description": "Partial System Outage"
}
}
```
`summary.json` returns `page`, `components`, `incidents`, `scheduled_maintenances` and `status`:
```json
{
"page": { "id": "9b2f6d1e-...", "name": "Acme Cloud", "url": "https://acme.spectate.page", "time_zone": "Etc/UTC", "updated_at": "2026-10-27T09:41:12Z" },
"components": [
{
"id": "5e0c2a77-...",
"name": "Core services",
"status": "partial_outage",
"created_at": "2026-03-02T10:00:00Z",
"updated_at": "2026-10-27T09:12:00Z",
"position": 1,
"description": null,
"showcase": false,
"start_date": null,
"group_id": null,
"page_id": "9b2f6d1e-...",
"group": true,
"only_show_if_degraded": false,
"components": ["c41d8e02-..."]
},
{
"id": "c41d8e02-...",
"name": "API",
"status": "partial_outage",
"created_at": "2026-03-02T10:00:00Z",
"updated_at": "2026-10-27T09:12:00Z",
"position": 2,
"description": "Public REST API",
"showcase": true,
"start_date": "2026-03-02",
"group_id": "5e0c2a77-...",
"page_id": "9b2f6d1e-...",
"group": false,
"only_show_if_degraded": false
}
],
"incidents": [
{
"id": "0f7a3b9c-...",
"name": "Elevated API error rates",
"status": "identified",
"created_at": "2026-10-27T09:14:30Z",
"updated_at": "2026-10-27T09:41:12Z",
"monitoring_at": null,
"resolved_at": null,
"impact": "major",
"shortlink": "https://acme.spectate.page/incidents/0f7a3b9c-...",
"started_at": "2026-10-27T09:12:00Z",
"page_id": "9b2f6d1e-...",
"incident_updates": [
{
"id": "a83e5d10-...",
"status": "identified",
"body": "We found the cause and are applying a fix.",
"incident_id": "0f7a3b9c-...",
"created_at": "2026-10-27T09:41:12Z",
"updated_at": "2026-10-27T09:41:12Z",
"display_at": "2026-10-27T09:41:12Z"
}
],
"components": [{ "id": "c41d8e02-...", "name": "API", "status": "partial_outage" }]
}
],
"scheduled_maintenances": [],
"status": { "indicator": "major", "description": "Partial System Outage" }
}
```
The example shortens IDs and the components of the incident. The API returns full UUIDs and full component objects.
## Fields
### Overall status
| Page headline | `indicator` | `description` |
|---|---|---|
| All components operational | `none` | All Systems Operational |
| Degraded performance | `minor` | Minor Service Outage |
| Partial outage | `major` | Partial System Outage |
| Full outage | `critical` | Major System Outage |
| Maintenance | `maintenance` | Service Under Maintenance |
### Components
A component's `status` is `operational`, `degraded_performance`, `partial_outage`, `major_outage` or `under_maintenance`. See [component statuses](/status-pages/components#component-statuses).
A group is a component with `group: true`. Its `components` field lists the IDs of its components. Each component in a group has the group's ID in `group_id`. The status of a group is the worst status of its components.
### Incidents
| Field | Values |
|---|---|
| `status` | `investigating`, `identified`, `monitoring` or `resolved` |
| `impact` | `none`, `minor` (degraded performance), `major` (partial outage) or `critical` (full outage). The worst current impact, or the worst impact it had once it is resolved. |
| `started_at` | The earliest of the first impact, the first update and the creation of the incident. |
| `monitoring_at`, `resolved_at` | The time of the first update with that status, or `null`. |
| `incident_updates` | The public updates. `created_at` and `display_at` are the **Happened at** time of the update. |
| `components` | Every component that the incident affected, also after it is resolved. |
| `shortlink` | The incident page on the status page. |
### Scheduled maintenances
Maintenances have the same fields as incidents, and also these:
| Field | Values |
|---|---|
| `status` | `scheduled`, `in_progress` or `completed` |
| `impact` | Always `maintenance`. |
| `scheduled_for` | The planned start. |
| `scheduled_until` | The planned end, or `null`. |
| `started_at` | When the maintenance went in progress, or `null`. |
| `incident_updates` | One update with the description of the maintenance, or empty without a description. |
## Private pages
A [private page](/status-pages/access) returns `404` without access. Add the access key of the page to the URL:
```bash
curl "https://acme.spectate.page/api/v2/summary.json?key=YOUR_ACCESS_KEY"
```
Responses of a private page have `Cache-Control: private, no-store`. Anyone with the key can read the page, so keep the key out of public code.
## Caching and errors
Spectate builds the data of a page at most once per 30 seconds. Public responses have `Cache-Control: public, max-age=30`. A change can take up to 30 seconds to show in the API.
| Status | Body | When |
|---|---|---|
| `200` | The resource | The page exists and you have access. |
| `404` | `{"error": "Not found"}` | The page or resource does not exist, the page is private without a valid key, or the path does not end in `.json`. |
| `503` | `{"error": "Unavailable"}` | Spectate cannot read the page right now. The response has `Retry-After: 30`. |
## CORS
Every response has `Access-Control-Allow-Origin: *`, so a script on any website can read the API. `OPTIONS` requests return `204` with `Access-Control-Allow-Methods: GET, OPTIONS`.
## Differences from Atlassian Statuspage
- `time_zone` is always `Etc/UTC`. All times are UTC, in the format `2026-10-27T09:41:12Z`.
- Spectate calculates group IDs from the page and the group name. If you rename a group, its ID changes.
- `showcase` is `true` for components and `false` for groups. `only_show_if_degraded` is always `false`. `start_date` is the date that the component was created.
- Incidents never have the status `postmortem`. Maintenances never have the status `verifying`.
- A maintenance has no separate updates. Its description is its only update.
- If you hide incidents or maintenance in **Settings → Display**, `incidents` or `scheduled_maintenances` is an empty list.
- The API is read-only. It has no endpoints for subscribers or for changes. To change a status page, use the [public API](/developers/api) of Spectate.
## Related
- [RSS and Atom feeds](/status-pages/introduction#feeds)
- [Status pages in the API reference](/api-reference/status-pages)
---
## Document: Issue reports and traffic alerts
Let visitors report problems from a status page, get an alert when several report within minutes, and get an alert when page traffic spikes.
URL: /status-pages/issue-reports
# Issue reports and traffic alerts
Your customers often notice a problem before your monitors do. With issue reports, visitors of a [status page](/status-pages/introduction) can tell your team that something does not work. When enough visitors report within a short time, Spectate fires an [alert](/alerting/alerts). A second alert fires when the page gets much more traffic than usual.
## Turn on issue reports
Issue reports are off by default. Owners, managers and admins can turn them on.
1. In the dashboard, open the status page and go to **Settings → Visitor reports**.
2. Select **Let visitors report problems**.
3. Set the **Threshold**: the number of reports, 1 to 1000. The default is 5.
4. Set **Within**: the time window in minutes, 1 to 1440. The default is 10.
5. Optional: select **Tell visitors when others report problems too**.
6. Select **Save visitor reports**.
## What visitors send
With issue reports on, the public page shows a **Report a problem** link above the components and in the footer. The dialog has three fields, and all are optional:
- **Affected components**: the components that do not work for the visitor.
- **What's wrong?**: a message of up to 1000 characters.
- **Email**: an address, only if the visitor wants a reply.
The visitor selects **Send report**. The dialog has no captcha. Spectate drops reports from bots with a hidden field and a minimum time of 2 seconds to fill in the form.
## Limits per visitor
| Limit | Value |
|---|---|
| Reports that count, per visitor IP address and page | 1 per time window |
| Reports per visitor IP address, all pages | 10 per hour |
| Reports per page | 500 per time window |
Because each visitor counts once per window, the threshold is the number of different visitors. A visitor who sends a second report in the same window sees "You already reported a problem a few minutes ago".
## When many visitors report
When the number of reports in the time window reaches the threshold, the page is **Above threshold**. Spectate then does these things:
- It fires the alert "Visitors are reporting problems on ``" with severity high. Turn this off in **Settings → Alerting** with **Visitors report problems**.
- If you selected **Tell visitors when others report problems too**, the page shows "Users are reporting issues" under **Happening now**. The notice says that nothing has been confirmed yet. It does not show while an incident is open.
Issue reports never change the status of a component or the headline. Only [incidents](/status-pages/incidents) and [maintenance](/status-pages/maintenance) do that.
Spectate checks every minute. After a full time window without a new report, Spectate removes the notice and resolves the alert. If you turn off issue reports or their alert, Spectate also resolves a firing alert.
## Where the alerts go
Alerts from a status page go to the escalation paths that you select in **Settings → Alerting**. Without a selection, they go to the team default [escalation path](/alerting/escalation-paths). Status pages are not part of a project.
## Read the reports
The **Reports** tab of the status page lists all reports, newest first. The table shows when each report came in (**Reported**), **What's wrong**, the **Components** and **Reply to**. The top of the tab shows whether the page is above the threshold right now.
Select **Delete** on a report to remove it, for example to remove an email address.
Only owners, managers and admins see the email addresses of reporters. Members see **Hidden**.
## Privacy
Spectate stores the components, the message, the email address and the time of each report. It does not store the IP address or the browser of the visitor. Spectate uses a hash of the IP address only for the rate limits.
## Traffic spike alerts
A sudden rise in page views is often the first sign that customers notice a problem. Spectate counts the views of each status page and compares the last 15 minutes with the usual traffic at that time of day.
Spectate fires the alert "Traffic to `` is ``× normal" with severity medium when both of these are true:
- The views of the last 15 minutes are at least the **Multiplier** times the usual views. The usual views are the median of the same 15 minutes on each of the last 28 days, and at least 3.
- The views of the last 15 minutes are at least the **Minimum views**.
| Setting | Default | Range |
|---|---|---|
| **Multiplier** | 5 | 2 to 100 |
| **Minimum views** | 25 per 15 minutes | 10 or more |
Spectate checks every 5 minutes. The alert resolves when the views drop below three quarters of the threshold. Pages younger than 7 days never fire this alert.
Traffic spike alerts are on for new pages. Change them in **Settings → Alerting** under **Traffic spikes**.
Spectate counts one view per visitor IP address per page per 10 minutes. It does not count bots, automatic refreshes, feeds or share images. It stores only the number of views per minute, without IP addresses, browsers or referrers. The **Overview** tab shows the views per hour of the last 7 days, with the usual views as a dashed line.
## Related
- [Alerts](/alerting/alerts)
- [Status page issue reports in the API reference](/api-reference/status-page-issue-reports)
---
## Document: Status pages
What a Spectate status page shows, its default address, how to create one, plan limits, feeds, the share image and accessibility.
URL: /status-pages/introduction
# Status pages
A status page tells your customers which of your services work and which do not. Spectate status pages show components, 90 days of uptime, incidents and scheduled maintenance. Each page has its own address on `spectate.page`, or on [your own domain](/status-pages/custom-domains).
## What a status page shows
| Part | What visitors see |
|---|---|
| Headline | The worst status of all [components](/status-pages/components), for example "All systems operational" or "Partial outage". |
| Happening now | Open [incidents](/status-pages/incidents) and [maintenance](/status-pages/maintenance) in progress. |
| Components | Each component with its status, grouped if you use groups. |
| Uptime bars | One bar per day for the last 90 days, under each component. |
| Latency chart | The response time of the last 24 hours, for components linked to a monitor. |
| Past incidents | Incidents of the last 7 days, with a link to the full history. |
| History | The **History** page: past incidents and the daily uptime of each component. |
Visitors can open each incident and each maintenance on its own page, at `/incidents/` and `/maintenances/`. The main page refreshes itself every 60 seconds.
## Display settings
You choose which sections the public page shows in **Settings → Display**. All of them are on by default.
| Setting | What it controls |
|---|---|
| **90-day uptime history** | The daily bars under each component. |
| **Latency charts** | The latency chart of components linked to a monitor with charts enabled. |
| **Incidents** | Active incidents and the incident history. |
| **Scheduled maintenance** | Upcoming and in-progress maintenance. |
| **Subscriptions** | The **Subscribe** button for [email subscribers](/status-pages/subscribers). |
| **Uptime bars** | **Fill by duration** (default) colours the part of a day that a problem lasted. **Whole day** colours the full bar. |
| **Incident history layout** | **90-day calendar** (default) or **Timeline** on the **History** page. |
With **Fill by duration**, a 20-minute outage colours a small part of the bar, not the full day. Days in the uptime bars and the history are UTC days. Other times show in the time zone of the visitor.
## Default address
Every status page has the address `https://.spectate.page`. The slug is one DNS label: lowercase letters, digits and hyphens, at most 63 characters. Some slugs, such as `www`, `api` and `status`, are reserved.
The default address continues to work when you add a custom domain. If you change the slug in **Settings → General**, the old address stops working.
## Create a status page
Owners, managers and admins can create and change status pages. Members can see them.
1. In the dashboard, go to **Status pages**.
2. Select **Create status page**.
3. Type a **Name**, for example `Acme Cloud`.
4. Optional: change the **Slug**. Spectate makes it from the name.
5. Select the **Visibility**: **Public** or **Private**.
6. Select **Create status page**.
The new page has no components. Add them on the **Components** tab, then publish incidents and maintenance from the **Incidents** and **Maintenance** tabs. The **Overview** tab shows the public URL, the subscribers, the page views of the last 7 days and the open incidents.
## Plan limits
The number of status pages depends on the plan of the team.
| Plan | Status pages | Private pages |
|---|---|---|
| Starter | 1 | No |
| Team | 5 | Yes |
| Business | No limit | Yes |
During the 14-day trial, a team has the limits of the Team plan. All paid plans include custom domains and password protection. If a team has more pages than its plan allows, Spectate pauses the newest pages. The oldest pages stay online. A paused page is not served until the plan has room for it again. See [plans and billing](/account/plans-and-billing) and the [pricing page](https://spectate.net/pricing).
## Feeds
Every status page has an RSS feed and an Atom feed with its incidents and scheduled maintenance:
- RSS: `https://.spectate.page/feed/rss`
- Atom: `https://.spectate.page/feed/atom`
The feeds contain the 20 newest items, newest first. Spectate sorts incidents and maintenance together by the time you posted them. A maintenance item starts with "Scheduled maintenance:" and shows its status, its window and its affected components. See [scheduled maintenance](/status-pages/maintenance#feeds).
The feeds follow the **Settings → Display** settings of the page. If you clear **Incidents**, the feeds contain no incidents. If you clear **Scheduled maintenance**, the feeds contain no maintenance.
Each item keeps the same ID when you edit it, so feed readers do not show it again as a new item.
The footer of the page links to both feeds. The **Subscribe** dialog shows them under **RSS / Atom**. The feed title, the maintenance labels and the dates use the language of the page. For a private page, add the access key to the feed URL: `/feed/rss?key=`. See [access and visibility](/status-pages/access).
## Share image and status favicon
When someone shares a link to the page in Slack, X or LinkedIn, the preview shows a share image. The image shows the current status, or the incident or maintenance of the link. Spectate makes a new image URL when the status changes, so these platforms show the new status.
The browser tab icon follows the status. With all components operational, the tab shows a check. During an incident, it shows an exclamation mark in the status colour. During maintenance, it shows a clock. If you uploaded your own PNG, JPEG or SVG favicon, the tab shows your favicon with a dot in the status colour.
## Accessibility
Status pages meet WCAG 2.1 level AA:
- Text and status colours have a contrast of at least 4.5:1. Spectate adjusts the text colours of a [custom theme](/status-pages/appearance) until they meet this ratio.
- A **Skip to content** link lets keyboard users go past the header.
- Visitors can move through the days of an uptime bar with the arrow keys.
- The `lang` attribute of the page is the language that the visitor sees.
- Animations stop when the visitor's device asks for reduced motion.
Visitors can switch between light and dark mode with a button in the header.
## Related
Add components and link them to monitors.
Publish incidents and updates for your customers.
Serve the page from your own domain.
Read the status in the Atlassian Statuspage format.
---
## Document: Intercom Messenger app
Show the status of a Spectate status page and its open incidents in the Intercom Messenger, so customers see known problems before they ask.
URL: /status-pages/intercom
# Intercom Messenger app
The Spectate app for Intercom shows a [status page](/status-pages/introduction) in your Intercom Messenger. Customers see the current status and the open incidents before they start a conversation. Each Intercom workspace shows one status page.
## Connect a workspace
Owners, managers and admins can connect Intercom.
1. In the dashboard, go to **Integrations**.
2. Under **Status pages**, next to **Intercom Messenger**, select **Connect**.
3. Select **Connect workspace**.
4. In Intercom, allow Spectate to access the workspace.
5. Back in the dashboard, select the **Status page** to show in the Messenger.
6. Select **Complete setup**.
The team must have a status page before you connect. Then add the Spectate app to the Messenger home in your Intercom settings.
Spectate requests no Intercom permissions and stores no Intercom token. It uses the token once, to read the ID of the workspace.
## What customers see
| Item | Content |
|---|---|
| Status | "Status: " and the headline of the page, for example "Status: Partial Outage", with an icon and the time of the last refresh. The item opens the status page. |
| Open incidents | Up to 3 unresolved incidents, each with its title and the start of its newest update (120 characters). Each item opens the incident page. |
The Messenger asks Spectate for the status each time it shows the app. Spectate keeps the answer for 60 seconds.
For a [private or password-protected page](/status-pages/access), the Messenger shows only the status. It does not show incident titles or updates.
## Change the status page
To show another status page, connect the workspace again and select the other page. A workspace shows one page. Connecting it again moves it to the new page.
To show status pages in several Intercom workspaces, select **Connect another** on the **Integrations** page. The page lists each connected workspace with the status page that it shows.
## Health check
Intercom checks every connected app once a day. If the workspace is not connected to a status page, Spectate reports the app as unhealthy. Intercom then shows a **Finish setup** link to the connect page of the Spectate dashboard.
If the workspace is not connected, the Messenger shows "This status page is not available right now."
## Workspaces from Spectate v1
Workspaces that you connected in the previous version of Spectate continue to work. You do not need to connect them again.
## Related
- [Access and visibility](/status-pages/access)
- [Status page incidents](/status-pages/incidents)
---
## Document: Status page incidents
Publish public incidents on a status page, post updates with an impact per component, edit the impact timeline, write a public write-up and notify subscribers.
URL: /status-pages/incidents
# Status page incidents
A status page incident tells your customers about a problem, in your words. It has a title, a status, public updates and an impact on each affected component. The impacts set the [status of the components](/status-pages/components) and the uptime bars. Your team's own [incidents](/incidents/introduction) stay internal until you publish to a status page.
## Statuses and impacts
Each update gives the incident a status. The incident has the status of its newest update.
| Status | Value | Meaning |
|---|---|---|
| Investigating | `investigating` | The cause is not known yet. |
| Identified | `identified` | The cause is known and someone works on it. |
| Monitoring | `monitoring` | A fix is out. The team watches whether it holds. |
| Resolved | `resolved` | The problem is over. |
Each affected component gets an impact: **Degraded** (`degraded_performance`), **Partial outage** (`partial_outage`) or **Full outage** (`major_outage`). **Not affected** means no impact. If the page has no components, the incident has one **Impact** of its own, and the headline of the page follows it.
## Publish an incident
Owners, managers and admins can publish incidents.
1. In the dashboard, open the status page and go to the **Incidents** tab.
2. Select **New public incident**.
3. Type a **Title**, for example `Elevated API error rates`.
4. Select the status.
5. Under **Affected components**, select an impact for each affected component.
6. Type the **Initial update**. You can use Markdown.
7. Optional: set **Happened at** to a time in the past. The default is now.
8. Optional: clear **Notify subscribers by email** to publish without an email.
9. Select **Publish incident**.
The incident shows on the public page at once. Each affected component gets its impact from the **Happened at** time. The headline follows the worst impact.
## Post an update
1. Open the incident on the **Incidents** tab.
2. In **Post update**, select the new status.
3. Change the impact of each component, if the impact changed.
4. Type the **Update**.
5. Optional: set **Happened at** and clear **Notify subscribers by email**.
6. Select **Post update**.
An update states the impact of each component as of its **Happened at** time. A changed impact starts at that time. A component that you set to **Not affected** stops being affected at that time.
If you select **Resolved**, Spectate ends every ongoing impact at the time of the update. The affected components go back to operational, unless another incident or a maintenance still affects them.
## Edit and delete updates
The **Public timeline** on the incident lists all updates, newest first. Point at an update to edit or delete it.
- **Edit** changes the **Status**, **Happened at** time and **Message** of the update. If you move **Happened at**, the impact changes of that update move with it.
- **Delete** removes the update. The impact periods stay.
Edits and deletes are silent. Spectate does not email subscribers again.
To change the title, use **Incident details** and select **Save incident**. These edits are also silent.
## Edit the impact timeline
The **Impact timeline** shows one row per component, with a bar for each period of impact. Use it to correct the history, for example if the outage started at 09:12 and you posted at 09:40.
- Select a bar to change the **Component**, the impact, **Started** or **Ended**, or to delete the period.
- Select **Add period** to add a period. Select **Ongoing** for a period that has not ended.
Periods of one component in one incident cannot overlap. **Ended** must be after **Started**. Both times can be at most one minute in the future. A resolved incident needs an end time on every period.
Spectate calculates the component status and uptime again after each edit. Timeline edits never email subscribers.
## Publish from a team incident
You can publish to a status page from a team incident. The public incident is linked to the team incident.
1. Open the incident under **Incidents** in the dashboard.
2. In the **Status pages** panel, select **Publish**.
3. Select the **Status page**.
4. Select the **Public status** and the impact of each component.
5. Type the **Subscriber-facing update**.
6. Optional: set **Happened at** and clear **Notify subscribers by email**.
7. Select **Publish update**.
The first publication creates the public incident, with the title of the team incident. Later publications to the same page add updates to that public incident. Your role must allow you to change both the incident and the status page.
You can also publish from [Slack](/alerting/slack) with `/spectate status-page`, or ask an AI assistant through the [MCP server](/developers/mcp).
## Automatic incidents
Monitors that are linked to components can open and resolve public incidents. Turn this on in **Settings → Automation**. An automatic incident has the label **Automatic** in the dashboard. If you post an update or edit its impact timeline, you take it over and automation stops changing it. See [automatic incidents from monitors](/status-pages/components#automatic-incidents-from-monitors).
## Write a public write-up
A write-up explains to visitors what happened, why, and what you change. It is separate from the internal [postmortem](/incidents/postmortems). Spectate never publishes the postmortem.
1. Open the incident on the **Incidents** tab.
2. In **Public write-up**, type the text in Markdown. Or select **Start from postmortem** to copy the postmortem of the linked team incident into the editor.
3. Select **Published on the status page**.
4. Optional: select **Email subscribers the write-up**.
5. Select **Publish write-up**.
A published write-up shows above the updates on the public incident page. Without **Published on the status page**, the write-up is a draft that only your team sees. Select **Save draft** to keep it.
Spectate emails the write-up only once, when you first publish it. Later edits never send an email. **Unpublish** removes the write-up from the public page.
## Delete an incident
Deleting removes the incident, its updates and its impact periods from the public page and from the uptime history. Spectate does not email subscribers. Resolving keeps the public history, so it is usually the better choice.
1. Open the incident and go to **Incident details**.
2. Select **Delete incident**.
3. Confirm with **Delete incident**.
## When Spectate emails subscribers
Spectate emails confirmed [subscribers](/status-pages/subscribers) in these cases, unless you clear **Notify subscribers by email**:
| Action | Email |
|---|---|
| Publish an incident | New incident |
| Post an update | Incident update |
| Post an update with **Resolved** | Resolved |
| Publish a write-up with **Email subscribers the write-up** | Write-up |
| Automation opens, updates or resolves an incident | As above, always |
Edits of details, updates and the impact timeline never send an email. Deleting never sends an email.
## Related
- [Components and their status](/status-pages/components)
- [Subscribers](/status-pages/subscribers)
- [Status page incidents in the API reference](/api-reference/status-page-incidents)
---
## Document: Custom domains
Serve a status page from your own domain, such as status.example.com. Add the DNS records, verify the domain and get HTTPS automatically.
URL: /status-pages/custom-domains
# Custom domains
A custom domain serves your [status page](/status-pages/introduction) from your own hostname, for example `status.example.com`. You add one DNS record, Spectate verifies that you own the domain, and the first HTTPS visit gets a certificate. The default address `https://.spectate.page` continues to work.
All paid plans and the trial include custom domains. Owners, managers and admins can add them.
## Add a custom domain
1. In the dashboard, open the status page and go to the **Domain** tab.
2. Type the **Hostname**, for example `status.example.com`.
3. Select **Add domain**.
4. Add the DNS records that the **DNS records** section shows, at your DNS provider.
5. Select **Check DNS**.
When the check finds a correct record, the section shows **Domain verified**. DNS changes can take some time to reach all resolvers. If the check finds nothing, wait and select **Check DNS** again. Spectate does not check again by itself.
A subdomain such as `status.example.com` is the easiest choice: one CNAME record verifies the domain and sends visitors to Spectate.
## DNS records
Every status page with a custom domain has its own CNAME target, for example `3f9a1c07b2e4d856.custom.spectate.page`. Only this page uses it. The **DNS records** section shows the target of your page. Copy the values from there.
### Subdomain
Add one CNAME record:
| Type | Name | Value |
|---|---|---|
| `CNAME` | `status.example.com` | The page's target, for example `3f9a1c07b2e4d856.custom.spectate.page` |
This record verifies the domain and routes the visitors.
If you cannot add a CNAME record, for example because a proxy is in front of the domain, verify with a TXT record instead:
| Type | Name | Value |
|---|---|---|
| `TXT` | `_spectate.status.example.com` | The token from the dashboard, for example `spectate-verify=...` |
The TXT record only proves that you own the domain. Visitors must still reach Spectate, through a CNAME to the page's target or through the same IP addresses.
### Root domain
A root domain such as `example.com` cannot have a CNAME record. Add both of these records:
| Type | Name | Value |
|---|---|---|
| `TXT` | `_spectate.example.com` | The token from the dashboard |
| `ALIAS` | `example.com` | The page's target |
Use the ALIAS, ANAME or CNAME flattening record of your DNS provider. If your provider has none of these, add `A` and `AAAA` records with the addresses that `dig +short ` returns. These addresses can change, so an ALIAS record is better. You can also use a subdomain instead.
## Check results
For each record, the **DNS records** section shows what DNS returns:
| Result | Meaning |
|---|---|
| **Found** | The record has the expected value. |
| **Points at** `` | A record exists, with a different value. |
| **Not found** | DNS returns no record. |
**Traffic reaches Spectate** shows **Yes** when the domain points at Spectate, by the CNAME or by the same IP addresses. Otherwise it shows the address that the domain resolves to, or **Not yet**.
One correct record verifies the domain: the CNAME to the page's target, or the TXT token. After that, the domain stays verified, also if a later check fails.
:::caution
A CNAME to a shared Spectate host, such as `status.spectate.page`, does not verify a domain. Only the target of your own page or the TXT token proves that you own it. This stops other teams from claiming a domain that still points at Spectate.
:::
## HTTPS
You do not need to configure HTTPS. Spectate gets a certificate on the first HTTPS visit to the domain, after the domain is verified and points at Spectate. This first request can take a few seconds. Spectate renews the certificate automatically.
Spectate gets certificates only for verified domains of status pages that are not paused. This applies to public, private and password-protected pages.
## Change or remove the domain
To change the domain, type the new hostname and select **Update domain**. The new domain gets a new TXT token and must be verified again. The CNAME target of the page stays the same.
To remove the domain, select **Remove domain**. The page then has only its default address.
## What can go wrong
| Problem | Result | What to do |
|---|---|---|
| The domain is not verified. | Spectate does not serve the page on the domain and gets no certificate. | Add the CNAME or TXT record, then select **Check DNS**. |
| **Traffic reaches Spectate** is not **Yes**. | Visitors do not reach the page. | Point the domain at the page's target with a CNAME or ALIAS record. |
| The CNAME points at another host. | The check shows **Points at** with that host. | Change the CNAME to the target shown in the dashboard. |
| The hostname is under `spectate.page`, or another page uses it. | The dashboard rejects the hostname. | Use a domain that you own and that no other status page uses. |
| The page is paused because of the plan limit. | Spectate does not serve the page or issue a certificate. | Upgrade the plan or delete another status page. |
The **Integrations** page of the dashboard lists all custom domains of the team, with **Verified** or **Awaiting DNS**.
## Pages from Spectate v1
Pages that moved from the previous version of Spectate keep their verified domain and their target `.custom.spectate.page`. A CNAME to the old shared target `cname.spectate.page` continues to work for these domains. It does not verify a new domain.
## Related
- [Access and visibility](/status-pages/access)
- [Status pages in the API reference](/api-reference/status-pages)
---
## Document: Components
Add components to a status page, group them, link them to monitors, and learn how Spectate sets each component's status from incidents and maintenance.
URL: /status-pages/components
# Components
A component is a part of your service that customers see on a [status page](/status-pages/introduction), for example "API", "Website" or "Checkout". Spectate sets the status of each component from the incidents and maintenance that you publish. You do not set a component's status by hand.
## Add a component
1. In the dashboard, open the status page and go to the **Components** tab.
2. Select **Add component**.
3. Type a **Name**, for example `API`.
4. Optional: type a **Group**, for example `Core services`.
5. Optional: type a **Description**. Visitors see it on the public page.
6. Optional: select a **Linked monitor**.
7. Select **Create component**.
New components go to the end of the list. Use **Move up** and **Move down** on a component to change the order. Use **Edit** to change a component and **Delete** to remove it.
## Groups
A group is a heading with components under it. To put a component in a group, type the group name in the **Group** field. Components without a group show under **Ungrouped** in the dashboard.
Each group has a default state on the public page: **Expanded** or **Collapsed**. Visitors can open and close a group. The default state only sets how the group shows when the page loads.
## Component statuses
| Status | Value | Public label | Meaning |
|---|---|---|---|
| Operational | `operational` | Operational | Works normally. |
| Degraded | `degraded_performance` | Degraded performance | Slower or less reliable than usual. |
| Partial outage | `partial_outage` | Partial outage | Down for some visitors or some functions. |
| Full outage | `major_outage` | Full outage | Down. |
| Maintenance | `under_maintenance` | Maintenance | In planned maintenance. |
## How Spectate sets the status
A component's status is the worst of these, in this order:
1. The worst impact on the component from open [incidents](/status-pages/incidents). An incident impact is `degraded_performance`, `partial_outage` or `major_outage`.
2. `under_maintenance`, if a [maintenance](/status-pages/maintenance) that affects the component is in progress.
3. `operational`, if nothing else applies.
Any incident impact is worse than maintenance. Spectate calculates the status again each time an incident, an update, an impact period or a maintenance changes. When you resolve an incident, its components go back to `operational`, unless another incident or maintenance still affects them.
The headline of the page is the worst status of all components. On the **Components** tab, each component shows its status and the incident or maintenance that causes it, for example "Partial outage · from API errors".
### Change a component's status
You cannot set a status on a component directly. To change it, do one of these:
- Publish an incident, or post an update, with an impact on the component.
- Edit the impact timeline of an incident. See [incidents](/status-pages/incidents).
- Schedule a maintenance that affects the component.
## Link a monitor
Link a component to an [uptime monitor](/monitors/introduction) to get measured uptime and latency, and to let the monitor open incidents. Select the monitor in the **Linked monitor** field. You can link one monitor per component, from the same team. You cannot link a host.
A linked monitor gives the component these things:
- **Measured uptime.** The uptime bars use the checks of the monitor. A day's colour is the worse of the measured downtime and the incident impacts of that day.
- **A latency chart.** Turn on **Show primary-region latency chart** on the component. The chart shows the response time of the last 24 hours. It only shows for components with a linked monitor.
- **Automatic incidents.** These need the automation setting of the page. See below.
A linked monitor does not change the component's status by itself. Only incidents and maintenance change the status.
Components without a monitor also have an uptime history. Spectate calculates it from the incident impacts. `partial_outage` and `major_outage` count as down. `degraded_performance` and maintenance count as up.
## Automatic incidents from monitors
With automation, a monitor opens and resolves a public incident for each component that it is linked to.
1. Go to **Settings → Automation** on the status page.
2. Select **Open and resolve incidents from linked monitors**.
3. Optional: type a **Down message** and a **Recovered message**.
4. Select **Save automation**.
Automation is off by default. When it is on, Spectate does these things:
- **The monitor goes down.** When the downtime alert of the monitor fires, Spectate opens an incident "`` is down" with the status `investigating`. The component gets `major_outage` from the time the monitor went down.
- **The monitor recovers.** When the alert resolves, Spectate resolves the incident at the recovery time, with the recovered message.
- **The monitor fails again within 30 minutes.** Spectate opens the same incident again, not a new one.
- **Another open incident already affects the component.** Spectate does not open a second incident.
Each component gets its own incident, also when several monitors fail at the same time. If the alert opened a team [incident](/incidents/introduction), Spectate links the public incident to it. Spectate emails subscribers about automatic incidents as for incidents that you publish.
Empty messages use the defaults:
| Message | Default |
|---|---|
| **Down message** | `We are investigating an outage affecting {component}.` |
| **Recovered message** | `{component} has recovered and is operating normally.` |
In all messages, Spectate replaces `{component}` with the component name and `{status_page}` with the page name.
### Take over an automatic incident
The dashboard marks an automatic incident with **Automatic**. If a person posts an update or edits the impact timeline, the incident is no longer automatic. After that, automation does not change or resolve it.
## Related
- [Status page incidents](/status-pages/incidents)
- [Scheduled maintenance](/status-pages/maintenance)
- [Status page components in the API reference](/api-reference/status-page-components)
---
## Document: Appearance and languages
Brand a status page with a logo, favicon, colours, theme mode and font, and choose its language. Learn how Spectate keeps text readable.
URL: /status-pages/appearance
# Appearance and languages
You can make a [status page](/status-pages/introduction) look like your own product. Set a logo, a favicon, a brand colour, a colour preset, the mode that visitors see first and a font. The page and its subscriber emails can show in six languages.
## Change the appearance
Owners, managers and admins can change the appearance.
1. In the dashboard, open the status page and go to the **Appearance** tab.
2. Change the settings in **Brand**, **Theme**, **Colours** and **Font**.
3. Check the preview. Use **Preview in** to see light and dark mode.
4. Select **Save appearance**.
The preview shows the top of the real public page, with your components and uptime.
## Brand
| Setting | Formats | Size | Notes |
|---|---|---|---|
| **Logo** | SVG, PNG, JPG or WebP | 2 MB at most | Shows in the header and in subscriber emails. |
| **Logo for dark mode** | SVG, PNG, JPG or WebP | 2 MB at most | Optional. Without one, dark mode shows the logo. |
| **Favicon** | SVG, ICO, PNG, JPG or WebP | 512 KB at most | The browser tab icon. |
| **Brand colour** | Hex colour, for example `#0f766e` | | Fills the logo mark and the **Subscribe** button, and tints links. |
Without a brand colour, the page uses Spectate yellow (`#ffea00`). Email clients do not show SVG images, so subscriber emails show the page name if the logo is an SVG.
The tab icon also shows the status of the page. See [share image and status favicon](/status-pages/introduction#share-image-and-status-favicon).
## Colour presets
A preset sets all colours for light and dark mode. Pick the preset that is closest to your brand, then change single colours if necessary.
| Preset | Value | Colours |
|---|---|---|
| Spectate | `spectate` | Neutral greys. This is the default. |
| Paper | `paper` | Warm cream and sepia ink. |
| Graphite | `graphite` | Soft charcoal, strong lines. |
| Ocean | `ocean` | Clear blues, navy in dark mode. |
| Forest | `forest` | Sage greens, deep pine in dark mode. |
| Lavender | `lavender` | Lilac, aubergine in dark mode. |
| Ember | `ember` | Peach and terracotta, warm in dark mode. |
| High contrast | `contrast` | Pure black and white, bold lines. |
## Light and dark mode
**Visitors see first** sets the mode of the page when a visitor opens it:
| Option | Value | Visitors see |
|---|---|---|
| **Light** | `light` | Light mode. |
| **Dark** | `dark` | Dark mode. |
| **Device setting** | `system` | The mode of their operating system. |
Visitors can switch the mode with the button in the header of the page.
## Custom colours
Select **Customise** in **Colours** to change single colours of the preset. Use **Light mode** and **Dark mode** to change each mode separately. Colours that you do not change come from the preset.
| Colour | Value | Used for |
|---|---|---|
| **Background** | `background` | Behind everything. |
| **Cards** | `surface` | Panels, dialogs and menus. |
| **Text** | `foreground` | Headings and body text. |
| **Secondary text** | `muted` | Descriptions, labels and times. |
| **Lines** | `border` | Borders and dividers. |
| **Operational** | `success` | Healthy components and uptime days. |
| **Degraded** | `warning` | Degraded performance. |
| **Partial outage** | `partial` | Partial outages. |
| **Full outage** | `danger` | Full outages and open incidents. |
| **Maintenance** | `info` | Planned work. |
Spectate calculates the other colours from these, for example hover states, faint text and empty uptime days.
## Readable text
Spectate keeps the page readable for every combination of colours:
- Spectate calculates faint text and text in status colours from your colours. It adjusts these text colours until they have a contrast of at least 4.5:1.
- Spectate does not change the colours that you pick yourself. Instead, the editor warns when **Text**, **Text on cards** or **Secondary text** has a contrast below 4.5:1 against its background.
- The editor warns when a status colour has a contrast below 3:1 against the background. Status dots and bars need 3:1 to be visible.
The warnings show the measured ratio, for example "Text is hard to read (3.2:1, aim for 4.5)". You can save with a warning.
## Fonts
The font applies to all text on the page. Numbers and times always use a monospaced font.
| Font | Value |
|---|---|
| Geist (default) | `geist` |
| Inter | `inter` |
| IBM Plex Sans | `ibm-plex-sans` |
| DM Sans | `dm-sans` |
| Manrope | `manrope` |
| Space Grotesk | `space-grotesk` |
| Source Serif | `source-serif` |
| System | `system`: the interface font of each visitor's device. |
Spectate serves the fonts itself. Visitors do not load fonts from a third party.
## Languages
A status page and its subscriber emails can show in English (`en`), Dutch (`nl`), German (`de`), French (`fr`), Spanish (`es`) and Italian (`it`).
1. Go to **Settings → Language** on the status page.
2. Select the **Page language**. The default is English.
3. Select or clear **Match the visitor's browser language**. It is on by default.
4. Select **Save language**.
Spectate translates its own text: headings, labels, buttons, dates, durations and numbers. Your page name, component names, incident titles, updates and maintenance text show as you wrote them.
### Which language a visitor sees
- **Match the visitor's browser language is off.** Every visitor sees the page language.
- **Match the visitor's browser language is on.** A visitor whose browser prefers a supported language sees that language. Other visitors see the page language. A language switcher in the footer lets visitors pick another language. Spectate remembers the choice for one year.
The URL of the page does not change with the language. The RSS and Atom feeds and the share image always use the page language. Subscriber emails use the language that the subscriber saw when they subscribed. See [subscribers](/status-pages/subscribers#email-languages).
## Related
- [Status page settings in the API reference](/api-reference/status-pages)
- [Custom domains](/status-pages/custom-domains)
---
## Document: Access and visibility
Make a status page public or private, share it with an access link or a password, rotate the access link, and control search engine indexing.
URL: /status-pages/access
# Access and visibility
A status page is public or private. Anyone can open a public page. A private page opens only for people with its access link, or with its password if you turn the password on. Use a private page for status that only your customers, a partner or your own staff should see.
## Visibility
| Visibility | Value | Who can open the page |
|---|---|---|
| **Public** | `public` | Anyone with the URL. |
| **Private** | `private` | People with the access link, or the password if the page has one. |
Private pages need the Team or Business plan, or the trial. If a team moves to a plan without private pages, its private pages stay private. See the [pricing page](https://spectate.net/pricing).
## Make a page private
Owners, managers and admins can change the visibility.
1. In the dashboard, open the status page and go to **Settings → General**.
2. Under **Visibility**, select **Private**.
3. Select **Save general**.
4. Copy the **Access link** and share it with the people who need access.
You can also select **Private** when you create the page.
## The access link
The access link is the page URL with a key, for example `https://acme.spectate.page/?key=AbC123...`. Anyone with the link can open the page.
When a visitor opens the link, Spectate signs the visitor in to the page. Then it removes the key from the address bar, so the key does not stay in the browser history. The visitor stays signed in for 30 days. A **Sign out** link in the footer ends the visit.
The RSS and Atom feeds and the [JSON API](/status-pages/json-api) of a private page also accept the key: add `?key=` to their URL. Feed readers and scripts do not keep a sign-in, so they need the key on each request.
## Add a password
A private page can also accept a password. Visitors without the link then see a password prompt.
1. Go to **Settings → General** on a private page.
2. Select **Also allow a password**.
3. Type a **Password** of at least 8 characters.
4. Select **Save general**.
To keep the current password when you save, leave **Password** empty. A visitor who enters the correct password stays signed in for 30 days. Spectate accepts 5 password attempts per visitor IP address per minute.
All paid plans include password protection. Public pages cannot have a password.
## What visitors without access see
| Page | Visitors without access see |
|---|---|
| Private, no password | A "This page isn't available" page, as for a page that does not exist. |
| Private, with password | A password prompt with the page name, logo and colours. |
The share image of a private page shows "Private status page" without status details. The [Intercom Messenger app](/status-pages/intercom) shows the status of a private page, without incident details.
## Rotate the access link
Create a new access link if the link reached the wrong people.
1. Go to **Settings → General** on the private page.
2. Next to the **Access link**, select **New link**.
3. Select **Create new link**.
:::caution
The old link stops working at once. Every visitor is signed out, also visitors who entered the password. Share the new link with everyone who must keep access.
:::
Changing the password also signs out every visitor.
## Search engines
Search engines can index public status pages. There is no setting to stop this for a public page.
Search engines cannot index a private page. They do not have the access link, so they get the "This page isn't available" page or the password prompt. Both tell search engines not to index the page.
## Other effects of a private page
- [Subscribers](/status-pages/subscribers) of a private page get emails as usual. To subscribe, a visitor must first open the page.
- A [custom domain](/status-pages/custom-domains) works for private pages, with HTTPS.
- Shared caches and CDNs never store the content of a private page.
Links with `?secret=` from the previous version of Spectate continue to work. They open the page with its password.
## Related
- [Custom domains](/status-pages/custom-domains)
- [Status pages in the API reference](/api-reference/status-pages)
---
## Document: Updates and roles
Post incident updates, move an incident through its statuses, assign a commander and a communications lead, and publish to status pages.
URL: /incidents/updates-and-roles
# Updates and roles
During an incident, your team posts **updates** to say what is known and what happens next. Each update can move the incident to its next status. **Roles** say who leads the response and who talks to customers. When customers need to know, publish an update to a status page.
## Post an update
1. Open the incident.
2. Under **Status for the next update**, select a stage if the status changes.
3. In the **Post update** panel, write the update in Markdown.
4. Select **Post update**, or **Post & mark identified** (or the stage you selected).
Updates are internal. Your team sees them on the incident timeline, and in the Slack incident channel. Customers do not see them. To tell customers, [publish to a status page](#publish-to-a-status-page).
With the [public API](/api-reference/incidents), send `POST /v1/incidents/{incident}/updates` with a `body` and an optional `status`. In Slack, use `/spectate update`.
An update does not change the title, the summary or the severity. To change them, select **Edit** on the incident. See [edit an incident](/incidents/introduction#edit-an-incident).
## Statuses
An incident moves through these statuses:
1. `investigating`: declared, the cause is not known yet.
2. `identified`: the cause is known and someone works on it.
3. `monitoring`: a fix is out, and the team watches whether it holds.
4. `resolved`: over.
You can skip a status. Acknowledging an incident moves it to `identified`. See [incidents](/incidents/introduction) for acknowledging and resolving.
## Roles
| Role | `role` in the API | Responsibility |
|---|---|---|
| Commander | `commander` | Leads the response and makes the calls. |
| Communications lead | `communications_lead` | Keeps customers and the company informed, for example through the status page. |
Each role has one person at a time. The person must be a member of the team.
### Assign a role
1. Open the incident.
2. In the **Roles** panel, select **Assign** next to the role, or **Change** if someone has it.
3. Under **Member**, select a team member.
4. Select **Assign role**.
The new person replaces whoever had the role. To clear a role, select **Remove**. In Slack, use `/spectate roles` or the **Roles** button in the incident channel.
## Timeline
The **Timeline** panel shows everything that happened, newest first:
- The declaration, and whether a person or an escalation path declared it.
- Updates, with their author and status.
- Acknowledgement and resolution.
- Status and severity changes, and edits to the title or summary.
- Role assignments.
Select **Updates** to see only the updates, or **All** to see everything. Spectate records who did each thing: a member, or the name of the API token. The public API returns the same entries at `GET /v1/incidents/{incident}/timeline`.
## Publish to a status page
Publish an update to tell customers about the incident on a [status page](/status-pages/incidents). The first update creates the public incident on that page. Later updates go to the same public incident.
1. Open the incident.
2. In the **Status pages** panel, select **Publish**, or **Update** next to a status page.
3. Select the **Status page**.
4. Select the **Public status**.
5. Select the **Impact** on each affected component.
6. Write the **Subscriber-facing update**.
7. Optional: change **Happened at**, if the update describes an earlier moment.
8. Keep **Notify subscribers by email** selected to email subscribers, or clear it.
9. Select **Publish update**.
:::caution
The status page update is public. With **Notify subscribers by email** selected, Spectate also emails the page's [subscribers](/status-pages/subscribers).
:::
Owners, managers and admins can publish to a status page. Members can post internal updates, but cannot publish. In Slack, use `/spectate status-page`. With the API, send `POST /v1/incidents/{incident}/status-page-updates`.
## Slack incident channel
If you [connected Slack](/alerting/slack), Spectate posts each update, status change, severity change, role change and status page update into the incident's Slack channel. It also posts edits of the title or summary. Things that people do in the channel show on the incident in the dashboard, with the right person. To add a Slack message to the timeline, react to it with the pushpin emoji. See [incident channels](/alerting/slack#incident-channels).
## Related
- [Postmortems](/incidents/postmortems): write down what happened after the incident.
- [Status page incidents](/status-pages/incidents): how public incidents look to customers.
---
## Document: Postmortems
Write, save and mark as final a blameless postmortem for a Spectate incident, and turn it into a public write-up for your status page.
URL: /incidents/postmortems
# Postmortems
A **postmortem** is your team's write-up of an incident: what happened, why, and what changes as a result. Each incident has one postmortem, in Markdown. The postmortem is internal, so only your team sees it. To tell customers, publish a separate write-up on the status page incident.
## Write a postmortem
1. Open the incident.
2. In the **Postmortem** panel, select **Start postmortem**. For a resolved incident, you can also select **Write postmortem** at the top.
3. Optional: in an empty postmortem, select **Insert template**.
4. Write the postmortem in Markdown.
5. Select **Save postmortem**.
You can start the postmortem while the incident is still open, and add to it as you go. After you resolve the incident, the **Postmortem** panel asks you to write it while the facts are fresh.
The headings of the postmortem make the **Outline** next to the editor. Select a heading in the outline to go to it.
## The template
**Insert template** fills in the facts that Spectate knows:
| Section | Content |
|---|---|
| Summary | Space for two or three sentences about what happened. |
| Impact | The severity, start, end and duration of the incident, and a line for the customers affected. |
| Timeline | The declaration and every incident update, with its time and status. |
| Root cause | Empty. |
| Contributing factors | Empty list. |
| Resolution | Empty. |
| Action items | An empty checklist. |
## Mark the postmortem as final
Select **Published** in the **Publishing** panel, then select **Save postmortem**. **Published** marks the postmortem as final for your team. It does not make the postmortem public. Clear **Published** to make it a draft again.
## Tell customers
Spectate never shows the internal postmortem on a status page. To tell customers what happened, write a public write-up on the status page incident:
1. Open the status page incident that you published from the incident.
2. In the **Public write-up** panel, select **Start from postmortem**.
3. Edit the text for customers. Remove internal details.
4. Select **Published on the status page**.
5. Optional: select **Email subscribers the write-up**.
6. Select **Publish write-up**.
**Start from postmortem** copies the postmortem text. Later changes to the postmortem do not change the write-up. Spectate emails subscribers about a write-up only once, when you first publish it. See [status page incidents](/status-pages/incidents).
## Who can write postmortems
Owners, managers, admins and members can write and save postmortems. When you delete an incident, Spectate deletes its postmortem too.
## API and AI assistants
| Action | Public API | MCP tool |
|---|---|---|
| Read the postmortem | `GET /v1/incidents/{incident}/postmortem` | `get_incident_postmortem` |
| Save the postmortem | `PUT /v1/incidents/{incident}/postmortem` | `save_incident_postmortem` |
`PUT` takes `content`, the whole postmortem in Markdown, and an optional `published` boolean. The new content replaces the old content. If you leave out `published`, it keeps its value. See the [incidents API](/api-reference/incidents) and the [MCP server](/developers/mcp).
Through the MCP server, an AI assistant can draft a postmortem from the incident timeline. For example, ask: "Draft a postmortem for yesterday's incident from its timeline and save it."
---
## Document: Incidents
What a Spectate incident is, how it differs from an alert, and how to declare, edit, acknowledge, resolve and delete incidents.
URL: /incidents/introduction
# Incidents
An **incident** is a problem that your team works on together. It has a status, a severity, updates, roles, a timeline and a postmortem. Alerts tell you that something is wrong. An incident is where your team handles it, and where you tell your customers about it on a [status page](/status-pages/incidents).
## Incidents and alerts
| | [Alert](/alerting/alerts) | Incident |
|---|---|---|
| Starts | Automatically, when a monitor, host, domain or alert source sees a problem | When a person, an escalation path, the API or an AI assistant declares it |
| Ends | When the source recovers, or someone resolves it | When someone resolves it |
| Statuses | `firing`, `resolved` | `investigating`, `identified`, `monitoring`, `resolved` |
| Has | An escalation path and notifications | Updates, roles, a timeline, a postmortem, a Slack channel |
An incident can come from an alert, but it does not have to. Resolving an incident does not resolve its alert. The alert resolves when its source recovers.
## Declare an incident
1. In the dashboard, select **Incidents**.
2. Select **Declare incident**.
3. Enter a **Title**: the symptom, for example `Checkout API returning 502s in eu-west`.
4. Select a severity. The default is `medium`.
5. Optional: enter a **Summary** with the impact and links.
6. Select **Declare incident**.
The incident starts in the `investigating` status. You land on the incident page, where you can assign roles and post the first update.
You can also declare an incident in these places:
- In Slack, with `/spectate declare`, the **Declare incident** shortcut, or the **Declare incident** button on an alert message. See [Slack](/alerting/slack).
- In an [escalation path](/alerting/escalation-paths), with a **Create incident** step. The incident gets the alert's title and severity. An alert opens one incident at most.
- With the [public API](/api-reference/incidents): `POST /v1/incidents` with `title`, `severity` and an optional `summary`.
- With an AI assistant through the [MCP server](/developers/mcp).
If Slack is connected, each new incident can get its own Slack channel. See [incident channels](/alerting/slack#incident-channels).
## The reference
Each incident gets a number in your team: the first is `INC-1`, the next `INC-2`, and so on. Spectate shows the reference in the dashboard, in Slack and in incident channel names.
## Statuses
| Status | Meaning |
|---|---|
| `investigating` | Declared. The cause is not known yet. |
| `identified` | The cause is known and someone works on it. |
| `monitoring` | A fix is out. The team watches whether it holds. |
| `resolved` | The incident is over. |
Move the incident through the statuses with updates. See [updates and roles](/incidents/updates-and-roles).
## Severity
An incident has the same four severities as an alert:
| Severity | Use |
|---|---|
| `critical` | Customers are affected right now. |
| `high` | Serious, needs attention soon. |
| `medium` | Should be looked at. |
| `low` | Informational. |
## Edit an incident
You can change the title, the summary and the severity of an incident at any time, also after you resolve it.
1. Open the incident.
2. Select **Edit**.
3. Change the **Title**, the **Severity** or the **Summary**. The summary is Markdown.
4. Select **Save changes**.
Spectate records the change on the incident timeline with your name. If the incident has a Slack channel, Spectate posts the change there. A severity change shows the old and the new severity.
You can also edit an incident with the [public API](/api-reference/incidents) (`PATCH /v1/incidents/{incident}`) or with an AI assistant through the MCP server. To change the status, post an update. See [updates and roles](/incidents/updates-and-roles).
## Acknowledge an incident
Acknowledge an incident to show that someone works on it.
1. Open the incident.
2. Select **Acknowledge**.
The incident moves to `identified`. If an alert opened the incident, Spectate also acknowledges that alert, which stops its escalation. You can also acknowledge in Slack, with `/spectate ack` or the **Acknowledge** button in the incident channel.
## Resolve an incident
1. Open the incident.
2. Select **Resolve**.
The incident moves to `resolved`. In Slack, with the API and with the MCP server, you can add a closing message, which Spectate posts as the last update. After you resolve the incident, write the [postmortem](/incidents/postmortems).
## Delete an incident
1. Open the incident.
2. Select **Delete**.
3. Type the reference, for example `INC-42`, to confirm.
4. Select **Delete incident**.
Spectate deletes the incident with its updates, roles and postmortem. This cannot be undone. The alert that opened the incident does not change. Status page incidents that you published from it stay on their status pages. The Slack channel of the incident stays in Slack.
## Notifications
Spectate does not send emails about incidents. It tells people in these places:
- Slack: the announcements channel and the incident channel, if you [connected Slack](/alerting/slack).
- Status pages: only when you publish an update. See [updates and roles](/incidents/updates-and-roles#publish-to-a-status-page).
## Find incidents
The **Incidents** page has the tabs **Active**, **Investigating**, **Identified**, **Monitoring**, **Resolved** and **All**. You can search by title and filter by severity.
## Who can do what
| Action | Owner | Manager | Admin | Member | Billing |
|---|---|---|---|---|---|
| See incidents | Yes | Yes | Yes | Yes | No |
| Declare, edit, update, acknowledge and resolve | Yes | Yes | Yes | Yes | No |
| Publish to a status page | Yes | Yes | Yes | No | No |
| Delete | Yes | Yes | Yes | No | No |
## Related
Post updates, assign a commander and publish to status pages.
Write down what happened and what changes.
---
## Document: Host metrics
The charts on a host's Overview and Metrics tabs, every metric the Spectate agent reports with its unit, the collectors, and how long Spectate keeps metrics.
URL: /hosts/metrics
# Host metrics
The Spectate agent reports metrics for CPU, memory, disk, network and the system. The host page in the dashboard shows them as charts, and [metric conditions](/hosts/metric-conditions) use them to fire alerts. The agent collects a sample every 15 seconds and sends the samples once a minute.
## The host page
Open a host from the **Hosts** page. The host page has three tabs: **Overview**, **Metrics** and **Settings & alerts**.
The header shows the platform, the kernel, the virtualization, the agent version and **Last seen**. If a newer agent release exists, the header shows it next to the agent version. If the server's clock differs from Spectate's clock by more than 30 seconds, the header also shows the difference under **Clock**.
### Overview tab
The **Overview** tab shows, from top to bottom:
1. The [health checks](/hosts/health-checks) of the host (agent 2.1 or later).
2. **System uptime**, the number of CPU cores, and the total memory and swap.
3. Charts for **CPU**, **Memory**, **Load**, **Network** and **Disk**. Select a period of **6h**, **24h**, **7d** or **30d**. Select a network interface for the network chart and a mountpoint for the disk chart.
4. A table of the disks, with the space used per mountpoint.
5. **CPU inventory**: the model and cores of each CPU.
### Metrics tab
The **Metrics** tab shows all charts of the host, in five sections. Select a period of **6h**, **24h** (default), **7d** or **30d**.
| Section | Charts |
|---|---|
| **CPU** | CPU use, load, and **CPU pressure** |
| **Memory** | RAM and swap, **Memory pressure**, and **Out of memory kills** |
| **Disk** | Space per mountpoint, **Throughput**, **Operations**, **Busy**, **Latency** and **I/O pressure** |
| **Network** | Traffic, and **TCP connections** (established, time wait and orphaned) |
| **System** | **File handles**: the share of the system-wide maximum in use |
The disk I/O charts show all disks together. If the host has more than one disk, select one disk in the list next to the **Disk** heading.
Charts of agent 2.1 metrics show only when the host reports them. A host with an older agent, or a collector that is off, has fewer charts. On macOS, the agent does not report pressure, out of memory kills or TCP connections in the time wait state.
## Collectors
A collector is the part of the agent that reads one group of metrics. The agent always runs the base collectors: CPU, memory, load, disk, network, uptime and the agent's own metrics.
With agent 2.1 or later, you can turn off these collectors per host:
| Collector | Label in the dashboard | Systems |
|---|---|---|
| `diskio` | **Disk I/O** | Linux, macOS |
| `pressure` | **Pressure & out of memory** | Linux |
| `services` | **Services** | Linux with systemd |
| `updates` | **Updates & reboot** | Linux with apt, dnf or yum |
| `sockets` | **Connections & file handles** | Linux, macOS |
| `clock` | **Clock** | Linux |
To turn a collector off or on:
1. Open the host and go to **Settings & alerts**.
2. Under **Collection**, clear or select the collector.
3. Select **Save changes**.
The change applies at the agent's next report. A collector that is off also hides its [health checks](/hosts/health-checks) and resolves their alerts.
A collector that has nothing to report on a server sends nothing, not zeros. For example, Linux before kernel 4.20 has no pressure data.
## Metrics and units
These are the metrics that you can see in charts and use in metric conditions. The key is the name in the [public API](/api-reference/metric-conditions) and in alert data.
### Summary metrics
Spectate calculates these from the agent's raw values:
| Key | Label | Unit |
|---|---|---|
| `cpu_usage` | CPU usage | % (100 minus idle) |
| `memory_usage` | Memory usage | % (100 minus available) |
| `disk_usage` | Disk usage | % per mountpoint |
| `load_average` | Load average | The 1-minute load average |
| `network_in` | Network received | KB per 60 seconds, per interface |
| `network_out` | Network sent | KB per 60 seconds, per interface |
### CPU
| Key | Label | Unit |
|---|---|---|
| `system.cpu.user` | CPU user | % |
| `system.cpu.system` | CPU system | % |
| `system.cpu.iowait` | CPU I/O wait | % |
| `system.cpu.stolen` | CPU steal | % |
| `system.cpu.idle` | CPU idle | % |
| `system.cpu.guest` | CPU guest | % |
| `system.cpu.interrupt` | CPU interrupt | % |
| `system.pressure.cpu.some` | CPU pressure | % of time that tasks waited (agent 2.1) |
### Memory and swap
| Key | Label | Unit |
|---|---|---|
| `system.memory.total` | Memory total | MB |
| `system.memory.used` | Memory used | MB |
| `system.memory.free` | Memory free | MB |
| `system.memory.available` | Memory available | MB |
| `system.memory.available_percent` | Memory available | % |
| `system.swap.total` | Swap total | MB |
| `system.swap.used` | Swap used | MB |
| `system.swap.free` | Swap free | MB |
| `system.swap.free_percent` | Swap free | % |
| `system.swap.in` | Swap in | MB |
| `system.swap.out` | Swap out | MB |
| `system.pressure.memory.some` | Memory pressure | % of time that tasks waited (agent 2.1) |
### Disk
| Key | Label | Unit |
|---|---|---|
| `system.disk_usage.total` | Disk total | KB per mountpoint |
| `system.disk_usage.used` | Disk used | KB per mountpoint |
| `system.disk_usage.free` | Disk free | KB per mountpoint |
| `system.disk_usage.inodes_total` | Disk inodes total | Inodes |
| `system.disk_usage.inodes_used` | Disk inodes used | Inodes |
| `system.disk_usage.inodes_free` | Disk inodes free | Inodes |
| `system.disk_usage.inodes_used_percent` | Disk inodes used | % |
| `system.io.busy_percent` | Disk busy | % of time, per disk (agent 2.1) |
| `system.io.await_ms` | Disk latency | Milliseconds per operation, per disk (agent 2.1) |
| `system.pressure.io.some` | I/O pressure | % of time that tasks waited (agent 2.1) |
The disk I/O charts also show bytes read and written per second and operations per second.
### Network
| Key | Label | Unit |
|---|---|---|
| `system.net.packets_recv` | Packets received | Packets per 60 seconds |
| `system.net.packets_sent` | Packets sent | Packets per 60 seconds |
| `system.net.err_in` | Network receive errors | Per 60 seconds |
| `system.net.err_out` | Network send errors | Per 60 seconds |
| `system.net.drop_in` | Network receive drops | Per 60 seconds |
| `system.net.drop_out` | Network send drops | Per 60 seconds |
| `system.net.fifo_in` | Network receive FIFO | Per 60 seconds |
| `system.net.fifo_out` | Network send FIFO | Per 60 seconds |
| `system.net.tcp.established` | TCP connections | Connections (agent 2.1) |
| `system.net.tcp.time_wait` | TCP connections in TIME_WAIT | Connections (agent 2.1) |
Network values are amounts per 60 seconds, also when the agent collects every 15 seconds. The v1 agent used the same unit, so thresholds keep their meaning after you move a host to v2.
### System
| Key | Label | Unit |
|---|---|---|
| `system.load.1` | Load 1 minute | Load average |
| `system.load.5` | Load 5 minutes | Load average |
| `system.load.15` | Load 15 minutes | Load average |
| `system.uptime` | System uptime | Seconds |
| `system.files.used_percent` | File handles used | % of the system-wide maximum (agent 2.1) |
The agent also reports metrics that only the [health checks](/hosts/health-checks) use: failed services, out of memory kills, pending updates, reboot required and clock sync.
## Disk and network filters
The agent skips some disks and network interfaces by default:
- **File systems**: network and virtual file systems, such as `nfs`, `nfs4`, `cifs`, `smbfs`, `squashfs`, `vfat`, `fuse.sshfs`, `ceph` and `9p`.
- **Network interfaces**: loopback (`lo`), bridges and virtual interfaces, such as `br*`, `docker*`, `veth*`, `virbr*`, `cni*`, `flannel*` and `cali*`.
- **Disk I/O**: virtual and stacked devices, such as `loop*`, `ram*`, `zram*`, `dm-*` and `md*`. Their I/O is already counted on the disks below them.
## How long Spectate keeps metrics
| Data | Kept for |
|---|---|
| Samples, one every 15 seconds | 30 days |
| Hourly minimum, maximum, average and last value per metric | 400 days (about 13 months) |
When you delete a team, Spectate deletes its metrics. See [data and privacy](/account/data-and-privacy).
---
## Document: Metric conditions
Fire an alert when a host metric crosses a threshold, such as disk usage above 90% for 10 minutes, or when a host stops reporting.
URL: /hosts/metric-conditions
# Metric conditions
A metric condition is an alert rule for host metrics, for example "disk usage above 90 for 10 minutes". You add it to one host or to a project. When the condition holds for its duration, Spectate fires an alert with the condition's severity. A separate setting fires an alert when a host stops reporting.
## How a condition works
A metric condition has these parts:
| Part | Values |
|---|---|
| **Metric** | A host metric, for example `disk_usage` or `system.load.5`. See [metrics and units](/hosts/metrics#metrics-and-units). |
| **Condition** | `greater_than`, `less_than` or `equals` |
| **Threshold** | A number, in the unit of the metric. For example, `90` for 90% disk usage. |
| **For** | How long the condition must hold before it fires: **Immediately**, **1 minute**, **2 minutes**, **5 minutes**, **10 minutes**, **15 minutes**, **30 minutes** or **1 hour**. The default is **Immediately**. |
| **Severity** | **Critical**, **High**, **Medium** or **Low**. The default is **Medium**. |
Spectate checks the conditions each time the agent sends data, once a minute:
- If the metric has more than one series, one series is enough. For example, one full mountpoint fires a `disk_usage` condition. The alert title names the series, such as `mountpoint=/data`.
- A breach that is shorter than **For** does not fire. If the host sends no data for 5 minutes, the count starts again.
- `equals` matches values within 0.001 of the threshold.
- Spectate does not check data that the agent sends late from its disk buffer, if the newest sample is more than 5 minutes old. This prevents alerts about old data.
The alert title has the metric, the threshold and the host, for example `Disk usage above 90 on web-01 (mountpoint=/)`. When the value is back on the right side of the threshold, Spectate resolves the alert. Spectate fires one alert per condition and host at a time.
The alert goes to the host's [escalation paths](/alerting/escalation-paths). Set them on the host under **Settings & alerts → Alerting**.
## Add a condition to a host
Owners, managers and admins can add conditions.
1. Open the host and go to **Settings & alerts**.
2. Under **Metric conditions**, select **Add condition**.
3. Select the **Metric**.
4. Select the **Condition**.
5. Type the **Threshold**.
6. Under **For**, select how long the condition must hold.
7. Select the **Severity**.
8. Select **Create condition**.
You cannot edit a condition. To change it, delete it and add a new one. In the row of the condition, select the delete icon (**Delete condition**).
## Add a condition to a project
A condition on a [project](/account/projects) applies to every host in that project, also to hosts that join later.
1. Go to **Projects** and open the project.
2. Under **Metric conditions**, select **Add condition**.
3. Fill in the fields as for a host, then select **Create condition**.
The **Metric conditions** list on a host shows only the conditions of that host. The host also uses the conditions of its project. If a host has a condition and its project has the same condition, Spectate evaluates both.
## Alert when a host stops reporting
The "Host stops reporting" alert fires when Spectate gets no data from the agent for a set time. For example, the server is down, the agent stopped, or the network is down.
| Setting | Value |
|---|---|
| Default | On, after 5 minutes |
| Range | 2 to 1,440 minutes |
| Severity | High. You cannot change it. |
To change it:
1. Open the host and go to **Settings & alerts**.
2. Under **Alerting**, find **Host stops reporting**.
3. Turn the alert on or off.
4. In **Silent for**, type the number of minutes.
5. Select **Save changes**.
Spectate checks every minute. The alert title is `No data received from` followed by the host's label. The alert resolves as soon as the agent reports again.
The alert does not fire in these cases:
- The agent never reported. The host is still `pending`.
- Spectate paused the host, for example because the team is over its plan limit.
- An alert of this type is already open for the host.
If you turn the alert off or make the time longer, Spectate resolves a firing alert.
## Use the API
The [public API](/api-reference/metric-conditions) can list, create, get and delete metric conditions. It needs a [team API token](/developers/api-tokens) with `hosts:read` to read and `hosts:write` to create. Deleting needs `hosts:delete`.
```bash
curl https://api.spectate.net/v1/metric-conditions \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"metric": "disk_usage",
"condition": "greater_than",
"threshold": 90,
"severity": "high",
"duration_minutes": 10,
"project_ids": ["YOUR_PROJECT_ID"]
}'
```
`duration_minutes` is 0 to 60. Use `host_ids`, `project_ids` or both. To change the "Host stops reporting" time, update the host with `no_data_alert_minutes`. Use `null` to turn the alert off.
---
## Document: Host monitoring
How the Spectate agent monitors your servers, which data it collects, which systems it supports, and how hosts count towards your plan.
URL: /hosts/introduction
# Host monitoring
Host monitoring shows what happens inside your servers: CPU, memory, disk, network, failed services and pending updates. You install the Spectate agent on each server. The agent sends metrics to Spectate, and Spectate alerts your team when a server stops reporting or a metric crosses a threshold.
## How it works
1. You [install the agent](/hosts/install-the-agent) with an install token from the dashboard.
2. The agent registers the server as a **host** in your team. The host gets the server's hostname as its label and joins the team's default [project](/account/projects).
3. The agent collects metrics every 15 seconds and sends them to Spectate once a minute, compressed.
4. Spectate stores the metrics, updates the host's [health checks](/hosts/health-checks) and evaluates its [metric conditions](/hosts/metric-conditions).
5. If a check or a condition fails, or the host stops reporting, Spectate fires an [alert](/alerting/alerts). The alert goes to the host's [escalation paths](/alerting/escalation-paths).
If the network is down, the agent keeps the batches on disk, up to 50 MB or 24 hours. It sends them when the connection comes back. Spectate removes duplicate batches.
The agent receives its settings from Spectate with every response: the collection interval, the collectors and the disk and network filters. You change them in the dashboard, not in a file on the server.
## What Spectate collects
The Spectate agent collects these data on every host:
| Area | Data |
|---|---|
| CPU | Usage, split into user, system, I/O wait, steal, idle, guest and interrupt time. |
| Memory | RAM total, used and available, and swap use. |
| Load | Load average over 1, 5 and 15 minutes. |
| Disk | Space and inodes per mountpoint. |
| Network | Traffic, packets, errors and drops per network interface. |
| System | Uptime, hostname, operating system, kernel, architecture, virtualization and CPU model. |
Agent 2.1 and later also collect these data. You can turn off each collector per host:
| Collector | Data |
|---|---|
| Disk I/O | Throughput, operations, busy time and latency per disk. |
| Pressure & out of memory | Time that tasks wait for CPU, memory and I/O, and processes that the kernel killed for lack of memory. Linux only. |
| Services | Failed systemd services, checked every minute. Linux only. |
| Updates & reboot | Pending updates, security updates, and whether the server needs a reboot. Linux only. |
| Connections & file handles | TCP connections by state, and open file handles. |
| Clock | Whether the clock is synchronised with NTP. Linux only. |
[Metrics](/hosts/metrics) lists every metric and its unit.
## Supported systems
| System | Support |
|---|---|
| Linux with systemd, on amd64 (x86_64) or arm64 (aarch64) | Supported. The agent runs as a systemd service. The dashboard lists Ubuntu, Debian, CentOS / RHEL, Rocky Linux, AlmaLinux and Fedora. |
| macOS on Apple silicon or Intel | Best effort. The agent runs as a launchd agent of the user who installs it. |
The installer stops with an error on other systems and architectures, and on Linux without systemd.
## Agent versions
There are two versions of the Spectate host agent:
| | Agent v2 (`spectate-agent`) | Agent v1 (`spectated`) |
|---|---|---|
| Status | Current version. The dashboard installs it. | Legacy. It is no longer supported, but Spectate still accepts its data. |
| Resolution | 15 seconds | 60 seconds |
| When the network is down | Keeps up to 50 MB or 24 hours of data on disk | Keeps data in memory only |
| Settings | From Spectate, changed in the dashboard | Local YAML file |
| Health checks | From version 2.1 | Not available |
Spectate stores the data of both versions in the same way. If you still run the v1 agent, [move the host to v2](/hosts/install-the-agent#move-a-host-from-the-v1-agent). The host keeps its history.
## Host states
The hosts list shows one of these states for each host:
| State | Label in the dashboard | Meaning |
|---|---|---|
| `up` | **Online** | The agent reported in the last 15 minutes. |
| `stale` | **Stale** | The agent reported before, but not in the last 15 minutes. |
| `pending` | **Pending** | The agent never reported. |
The **Needs attention** filter shows the hosts with a health check in the warning or critical status.
A host can be stale without an alert. The "Host stops reporting" alert has its own time, 5 minutes by default. See [no-data alerts](/hosts/metric-conditions#alert-when-a-host-stops-reporting).
## Plan limits
Each host counts as one resource, the same as an uptime monitor. Your plan sets how many monitors and hosts your team can run together:
| Plan | Monitors and hosts |
|---|---|
| Trial | 80 |
| Starter, Team, Business | The number that you pay for |
If the team is at its limit, the agent cannot register a new host. Registration fails with the error `PLAN_LIMIT_REACHED`. Add monitors and hosts on the **Billing** page, or delete a host or monitor that you do not need. See [plans and billing](/account/plans-and-billing) for the minimum of each plan and what happens over a limit.
## Who can manage hosts
All roles except Billing can see hosts. Owners, managers and admins can add hosts, change their settings and add metric conditions. Owners, managers and admins can also delete hosts. Spectate permanently deletes the metrics and alerts of a deleted host after 7 days. See [remove the agent](/hosts/install-the-agent#remove-the-agent) and [teams and roles](/account/teams-and-roles).
## Related
Install, update and remove the Spectate agent on Linux and macOS.
The charts on the host page, every metric and how long Spectate keeps it.
Failed services, out of memory kills, updates, reboots and clock sync.
Alert when a metric crosses a threshold, or when a host stops reporting.
---
## Document: Install the agent
Install the Spectate host agent on Linux or macOS with an install token, then update, troubleshoot or remove it.
URL: /hosts/install-the-agent
# Install the agent
The Spectate agent (`spectate-agent`) sends the metrics of a server to Spectate. You install it with one command from the dashboard. The command contains an install token that registers the server as a host in your team.
Owners, managers and admins can add hosts. Your team must have room for one more monitor or host on its plan. See [plan limits](/hosts/introduction#plan-limits).
## Before you start
- A Linux server with systemd, on amd64 or arm64, or a Mac. See [supported systems](/hosts/introduction#supported-systems).
- Root access with `sudo`.
- `curl` on the server.
- Outbound HTTPS (port 443) to the hosts in [network requirements](#network-requirements).
## Install on Linux
1. In the dashboard, go to **Hosts**.
2. Select **Add host**.
3. Under **Choose platform**, select your Linux distribution.
4. Under **Run the installer**, copy the command. If there is no command, select **Generate install command**.
5. Run the command on the server.
6. Wait for the host to appear under **Wait for the first report**.
The dashboard checks for new hosts every 5 seconds. A new host appears as soon as the agent registers it.
The command looks like this:
```bash
curl -fsSL https://get.spectate.net/agent.sh | sudo sh -s -- --token YOUR_INSTALL_TOKEN
```
The installer does these steps:
1. It downloads the newest agent release from GitHub and checks it against the release's checksums.
2. It creates the system user `spectate-agent`. The agent runs as this user, not as root.
3. It writes `/etc/spectate-agent/agent.env`.
4. It registers the host. The host token goes to `/var/lib/spectate-agent/state.json`, which only the agent user can read.
5. It installs and starts the systemd service `spectate-agent.service`.
6. If the server has apt, dnf or yum, it adds an hourly timer that counts pending updates. The timer never installs updates.
To install on many servers, run the same command on each server. One install token registers any number of hosts until it expires.
## Install on macOS
The agent on macOS is best effort. It runs as a launchd agent of your user and starts when you log in.
1. In the dashboard, go to **Hosts**.
2. Select **Add host**.
3. Under **Choose platform**, select **macOS**.
4. Under **Processor**, select **Apple silicon** or **Intel**.
5. Copy the command under **Run the installer**.
6. Run the command in Terminal, as the user that the agent must run as.
The command downloads the agent binary and checks it against `checksums.txt` of the release. Then it installs the binary in `/usr/local/bin` and registers the host. Last, it loads the launchd agent. The log file is `~/Library/Logs/spectate-agent.log`.
## Install tokens
An install token lets the agent register a host in your team. Install tokens start with `hct_`.
- A token is valid for 7 days.
- One token can register any number of hosts until it expires or you revoke it.
- **Add host** uses an existing token if it is valid for at least one more hour. If not, select **Generate install command** to create a new token.
- The **Install tokens** panel on the **Hosts** page lists the active tokens. Select **Revoke** to stop a token.
Revoking an install token does not affect hosts that registered with it. Each host has its own host token.
You can also create install tokens with the [public API](/api-reference/host-install-tokens).
## Move a host from the v1 agent
If a server runs the legacy v1 agent (`spectated`), replace it with the v2 agent. The host keeps its identity and history. You do not need an install token.
Run this command on the Linux server:
```bash
curl -fsSL https://get.spectate.net/agent.sh | sudo sh -s -- --import-legacy
```
The installer reads the host token from `/etc/spectated/config.yaml`, installs the v2 agent and removes `spectated`. The dashboard also shows this command under **Add host** and on the **Integrations** page.
## Check the agent
Use these commands on the server:
| Command | What it shows |
|---|---|
| `sudo spectate-agent doctor` | Checks the registration, the API connection and token, the clock, the disk buffer, the service, the collectors and the package check. It exits with an error code if a check fails. |
| `spectate-agent status` | The state of the agent, including an available update or a deleted host. Add `--json` for JSON output. |
| `spectate-agent collect --once` | What each collector reports on this server. It sends nothing to Spectate. |
| `spectate-agent config show` | The settings that the agent received from Spectate. |
| `spectate-agent version` | The agent version. |
`doctor` does not send metrics. It does not mark the host as reporting, so it does not resolve a "Host stops reporting" alert.
## Update the agent
The host page shows when a newer agent release is available. The agent also writes a message to its log once a day.
```bash
sudo spectate-agent update --check # show the current and the newest version
sudo spectate-agent update # install the newest release and restart the service
sudo spectate-agent update --version 2.1.0 # install a specific release
```
`update` installs only stable `v2.x.y` releases. It checks the signature of the release before it replaces the binary. On macOS, `update` shows the `launchctl` commands to run instead of a restart.
To update automatically on Linux, add `--auto-update` to the install command. The installer then adds a daily timer that runs `spectate-agent update --if-newer`.
## Remove the agent
On Linux, run:
```bash
sudo spectate-agent uninstall
```
This removes the service and the update timer. The agent keeps its state in `/var/lib/spectate-agent`.
On macOS, run `spectate-agent uninstall` as your user, without `sudo`. Then remove the binary with `sudo rm /usr/local/bin/spectate-agent`.
Removing the agent does not delete the host in Spectate. To delete the host, open it and go to **Settings & alerts**. Under **Danger zone**, select **Delete host** and type the host's label to confirm.
When you delete a host, it no longer shows in the dashboard or the API. After 7 days, Spectate permanently deletes the host with its metrics and alerts. In the first 7 days, Spectate support can restore the host. Send an email to [help@spectate.net](mailto:help@spectate.net).
If you delete a host while its agent still runs, the agent stops at its next report. It logs `This host was removed from Spectate` and does not start again. To add the server again, run `sudo spectate-agent uninstall` and `sudo rm -rf /var/lib/spectate-agent`. Then run the install command again. The installer keeps an existing registration, so you must remove the old state first.
## Network requirements
The agent connects out over HTTPS on port 443. Spectate never connects to your server.
| Host | Used by | Why |
|---|---|---|
| `api.spectate.net` | The agent | Registration and metrics |
| `get.spectate.net` | The installer | The install script |
| `github.com`, `objects.githubusercontent.com`, `release-assets.githubusercontent.com` | The installer and `update` | Agent releases |
| `api.github.com` | `update` | The list of releases |
If the agent cannot reach `api.spectate.net`, it keeps the metrics on disk for up to 24 hours, at most 50 MB. It sends them when the connection comes back.
## Settings on the server
The agent reads a few local settings from `/etc/spectate-agent/agent.env`:
| Variable | Default |
|---|---|
| `SPECTATE_API_URL` | `https://api.spectate.net` |
| `SPECTATE_STATE_DIR` | `/var/lib/spectate-agent` |
| `SPECTATE_SPOOL_MAX_MB` | `50` |
| `SPECTATE_SPOOL_MAX_AGE` | `24h` |
| `SPECTATE_LOG_LEVEL` | `info` |
Spectate sets everything else, such as the intervals and the collectors. Change the collectors on the host page under **Settings & alerts → Collection**. See [metrics](/hosts/metrics#collectors).
## Installer options
| Option | What it does |
|---|---|
| `--token TOKEN` | The install token. You can also set `SPECTATE_INSTALL_TOKEN`. |
| `--import-legacy` | Moves a host from the v1 agent and keeps its token. |
| `--upgrade` | Replaces the binary and restarts the service. |
| `--auto-update` | Adds a daily update timer. Linux only. |
| `--version VERSION` | Installs a specific release, for example `2.1.0`. |
| `--api-url URL` | Uses another API address. |
---
## Document: Health checks
The seven host health checks of agent 2.1 (services, out of memory, reboot, updates, clock, file handles, pressure), their thresholds and their alerts.
URL: /hosts/health-checks
# Health checks
Health checks find problems on a server that a chart does not show well. Examples are a failed systemd service, a process killed for lack of memory, and a pending security update. Spectate runs the checks on every report from the Spectate agent and can fire an alert for each one. Health checks need agent 2.1 or later.
## Where you see health checks
- The **Overview** tab of a host shows the health panel. It lists the checks that need attention first. It then shows the passing checks in one line, for example "All 7 checks passing".
- The **Hosts** page has the filter **Needs attention**. It shows the hosts with at least one check in the `warning` or `critical` status.
Each check has one of these statuses:
| Status | Meaning |
|---|---|
| `ok` | No problem. |
| `warning` | A problem that needs attention soon. |
| `critical` | A problem that needs attention now. |
| `unknown` | The host does not report this data yet. |
If the agent is older than 2.1, the checks show `unknown` with the message "Needs agent 2.1.0 or later: sudo spectate-agent update". See [update the agent](/hosts/install-the-agent#update-the-agent).
## The checks
| Check | Label | Warning | Critical | Collector |
|---|---|---|---|---|
| `services` | **Services** | | A systemd service failed | Services |
| `oom` | **Out of memory** | The kernel killed a process for lack of memory in the last 24 hours | A kill in the last hour | Pressure & out of memory |
| `reboot` | **Reboot** | The server needs a reboot | | Updates & reboot |
| `updates` | **Updates** | Security updates are pending | | Updates & reboot |
| `clock` | **Clock** | The clock is not synchronised with NTP, or it is more than 30 seconds off | | Clock |
| `files` | **File handles** | More than 80% of the maximum open files are in use | More than 95% | Connections & file handles |
| `pressure` | **Pressure** | Tasks stalled on memory or I/O more than 20% of the time, for 5 minutes | | Pressure & out of memory |
More details per check:
- **Services** names up to four failed units, for example `nginx.service failed`.
- **Updates** is `ok` when only normal updates are pending. It shows the number of pending updates.
- **Reboot** shows the packages that need the reboot, if the package manager reports them.
- **Clock** uses two sources. The agent reports whether NTP is synchronised. Spectate also measures the clock offset on every report. Spectate corrects the timestamps of the samples, but you must fix the server's clock.
- **Pressure** only uses memory and I/O pressure. CPU pressure shows in the detail, but does not change the status.
## Which hosts have which checks
Spectate leaves out a check in these cases:
- Its collector is off for the host. See [collectors](/hosts/metrics#collectors).
- The check is Linux only and the host runs another system. Only **Clock** and **File handles** run on macOS.
The **Updates** and **Reboot** checks need apt, dnf or yum. The agent runs a separate package check every hour, which only reads the package lists on the server. It never runs `apt-get update` and never installs anything.
## Health alerts
Spectate can fire one alert per check. The alert fires when the problem has lasted for the time in the table. These are the defaults:
| Alert | Default | Severity | Fires after |
|---|---|---|---|
| Services | On | Critical | At once |
| Out of memory | On | High | At once. The alert stays open until one hour after the last kill. |
| Clock | On | Medium | 30 minutes without NTP synchronisation |
| Reboot | On | Low | 1 day |
| Updates | On | Low | 1 day of pending security updates |
| File handles | Off | High | 5 minutes above 95% |
| Pressure | Off | Medium | 5 minutes above 20% |
The **Clock** alert only fires when NTP is not synchronised. A clock offset alone changes the check to `warning`, but does not fire the alert.
A health alert resolves when the problem is over. It also resolves when you turn the alert off, or when you turn off its collector. Health alerts go to the same [escalation paths](/alerting/escalation-paths) as the other alerts of the host.
The alert text tells you where to look. For example, the Services alert says `Check them with: systemctl --failed`.
## Change the health alerts of a host
Owners, managers and admins can change the health alerts.
1. Open the host and go to **Settings & alerts**.
2. Under **Health alerts**, turn each alert on or off.
3. Select a severity for each alert: **Critical**, **High**, **Medium** or **Low**.
4. Select **Save changes**.
You cannot change the time before an alert fires. If the collector of an alert is off, the dashboard says that the alert cannot fire.
## Related
- [Metric conditions](/hosts/metric-conditions): alert on a metric threshold, or when a host stops reporting.
- [Alerts](/alerting/alerts): how Spectate acknowledges and resolves alerts.
---
## Document: Uptime monitor bot
Why the Spectate uptime monitor bot is in your access logs, and how to stop it.
URL: /faq/uptime-monitor-bot
# Uptime monitor bot
You found this page because a request in your access logs has this user agent:
```text
Spectate/1.0 (+https://docs.spectate.net/faq/uptime-monitor-bot)
```
This is the Spectate uptime checker. A Spectate customer added your website, API or server to a [monitor](/monitors/introduction). The checker sends a request to that address at a fixed interval, as often as every 30 seconds, from one or more of four regions. It measures if the address answers, how fast it answers, and if its certificate is valid.
## What the checker does
- It sends the request that the monitor specifies to one URL. It follows up to 10 redirects of that URL by default.
- When a check fails, the checker can open the URL in a browser to take a screenshot for the customer. The browser loads the page with its images, styles and scripts.
- It does not follow other links, crawl pages or submit forms.
- It sends its requests from the [Spectate IP addresses](/faq/ip-addresses).
## Stop the checks
If you own the website and you do not want these checks:
- Block the [IP addresses of the checkers](/faq/ip-addresses) or the user agent above. Spectate's customer then sees the monitor as down.
- If you think that someone uses Spectate to abuse your service, send an email to [abuse@spectate.net](mailto:abuse@spectate.net). Include the URL that the checker requests and the times of the requests.
## Allow the checks
If you use Spectate and your firewall or bot protection blocks the checker, allow the IP addresses on the [IP addresses](/faq/ip-addresses) page. For services such as Cloudflare, also allow the user agent above.
---
## Document: IP addresses
The IP addresses that Spectate uptime checks come from, per region, to allow or block in a firewall.
URL: /faq/ip-addresses
# IP addresses
Spectate sends uptime checks from four regions. Each region uses the IP addresses below. Allow them in your firewall, bot protection or allow list, so that Spectate can reach your services.
The same list is available as plain text for scripts: [ip-addresses.txt](/ip-addresses.txt).
## Notes
- A monitor only sends checks from the regions that it uses. See [Locations and checks](/monitors/locations-and-checks).
- The checkers send requests with the user agent `Spectate/1.0 (+https://docs.spectate.net/faq/uptime-monitor-bot)`.
- A check can come from the IPv4 or the IPv6 address of a region, depending on the target. Allow both.
---
## Document: TCP monitors
Check that a port accepts connections, with an optional TLS handshake and a keyword in the banner the server sends.
URL: /monitors/tcp
# TCP monitors
A TCP monitor opens a connection to a host and port, for example a database, an SSH server or a message broker. The check passes when the port accepts the connection. You can also make the monitor do a TLS handshake, and look for a keyword in the first data the server sends.
## Add a TCP monitor
1. In the sidebar, select **Monitors**.
2. Select **Create monitor**.
3. Under **Type**, select **TCP**.
4. In **Target**, enter the host and port, for example `db.example.com:5432`.
5. Under **TLS**, select **None** or **TLS**.
6. Select **Create and start**.
The port is required. For an IPv6 address, put the address in brackets: `[2001:db8::10]:5432`.
## What a check does
1. The Spectate checker looks up the host name. It tries the IPv4 addresses first, then the IPv6 addresses, until one accepts the connection.
2. If **TLS** is **TLS**, the checker does a TLS handshake and verifies the certificate.
3. If the monitor has a **Banner keyword**, the checker reads what the server sends and looks for the keyword.
The check fails if any of these is true:
- The host name does not resolve, or resolves to a private or reserved address.
- No address accepts the connection before **Connection timeout** ends.
- The TLS handshake fails, or the certificate is not valid and **Allow invalid certificates** is off.
- The banner keyword check fails.
- The check takes longer than **Timeout**.
The response time covers the DNS lookup, the connection, the TLS handshake and the banner read.
## TLS
With **TLS** set to **TLS**, the checker starts TLS at the first byte. It verifies the certificate against its trust store and the host name of the target. It uses TLS 1.2 or newer.
Select **Allow invalid certificates** to count the check as up when the certificate does not verify. Use it for self-signed certificates or an internal certificate authority.
A TCP monitor with TLS can also have [certificate checks](/monitors/certificates). They alert before the certificate expires.
## Banner keyword
Many servers send a line of text, the banner, after they accept a connection. SSH servers send a line such as `SSH-2.0-OpenSSH_9.6`. Enter text from that line in **Banner keyword**, for example `SSH-2.0`. The match is case-sensitive.
The checker reads up to 4 KiB. It stops reading when the server sends nothing for 500 milliseconds, closes the connection, or the timeout ends. It also stops when it finds the keyword.
Select **Invert keyword check** to fail the check when the banner contains the keyword.
If the server sends nothing until the client speaks first, leave **Banner keyword** empty. A keyword check on such a server always fails. The monitor **Overview** shows the banner of the latest check.
## Settings
| Setting | Values | Default |
|---|---|---|
| **Target** | `host:port` | |
| **TLS** | **None** or **TLS** | **None** |
| **Connection timeout** | 1 to 60 seconds, for the TCP connection only | The value of **Timeout** |
| **Banner keyword** | Up to 255 characters | Empty |
| **Invert keyword check** | On or off | Off |
| **Allow invalid certificates** | On or off. Only with **TLS**. | Off |
These settings are in the **Connection** section of the monitor settings. In the API, they are `uri`, `advanced_settings.tls_mode` (`none` or `tls`), `advanced_settings.connection_timeout`, `advanced_settings.keyword`, `advanced_settings.keyword_inverted` and `allow_insecure_requests`.
---
## Document: Ping monitors
Check that a host answers ICMP echo requests, and measure the round-trip time, with a Spectate ping monitor.
URL: /monitors/ping
# Ping monitors
A ping monitor sends ICMP echo requests to a host and waits for replies. Use it for servers, routers and other devices that do not run a web server. The check passes if at least one reply arrives before the timeout.
## Add a ping monitor
1. In the sidebar, select **Monitors**.
2. Select **Create monitor**.
3. Under **Type**, select **Ping**.
4. In **Target**, enter a host name or an IP address, for example `203.0.113.10`.
5. Select **Create and start**.
## What a check does
1. If the target is a host name, the Spectate checker looks up its IP address. If the name has both IPv4 and IPv6 addresses, the checker uses IPv4.
2. The checker sends 3 echo requests, 250 milliseconds apart.
3. It waits for replies until **Timeout** ends.
The check passes if at least one reply arrives. The response time is the average round-trip time of the replies.
The check fails if any of these is true:
- The host name does not resolve, or resolves to a private or reserved address.
- No reply arrives before **Timeout** ends. The error is `no icmp echo reply from ADDRESS (3 sent)`.
As for every monitor type, Spectate checks again about 5 seconds after a failure. Only a second failure makes the monitor down. See [Locations and checks](/monitors/locations-and-checks).
## Settings
| Setting | Values | Default |
|---|---|---|
| **Target** | A host name or an IPv4 or IPv6 address | |
| **Timeout** | 1 to 60 seconds, for the whole check | 10 seconds in the dashboard, 30 seconds in the API |
A ping monitor has no TLS, no keyword and no certificate checks. The other settings are the same as for every monitor. See [Uptime monitors](/monitors/introduction).
## Allow the checker through your firewall
Many firewalls drop ICMP echo requests. If your firewall drops them, the ping monitor is down even when the host works. Allow ICMP echo requests from the IP address of the region that checks the monitor. See [IP addresses](/faq/ip-addresses).
A host that answers ping can still have a service that does not work. To check a service, use a [TCP monitor](/monitors/tcp) on its port, or an [HTTP monitor](/monitors/http).
---
## Document: Response time alerts
Get an alert when a monitor gets slow, with a hard threshold in milliseconds or a rise above its recent baseline.
URL: /monitors/performance
# Response time alerts
Spectate records the response time of every check. With response time alerts on, a monitor also fires an alert when it answers, but too slowly. There are two thresholds: a hard limit in milliseconds, and a rise in percent compared with the monitor's own recent response times.
## Turn on response time alerts
1. Open the monitor.
2. Select the **Settings** tab.
3. Under **Alerting**, turn on **Slow responses**.
4. Set **Hard threshold**, **Deviation**, **Baseline window** and **Compared against**.
5. Select **Save changes**.
Response time alerts are off for a new monitor. In the API, the switch is `performance_check_enabled`.
## Hard threshold
**Hard threshold** is a response time in milliseconds, 1 to 30,000. The dashboard suggests 5,000.
Spectate compares each successful check with the hard threshold. If the response time is above it, Spectate fires the alert "Response time exceeded threshold for NAME" with the severity `high`. The alert shows the response time and the threshold.
The alert resolves at the first successful check that is at or below the threshold. Failed checks do not count. A failed check is a [down](/monitors/locations-and-checks) problem, not a response time problem.
## Deviation from the baseline
The deviation alert finds a monitor that gets slower than usual, also when it stays below the hard threshold. Every 5 minutes, Spectate compares two median response times:
- The median of the last **Baseline window**, for example the last 15 minutes.
- The median of the **Compared against** period before that window, for example the 2 hours before.
If the recent median is higher than the earlier median by **Deviation** percent or more, Spectate fires the alert "Response time deviated for NAME". The severity is `medium`. The alert resolves when a later comparison finds a rise below **Deviation**.
For example, the earlier median is 200 ms and **Deviation** is 100%. The alert fires when the recent median reaches 400 ms.
| Setting | Values | Default in the dashboard | API field |
|---|---|---|---|
| **Deviation** | 1 to 500 percent | 100 | `performance_deviation_percentage` |
| **Baseline window** | 15 minutes to 2 hours, in steps of 15 minutes | 15 minutes | `performance_deviation_timeframe`, in minutes |
| **Compared against** | 1 to 24 hours, in whole hours | 2 hours | `performance_deviation_before_timeframe`, in minutes |
**Baseline window** must be shorter than **Compared against**. Spectate needs checks in both periods. Each period must hold enough checks for a useful median. For example, with an interval of 5 minutes, a 15-minute window holds 3 checks.
## How the two thresholds work together
- A monitor has one response time alert at a time. While one fires, Spectate does not fire a second.
- If you set only **Hard threshold**, a check at or below it resolves the alert.
- If you leave a threshold empty in the API, Spectate does not use it. `performance_hard_threshold: null` turns off the hard threshold. `performance_deviation_percentage: null` turns off the deviation check.
- Spectate does not compare response times of a paused monitor.
Response time alerts follow the same [escalation paths](/alerting/escalation-paths) as the other alerts of the monitor. Because they have a lower severity than a down alert, a path can [branch on severity](/alerting/escalation-paths) and send them to a quieter channel.
## See the response times
The **Performance** tab of a monitor shows the response times for a period you select. It shows **Average**, **p50**, **p95**, **Apdex** and the number of **Samples**. For HTTP and HTTPS monitors, it also splits each request into phases: DNS lookup, connection, TLS handshake and time to first byte.
All response times come from the monitor's primary region. A monitor in Europe that checks a server in Asia has a longer response time than a monitor in Asia. See [Locations and checks](/monitors/locations-and-checks).
---
## Document: Pause and delete monitors
Stop the checks of a monitor for a time or for good, and learn why Spectate pauses monitors for the plan limit or an unpaid team.
URL: /monitors/pause-and-delete
# Pause and delete monitors
Pause a monitor to stop its checks for a time, for example during maintenance of the target. A paused monitor keeps its settings and its history, and you can resume it at any time. Delete a monitor when you do not need it again.
## Pause a monitor
1. Open the monitor.
2. Select **Pause** in the header.
You can also pause a monitor from its row on the **Monitors** page. In the API, use [pause a monitor](/api-reference/monitors).
When you pause a monitor:
- Spectate stops the checks at once. The monitor shows as **Paused**.
- The monitor keeps its settings, uptime history and response times.
- A firing alert of the monitor stays firing. Escalation continues until someone acknowledges it. If the problem is over, resolve the alert by hand.
- The monitor fires no new alerts.
## Resume a monitor
1. Open the monitor.
2. Select **Resume** in the header.
Spectate checks the monitor again when its interval has passed since the last check. If the monitor was down when you paused it, Spectate checks it at once.
Spectate refuses to resume a monitor in two cases:
- The team has reached the plan limit for monitors and hosts. Pause another monitor or host, or [change the plan](/account/plans-and-billing). The API returns `403` with the code `PLAN_LIMIT_REACHED`.
- The monitoring of the whole team is paused, because the team has no paid plan. The API returns `409` with the code `TEAM_MONITORING_PAUSED`.
## When Spectate pauses monitors
Spectate pauses monitors itself in two cases. The API shows the reason in `paused_reason`. A monitor that a member paused has `paused_reason: null`.
| `paused_reason` | Why | When it resumes |
|---|---|---|
| `plan_limit` | The team has more monitors and hosts than its plan allows, for example after a downgrade. | Spectate resumes it within an hour after the team has room again. You can also resume it by hand when there is room. |
| `team_paused` | The monitoring of the whole team is paused. The trial or the subscription ended, the team is scheduled for deletion, or Spectate support paused the team. | When the team subscribes to a plan, an owner cancels the deletion, or support resumes the team. |
Monitors and hosts share one limit. If a team is over the limit, Spectate keeps the oldest monitors and hosts running and pauses the newest. The dashboard shows a notice under the top bar: "N resources are paused because they are over your plan's limits". Select **View plans** to change the plan.
A new monitor of a team with paused monitoring starts paused.
When a team moves to a plan with a longer minimum interval, Spectate does not pause monitors. It raises their intervals to the plan minimum. See [Plans and billing](/account/plans-and-billing).
## Delete a monitor
1. Open the monitor.
2. Select the **Settings** tab.
3. Under **Danger zone**, select **Delete monitor**.
4. Type the name of the monitor in **Confirmation**.
5. Select **Delete monitor**.
When you delete a monitor:
- Spectate stops the checks at once.
- The monitor and its history no longer show in the dashboard, the API or the [MCP server](/developers/mcp). The monitor no longer counts toward the plan limit.
- A status page component that shows the monitor stays on the page. It no longer shows the uptime of the monitor.
- After 7 days, Spectate permanently deletes the monitor and all its data. This includes the check history, the response times, the alerts of the monitor and the failure snapshots.
- Incidents stay. An incident that started from an alert of the monitor loses the link to that alert.
You cannot undo a delete in the dashboard. In the first 7 days, Spectate support can restore the monitor with its history. Send an email to [help@spectate.net](mailto:help@spectate.net). To keep the history, pause the monitor instead.
To delete monitors, a member needs the role Owner, Manager or Admin. A member with the role Member can pause and resume monitors, but cannot delete them. See [Teams and roles](/account/teams-and-roles).
---
## Document: Mail server monitors
Check SMTP, IMAP and POP3 servers. Spectate reads the greeting, tests STARTTLS or implicit TLS, and never logs in.
URL: /monitors/mail-servers
# Mail server monitors
A mail server monitor connects to an SMTP, IMAP or POP3 server and checks that it answers like a mail server. It also checks that TLS works in the mode you select. Spectate never logs in and never sends or reads mail, so the monitor needs no credentials.
## Add a mail server monitor
1. In the sidebar, select **Monitors**.
2. Select **Create monitor**.
3. Under **Type**, select **SMTP**, **IMAP** or **POP3**.
4. In **Target**, enter the host name, for example `smtp.example.com`. Add `:PORT` to use another port.
5. Under **TLS**, select **STARTTLS**, **TLS** or **None**.
6. Select **Create and start**.
If the target has no port, Spectate adds the default port of the TLS mode when it saves the monitor.
## Default ports and TLS modes
| Type | TLS mode | Default port | Default mode |
|---|---|---|---|
| SMTP | **STARTTLS** | 587 | Yes |
| SMTP | **TLS** | 465 | |
| SMTP | **None** | 587 | |
| IMAP | **TLS** | 993 | Yes |
| IMAP | **STARTTLS** | 143 | |
| IMAP | **None** | 143 | |
| POP3 | **TLS** | 995 | Yes |
| POP3 | **STARTTLS** | 110 | |
| POP3 | **None** | 110 | |
In the mode **TLS**, the connection uses TLS from the first byte. This is also called implicit TLS. In the mode **STARTTLS**, the checker connects without encryption and then upgrades the session. It sends `STARTTLS` to SMTP and IMAP servers, and `STLS` to POP3 servers. In **STARTTLS** mode the upgrade is required. If the server does not offer it or refuses it, the check fails.
To monitor SMTP on port 25, enter the port in the target, for example `mx.example.com:25`. Spectate does not use port 25 by default.
## What a check does
| Type | Steps | Up when |
|---|---|---|
| SMTP | Read the greeting, send `EHLO`. With STARTTLS: send `STARTTLS`, upgrade, send `EHLO` again. Then `QUIT`. | The greeting is `220`, `EHLO` gets `250`, and the upgrade works if required |
| IMAP | Read the greeting. With STARTTLS: send `STARTTLS` and upgrade. Then `LOGOUT`. | The greeting starts with `* OK` or `* PREAUTH`, and the upgrade works if required |
| POP3 | Read the greeting. With STARTTLS: send `STLS` and upgrade. Then `QUIT`. | The greeting starts with `+OK`, and the upgrade works if required |
The check fails if any of these is true:
- The host name does not resolve, or resolves to a private or reserved address.
- The connection, a reply or the TLS handshake fails.
- The certificate is not valid, and **Allow invalid certificates** is off.
- The check takes longer than **Timeout**.
The response time does not include the closing `QUIT` or `LOGOUT`. The monitor **Overview** shows the first line of the greeting as the banner.
## Certificates
In **TLS** and **STARTTLS** mode, the checker verifies the certificate against its trust store and the host name of the target. It uses TLS 1.2 or newer.
Select **Allow invalid certificates** to count the check as up when the certificate does not verify. Use it for self-signed certificates or an internal certificate authority. A mail server monitor with TLS can also have [certificate checks](/monitors/certificates), which alert before the certificate expires.
## Settings
| Setting | Values | Default |
|---|---|---|
| **Target** | `host` or `host:port` | |
| **TLS** | **STARTTLS**, **TLS** or **None** | SMTP: **STARTTLS**. IMAP and POP3: **TLS**. |
| **Connection timeout** | 1 to 60 seconds, for the TCP connection only | The value of **Timeout** |
| **Allow invalid certificates** | On or off. Not with **None**. | Off |
These settings are in the **Connection** section of the monitor settings. In the API, the TLS mode is `advanced_settings.tls_mode`: `starttls`, `tls` or `none`.
---
## Document: Locations and checks
Where Spectate checks your monitors from, how often, how it confirms a failure before an alert, and how to recognise its requests.
URL: /monitors/locations-and-checks
# Locations and checks
Spectate runs uptime checks from checkers in four regions. Each monitor has one primary region, and every check of the monitor runs there. Before Spectate marks a monitor down, a second check from the same region, about 5 seconds later, must confirm the failure.
## Regions
| Region | `primary_location` in the API |
|---|---|
| Europe | `eu` |
| North America | `us` |
| Asia | `as` |
| Oceania | `oc` |
The checks of a region come from its own IP addresses. [IP addresses](/faq/ip-addresses) has the current list, also as plain text for firewalls.
To change the region of a monitor, open the monitor and select the **Settings** tab. Under **Region**, select the region, then select **Save changes**. Uptime, response times, charts and alerts of the monitor all come from this region. Select the region that is nearest to your users, or nearest to the server, to measure without long network paths.
## How often Spectate checks
A checker asks Spectate for the monitors that are due, about every 10 seconds. A monitor is due when its **Interval** has passed since its last check. One checker in the region gets the monitor, so each check runs one time.
Two kinds of monitors do not wait for the interval:
- Spectate checks a new monitor as soon as a checker asks.
- Spectate checks a monitor that is down every time a checker asks, until it is up again. So Spectate sees a recovery soon after it happens.
The plan sets the shortest interval: 60 seconds on Starter, 30 seconds on Team and Business. See [Uptime monitors](/monitors/introduction).
## How Spectate confirms a failure
1. A check fails, for example with a timeout or an unexpected status code.
2. The checker waits about 5 seconds.
3. The checker runs the check again, from the same region. This is the recheck.
4. If the recheck succeeds, the monitor is up. Spectate fires no alert.
5. If the recheck also fails, the monitor is down. Spectate fires the alert "NAME is down" with the severity `critical`.
The recheck does not run from another region. The other regions never change the uptime or the alerts of a monitor. With **Also measure response time from the other regions** (Team and Business plans), they only measure its response time for comparison.
For HTTP and HTTPS monitors, the recheck that makes the monitor down also records a [failure snapshot](/monitors/http#failure-snapshots-and-screenshots). One successful check makes the monitor up again, and Spectate resolves the down alert at once.
While the alert fires, Spectate does not fire a second down alert for the same monitor. The [escalation path](/alerting/escalation-paths) of the alert decides who gets notified, and when.
## Recognise the checks
HTTP and HTTPS checks send this `User-Agent` header, unless the monitor sets its own:
```http
User-Agent: Spectate/1.0 (+https://docs.spectate.net/faq/uptime-monitor-bot)
```
If a firewall, a WAF or a bot filter blocks the checks, allow the user agent or the IP address of the monitor's region. See [The uptime monitor bot](/faq/uptime-monitor-bot) and [IP addresses](/faq/ip-addresses).
Each HTTP check opens a new connection. It does not keep cookies between checks. The check measures DNS lookup, connection, TLS handshake and time to first byte. The **Heartbeats** tab shows these times per check in **Check log · 24h**.
## Targets Spectate does not check
Spectate checks only public addresses. It refuses targets that are, or resolve to, private, loopback, link-local, carrier-grade NAT, multicast or reserved addresses. Examples are `10.0.0.5`, `192.168.1.1`, `127.0.0.1` and `169.254.169.254`. The checker tests the address again before each connection, also after a redirect.
To monitor a server on a private network, give it a public address or a public URL. For metrics from inside the network, install the [Spectate host agent](/hosts/introduction).
---
## Document: Uptime monitors
The monitor types Spectate has, the settings every monitor shares, the states a monitor can be in, and what the dashboard shows.
URL: /monitors/introduction
# Uptime monitors
A Spectate uptime monitor checks one target, such as a URL, a host, a port or a DNS name, at a fixed interval. When the target stops answering as you expect, Spectate confirms the failure and fires an alert. Every check also records the response time, so you see how fast the target answers over time.
## Monitor types
| Type in the dashboard | `protocol` | Target | Up when | Page |
|---|---|---|---|---|
| HTTPS | `https` | URL | The status code is expected, and the keyword matches if set | [HTTP and HTTPS](/monitors/http) |
| HTTP | `http` | URL | The status code is expected, and the keyword matches if set | [HTTP and HTTPS](/monitors/http) |
| Ping | `icmp` | Host name or IP address | At least one ICMP echo reply arrives | [Ping](/monitors/ping) |
| TCP | `tcp` | `host:port` | The port accepts a connection | [TCP](/monitors/tcp) |
| DNS | `dns` | Domain name | The record resolves, and matches the expected values if set | [DNS](/monitors/dns) |
| SMTP | `smtp` | `host` or `host:port` | The server sends `220`, accepts `EHLO` and, by default, `STARTTLS` | [Mail servers](/monitors/mail-servers) |
| IMAP | `imap` | `host` or `host:port` | The server greets with `* OK` or `* PREAUTH` | [Mail servers](/monitors/mail-servers) |
| POP3 | `pop3` | `host` or `host:port` | The server greets with `+OK` | [Mail servers](/monitors/mail-servers) |
Spectate does not monitor private, loopback or reserved addresses. If a target resolves to such an address, the dashboard refuses it, or the check fails.
For HTTP and HTTPS, the type sets the scheme. Enter the URL without the scheme, for example `example.com/health`. Spectate stores it that way. In the public API, `uri` can also start with the scheme of `protocol`, for example `https://example.com/health`. Spectate removes the scheme before it stores the target. A scheme that does not match `protocol` gives the error `422`. See [Target format](/monitors/http#target-format).
## Add a monitor
1. In the sidebar, select **Monitors**.
2. Select **Create monitor**.
3. Under **Type**, select the monitor type.
4. In **Target**, enter the target in the format of the type.
5. Set the **Name**, **Interval** and **Primary region**.
6. Select **Create and start**.
To add the monitor without checks, select **Create paused** instead. You can [resume](/monitors/pause-and-delete) it later. Headers, keywords, authentication and alert thresholds are in the monitor's **Settings** tab after you create it.
You can also add monitors with the [public API](/api-reference/monitors) or the [MCP server](/developers/mcp). The API needs only `label`, `protocol`, `uri` and `interval`. Some API defaults are different from the dashboard:
| Setting | API default | Dashboard default |
|---|---|---|
| `enabled` | `true`, the monitor starts at once | Select **Create and start** or **Create paused** |
| `timeout` | 30 seconds | 10 seconds |
| `max_redirects` | `null`, up to 10 redirects | 3 |
| `certificate_check_enabled` | `false` | On for monitors that use TLS |
## Settings of every monitor
| Setting | Values | Default |
|---|---|---|
| **Name** | Up to 255 characters. Shown in the dashboard, alerts and status pages. | Filled in from the target |
| **Interval** | 30 seconds, 60 seconds, 2, 3, 5, 10, 15 or 30 minutes, 1 hour | 5 minutes |
| **Timeout** | 1 to 60 seconds. A check that takes longer fails. | 10 seconds in the dashboard, 30 seconds in the API |
| **Primary region** | Europe, North America, Asia, Oceania | Europe |
| **Project** | Any project of the team | The default project |
| **Alerting** | **Default routing** or **Specific paths** | **Default routing** |
The plan sets the shortest interval:
| Plan | Shortest interval |
|---|---|
| Trial | 30 seconds |
| Starter | 60 seconds |
| Team | 30 seconds |
| Business | 30 seconds |
If a team moves to a plan with a longer minimum, Spectate raises shorter intervals to that minimum. See [Plans and billing](/account/plans-and-billing).
**Primary region** sets where all checks of the monitor run. See [Locations and checks](/monitors/locations-and-checks).
**Default routing** sends alerts to the escalation paths of the monitor's project. If the project has none, the alerts go to the team default path. **Specific paths** sends alerts only to the [escalation paths](/alerting/escalation-paths) you select.
## Alerts a monitor fires
The **Alerting** section of the monitor settings lists the triggers under **Alert when**.
| Trigger | Fires when | Severity |
|---|---|---|
| **Monitor is down** | A check fails, and a second check from the same region about 5 seconds later also fails. Always on. | `critical` |
| **Slow responses** | The response time is above a threshold. Off by default. See [Performance](/monitors/performance). | `high` or `medium` |
| **Certificate problems** | The TLS certificate expires soon, expired or is not valid. See [Certificates](/monitors/certificates). | `medium` or `critical` |
| **DNS answer changes** | The answer of a DNS monitor changes. Off by default. See [DNS](/monitors/dns). | `low` |
A down alert resolves on its own at the first successful check.
## Monitor states
| State | Meaning |
|---|---|
| Pending | Spectate has not checked the monitor yet. |
| Up | The latest check succeeded. |
| Down | A check failed, and a second check from the same region about 5 seconds later confirmed the failure. |
| Paused | A member or the system turned the checks off. See [Pause and delete](/monitors/pause-and-delete). |
In the API, `enabled` tells if the monitor runs, and `uptime_status` is `pending`, `up` or `down`. A paused monitor keeps its last `uptime_status`.
## What the dashboard shows
The **Monitors** page lists all monitors with the ones that need attention first. Filter the list by **All**, **Up**, **Down**, **Pending** or **Paused**, or search by name, URL or region.
A monitor has these tabs:
| Tab | Shows |
|---|---|
| **Overview** | Uptime for 30 days, 7 days and 24 hours, response time for 24 hours, recent failures and the downtime report |
| **Performance** | Response times with average, p50, p95 and Apdex, and the request phases of HTTP checks |
| **Heartbeats** | Daily uptime for 30 days and the check log of the last 24 hours |
| **Certificate** | The TLS certificate chain. Only for monitors that use TLS. |
| **Settings** | All settings, alerting and the **Danger zone** |
The header shows the region, interval, type, timeout and the time of the last check. **Export CSV** downloads the downtime report of the current month.
For DNS monitors, **Overview** also shows the latest answer. For TCP and mail monitors, it shows the banner of the server, if there is one.
---
## Document: HTTP and HTTPS monitors
Check a website or API with an HTTP request. Set the method, headers, authentication, expected status codes, a keyword, redirects and timeouts.
URL: /monitors/http
# HTTP and HTTPS monitors
An HTTP or HTTPS monitor sends a request to a URL and checks the response. The check passes when the status code is one you expect and, if you set one, the body contains a keyword. An HTTPS monitor also checks the TLS certificate of the server.
## Add an HTTP or HTTPS monitor
1. In the sidebar, select **Monitors**.
2. Select **Create monitor**.
3. Under **Type**, select **HTTPS** or **HTTP**.
4. In **Target**, enter the URL without the scheme, for example `example.com/health`.
5. In **Max redirects**, enter how many redirects Spectate follows, 0 to 10.
6. Select **Create and start**.
The other settings are on the **Settings** tab of the monitor. Select **Save changes** after you change them.
## Target format
The type of the monitor sets the scheme. An HTTPS monitor requests `https://` and the target, and an HTTP monitor requests `http://` and the target. Spectate stores the target without the scheme, for example `example.com/health`.
If you paste a URL with a scheme into **Target**, the dashboard removes the scheme. To change the scheme, change **Type**.
In the [public API](/api-reference/monitors) and the [MCP server](/developers/mcp), the scheme in `uri` is optional:
| `protocol` | `uri` | Result |
|---|---|---|
| `https` | `example.com/health` | Spectate stores `example.com/health` and checks `https://example.com/health`. |
| `https` | `https://example.com/health` | The same monitor. Spectate removes the scheme. |
| `https` | `http://example.com/health` | Error `422`. The scheme must match `protocol`. |
The response has the stored target in `uri`, and the full URL in `url`.
## What a check does
1. The Spectate checker looks up the host name and opens a new connection. It never reuses a connection, so each check measures DNS, connect and TLS time.
2. It sends the request with the method, headers and authentication of the monitor. The request has no body.
3. It follows redirects, up to **Max redirects**.
4. It compares the status code with **Expected status**.
5. If the status code is expected and the monitor has a **Keyword**, it looks for the keyword in the body.
The check fails if any of these is true:
- The host name does not resolve, or resolves to a private or reserved address.
- The connection fails or the TLS handshake fails.
- The certificate is not valid, and **Allow insecure requests** is off. This applies to HTTPS only.
- The check takes longer than **Timeout**.
- The status code is not expected.
- The keyword check fails.
One failed check does not make the monitor down. Spectate checks again about 5 seconds later, and only a second failure makes the monitor down. See [Locations and checks](/monitors/locations-and-checks).
## Expected status codes
**Expected status** (`expected_http_status_code` in the API) lists the status codes that count as up. Separate codes with commas. A `*` matches any digit.
| Value | Counts as up |
|---|---|
| Empty (default) | 200 to 399 |
| `200` | Only 200 |
| `2**` | 200 to 299 |
| `2**,301` | 200 to 299, and 301 |
| `401` | Only 401, for example for a page behind a login |
| `*` | Any status code |
`2*` is the same as `2**`. The value can have up to 200 characters.
## Keyword
**Keyword** is text that must be in the response body. The match is case-sensitive. Spectate reads up to 1 MiB of the body. Text after the first 1 MiB is not checked.
Select **Invert keyword check** to fail the check when the body contains the keyword. Use this for text such as `Maintenance mode` or `Fatal error`.
Spectate checks the keyword only when the status code is expected. The keyword can have up to 255 characters.
## Method, headers and user agent
| Setting | Values | Default |
|---|---|---|
| **Method** | `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` | `GET` |
| **Headers** | Up to 25 headers. Names up to 255 characters, values up to 2,500 characters. | None |
| **User agent** | Up to 255 characters | `Spectate/1.0 (+https://docs.spectate.net/faq/uptime-monitor-bot)` |
To add a header, go to the **Headers** section and select **Add header**. A `Host` header sets the host name that the request asks for. If you set both **User agent** and a `User-Agent` header, **User agent** wins.
Some firewalls block unknown bots. To allow Spectate, see [The uptime monitor bot](/faq/uptime-monitor-bot) and [IP addresses](/faq/ip-addresses).
## Authentication
Set **Authentication** under **HTTP request → Advanced**.
| **Authentication** | Uses | Sends |
|---|---|---|
| None | | No credentials |
| Basic | **Auth username** and **Auth password / token** | HTTP Basic authentication |
| Bearer | **Auth password / token** | `Authorization: Bearer TOKEN` |
| Digest | **Auth username** and **Auth password / token** | HTTP Digest authentication, MD5 or SHA-256, `qop=auth` |
Spectate encrypts the password or token. The dashboard and the API never show it again. The field shows **Saved** when Spectate has a stored value. To keep the stored value, leave the field empty when you save.
## Redirects
Spectate follows up to **Max redirects** redirects, 0 to 10. The dashboard sets 3 for a new monitor. In the API, `max_redirects: null` follows up to 10.
If the server asks for more redirects than the limit, Spectate checks the last redirect response itself. With the default **Expected status**, a `3xx` response counts as up.
If a redirect goes to another host, scheme or port, Spectate removes credentials before it follows the redirect. It removes `Authorization`, `Cookie` and your custom headers. It keeps `Accept`, `Accept-Encoding`, `Accept-Language`, `Cache-Control`, `Pragma` and `User-Agent`. A redirect from `http` on port 80 to `https` on port 443 of the same host keeps all headers.
## Timeouts
| Setting | Limits | Default |
|---|---|---|
| **Timeout** | The whole check, 1 to 60 seconds | 10 seconds in the dashboard, 30 seconds in the API |
| **Connection timeout** | Only the TCP connection, 1 to 60 seconds | The value of **Timeout** |
**Connection timeout** is under **HTTP request → Advanced**. If it is longer than **Timeout**, **Timeout** applies.
## TLS
An HTTPS monitor verifies the certificate of the server against the trust store of the checker and the host name of the URL. If the verification fails, the check fails.
Select **Allow insecure requests** in the **TLS** section to skip this verification for the uptime check. Use it for self-signed certificates or an internal certificate authority. The separate [certificate checks](/monitors/certificates) still report and alert on certificate problems.
## Failure snapshots and screenshots
When an HTTP or HTTPS monitor goes down, Spectate keeps a snapshot of what the checker saw. It records one snapshot per outage, from the check that confirmed the failure.
A snapshot has:
- The error, the status code and the response time.
- The final URL after redirects, and the IP address that answered.
- The response headers. Spectate replaces the values of `Set-Cookie`, `Cookie`, `Authorization` and `Proxy-Authorization` with `[redacted]`.
- The first 128 KiB of the body, and the page title.
- A screenshot of the page, 1440 by 900 pixels, from the same region.
Spectate takes the response and the screenshot only when the server sent an HTTP response. A refused connection, a DNS error or a TLS error has no snapshot body and no screenshot.
The screenshot uses the user agent, headers and Basic or Bearer authentication of the monitor. It sends them only to the monitor's own host. Digest authentication does not work for screenshots.
Screenshots are part of every paid plan and the trial. The snapshot shows on the alert page under **What we saw**, and on the monitor **Overview** under **Recent failures**. Spectate deletes snapshots and screenshots after 90 days.
| Screenshot status | Meaning |
|---|---|
| `pending` | The checker takes the screenshot. It arrives a few seconds after the alert. |
| `captured` | The screenshot is stored. |
| `failed` | No screenshot was possible. The snapshot shows the reason. |
| `not_requested` | The plan has no screenshots, or the server sent no HTTP response. |
## Settings reference
The names in the [public API](/api-reference/monitors). Settings in `advanced_settings` are marked with `advanced_settings.`.
| Dashboard label | API field |
|---|---|
| **Target** | `uri` |
| **Max redirects** | `max_redirects` |
| **Timeout** | `timeout` |
| **Expected status** | `expected_http_status_code` |
| **Allow insecure requests** | `allow_insecure_requests` |
| **Headers** | `headers`, a list of `key` and `value` |
| **Method** | `advanced_settings.method` |
| **Keyword** | `advanced_settings.keyword` |
| **Invert keyword check** | `advanced_settings.keyword_inverted` |
| **Connection timeout** | `advanced_settings.connection_timeout` |
| **User agent** | `advanced_settings.useragent` |
| **Authentication** | `advanced_settings.auth_method`: `basic`, `bearer` or `digest` |
| **Auth username** | `advanced_settings.auth_user` |
| **Auth password / token** | `advanced_settings.auth_password`, write-only |
---
## Document: DNS monitors
Check that a DNS record resolves and has the values you expect, and get an alert when the answer changes.
URL: /monitors/dns
# DNS monitors
A DNS monitor asks a resolver for one record of a domain name, for example the `A` record of `example.com`. The check passes when the record exists and, if you set expected values, the answer matches them. Use it to find DNS mistakes, expired zones and records that someone changed.
## Add a DNS monitor
1. In the sidebar, select **Monitors**.
2. Select **Create monitor**.
3. Under **Type**, select **DNS**.
4. In **Target**, enter the domain name, for example `example.com` or `_dmarc.example.com`.
5. Under **Record**, select the record type.
6. In **Expected values**, enter the values the answer must have, one per line. This is optional.
7. Select **Create and start**.
## What a check does
1. The Spectate checker sends a query for the record type over UDP. If the answer is truncated, it asks again over TCP.
2. It reads the records of that type from the answer.
3. If the monitor has expected values, it compares them with the answer.
The check fails if any of these is true:
- The response code is not `NOERROR`, for example `NXDOMAIN` or `SERVFAIL`. The error is `dns rcode NXDOMAIN`.
- The answer has no records of the type. The error is `no A records for example.com`.
- The answer does not match the expected values.
- The query takes longer than **Timeout**.
## Record types
| Record | Value format in the answer | Example |
|---|---|---|
| `A` | IPv4 address | `203.0.113.10` |
| `AAAA` | IPv6 address | `2001:db8::10` |
| `CNAME` | Host name | `target.example.net` |
| `MX` | Preference and host | `10 mx.example.com` |
| `NS` | Host name | `ns1.example.net` |
| `TXT` | The text, with the strings joined | `v=spf1 include:_spf.example.com ~all` |
| `CAA` | Flag, tag and value | `0 issue "letsencrypt.org"` |
| `SOA` | Primary name server, mailbox and serial | `ns1.example.net hostmaster.example.com 2026102201` |
Enter expected values in the same format. The default record type is `A`.
## Expected values and matching
**Match** decides how Spectate compares the answer with **Expected values**:
| **Match** | API value | The check passes when |
|---|---|---|
| **Answer contains every value** | `contains` | Every expected value is in the answer. The answer can have more values. |
| **Answer is exactly these values** | `exact` | The answer has the expected values and no others, in any order. |
The comparison ignores upper and lower case and a dot at the end of a name. Quotes around a `TXT` value are optional. You can enter up to 20 values, each up to 512 characters. Without expected values, any answer with at least one record of the type passes.
## Resolver
By default, the checker asks its own resolver. You can change this in the **DNS query** section of the settings:
- **Resolver**: ask a public resolver, as an IP address with an optional port, for example `1.1.1.1` or `9.9.9.9:53`.
- **Ask the authoritative nameservers**: find the name servers of the zone and ask one of them directly. The answer skips resolver caches, so you see a change as soon as the zone publishes it.
With **Ask the authoritative nameservers** on, **Resolver** is not used. Spectate does not query private or reserved addresses.
## Alert when the answer changes
Under **Alerting**, turn on **DNS answer changes** to get an alert when the answer is different from the answer of the previous check. Spectate fires the alert even when the new answer still matches the expected values.
The alert has the severity `low` and the title "DNS records changed for NAME". It shows the old and the new answer. This alert does not resolve on its own. While it fires, later changes do not fire a second alert. Resolve it on the alert page after you check the change.
## Settings reference
| Dashboard label | API field | Default |
|---|---|---|
| **Target** | `uri` | |
| **Record** or **Record type** | `advanced_settings.dns_record_type` | `A` |
| **Expected values** | `advanced_settings.dns_expected_values` | None |
| **Match** | `advanced_settings.dns_match` | `contains` |
| **Resolver** | `advanced_settings.dns_resolver` | The checker's resolver |
| **Ask the authoritative nameservers** | `advanced_settings.dns_authoritative` | Off |
| **DNS answer changes** | `advanced_settings.dns_alert_on_change` | Off |
---
## Document: Certificate checks
Get an alert before a TLS certificate expires, and when a certificate is expired, untrusted, for the wrong host or issued by a new authority.
URL: /monitors/certificates
# Certificate checks
A certificate check reads the TLS certificate chain of a monitor's server and checks it for problems. Spectate alerts before the certificate or an intermediate certificate expires, so you can renew it in time. It also alerts when the chain is not valid.
## Which monitors have certificate checks
Certificate checks work for every monitor that does a TLS handshake:
- HTTPS monitors.
- TCP monitors with **TLS** set to **TLS**.
- SMTP, IMAP and POP3 monitors with **TLS** or **STARTTLS**.
When you create one of these monitors in the dashboard, certificate checks are on. In the API, `certificate_check_enabled` is `false` by default.
## Turn certificate checks on or off
1. Open the monitor.
2. Select the **Settings** tab.
3. Under **Alerting**, turn **Certificate problems** on or off.
4. In **Warn before expiry**, enter the number of days, 1 to 90.
5. Select **Save changes**.
The default for **Warn before expiry** is 14 days. In the API, it is `certificate_expiry_threshold_days`.
## How the check works
The Spectate checker reads the certificate during a normal check, at most one time every 15 minutes. For an HTTPS monitor, it opens a separate TLS connection to the host and port of the URL after the HTTP check.
The checker verifies the chain against its trust store and the host name of the target. It reports the whole chain: the certificate of the server, the intermediate certificates and the root.
## Certificate states
| State | Meaning |
|---|---|
| `pending` | Spectate has not read the certificate yet. |
| `valid` | The chain is trusted, and no certificate in it expires within **Warn before expiry**. |
| `expires_soon` | The chain is valid, but a certificate that the server sends expires within **Warn before expiry**. |
| `expired` | The certificate has expired. |
| `invalid` | The chain is not trusted. For example, it is self-signed, for another host name, or misses an intermediate certificate. |
For `expires_soon`, Spectate looks at every certificate that the server sends, not only the server's own certificate. An expired intermediate certificate breaks the chain in the same way. Spectate ignores root certificates from the trust store of the checker.
## Alerts
| Alert | Severity | Fires when |
|---|---|---|
| "Certificate expires soon for NAME" | `medium` | The state is `expires_soon` because of the server's own certificate. |
| "Intermediate certificate CN expires soon for NAME" | `medium` | The state is `expires_soon` because of an intermediate certificate. |
| "Certificate expired for NAME" | `critical` | The state is `expired`. |
| "Certificate invalid for NAME" | `critical` | The state is `invalid`. |
| "Certificate issuer changed for NAME" | `low` | A new certificate comes from another certificate authority than the previous one. |
The description of an "expires soon" alert gives the days left and the expiry date, for example "Expires in 13 days, on 9 Nov 2026." Emails, Slack and Telegram messages show it. The title does not change from day to day.
A monitor has one certificate state alert at a time. While the state stays the same, the alert stays open. Spectate updates the days left in the description, but it does not fire a new alert or escalate again. If the state changes, for example from `expires_soon` to `expired`, Spectate resolves the old alert and fires a new one. The new alert goes through the escalation paths again. When the certificate is `valid` again, Spectate resolves the alert.
The issuer change alert is a heads-up. A renewal by another certificate authority can be a planned change, a mistake or a takeover. This alert does not resolve on its own. Resolve it on the alert page after you check the certificate.
## Certificates and uptime
Certificate checks and uptime checks are separate. An HTTPS check also verifies the certificate. If the certificate is expired or not trusted, the uptime check fails, and the monitor goes down too.
To keep the uptime check up with a self-signed certificate, turn on **Allow insecure requests** (HTTPS) or **Allow invalid certificates** (TCP and mail). Certificate checks still report the problem.
## See the certificate
Monitors that use TLS have a **Certificate** tab. It shows the **Certificate chain** from the latest certificate check. For each certificate, it shows the subject, the issuer, the dates and the host names. It also shows the key, the signature algorithm, the serial number and the SHA-256 fingerprint. The tab also shows the TLS version and cipher suite.
The **Overview** tab shows the certificate state. If certificate checks are off, the **Certificate** tab says **Certificate checks are off**.
---
## Document: MCP server
Connect Claude, ChatGPT, Cursor or another AI assistant to Spectate with OAuth, and let it work with your role.
URL: /developers/mcp
# MCP server
Spectate has a hosted [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server. Connect an AI assistant to it. The assistant can then answer questions about your incidents, alerts, monitors and status pages, and work in Spectate for you. The assistant always has the same access as you: your role in each team, nothing more.
```text
https://api.spectate.net/mcp
```
There is nothing to install and no API key to copy. The assistant registers itself, and you sign in to Spectate in your browser.
## Before you connect
- You need a Spectate account with a verified email address.
- At least one of your teams must allow AI assistants. This is on by default. See [Team setting](#team-setting).
- Your AI client must support remote MCP servers over Streamable HTTP with OAuth.
Team API tokens (`spct_...`) do not work with the MCP server. The MCP connection does not work with the public API.
## Connect your client
| Client | How to connect |
|---|---|
| Claude (web and desktop) | Open **Settings → Connectors → Add custom connector**. Type the name `Spectate` and the URL `https://api.spectate.net/mcp`. Select **Connect** and sign in. |
| Claude Code | Run `claude mcp add --scope user --transport http spectate https://api.spectate.net/mcp`. Then run `/mcp`, select Spectate and sign in. |
| Cursor | Add `{"mcpServers": {"spectate": {"url": "https://api.spectate.net/mcp"}}}` to `~/.cursor/mcp.json`. Restart Cursor and sign in when Cursor asks. |
| VS Code | Run `code --add-mcp '{"name":"spectate","type":"http","url":"https://api.spectate.net/mcp"}'`. Start the server from the MCP list and sign in. |
| Codex | Run `codex mcp add spectate --url https://api.spectate.net/mcp`. Then run `codex mcp login spectate`. |
| Other clients | Use the transport Streamable HTTP, the URL `https://api.spectate.net/mcp` and OAuth with automatic client registration. |
Your client opens Spectate in your browser:
1. Sign in, if you are not signed in.
2. Read the consent screen.
3. Select **Allow access**.
The consent screen shows two things:
- **The application.** Claude, ChatGPT, Cursor and VS Code have a **Verified** mark. Other clients show the name that they registered, a warning, and the address that receives the authorization. Allow access only for an assistant that you connected yourself.
- **The teams.** The teams that the assistant can use, with your role in each team. Teams that do not allow AI assistants are not on the list.
## Check the connection
Start with a request that changes nothing:
> Use Spectate to list my teams and tell me what is going on in each team. Do not change anything.
The assistant first calls `list_teams`. This tool returns your teams and your role in each team. It also returns the AI assistant access of each team (`full` or `read_only`) and the tools that you can use there.
## What the assistant can do
| Area | Tools |
|---|---|
| Overview | `get_overview`: open incidents, firing alerts, monitors that are down, certificates, hosts that need attention, domains that expire soon, and who is on call. It leaves out sections that your role cannot read. |
| Incidents | `list_incidents`, `get_incident`, `get_incident_timeline`, `declare_incident`, `update_incident`, `post_incident_update`, `acknowledge_incident`, `resolve_incident`, `assign_incident_role`, `get_incident_postmortem`, `save_incident_postmortem`, `publish_incident_to_status_page`, `delete_incident` |
| Alerts | `list_alerts`, `get_alert`, `acknowledge_alert`, `resolve_alert`. Read only: `list_escalation_paths`, `get_escalation_path`, `list_channels`, `list_alert_sources` |
| On-call | `list_on_call_schedules`, `get_on_call_now`, `get_on_call_timeline`, `create_on_call_override`, `delete_on_call_override` |
| Monitors | `list_monitors`, `get_monitor` (with recent failed checks and the checks of the last 24 hours), `create_monitor`, `update_monitor`, `pause_monitor`, `resume_monitor`, `delete_monitor` |
| Hosts, domains and projects | `list_hosts`, `get_host`, `list_domains`, `get_domain`, `create_domain`, `delete_domain`, `list_projects` |
| Status pages | `list_status_pages`, `get_status_page`, `list_status_page_incidents`, `get_status_page_incident`, `create_status_page_incident`, `post_status_page_incident_update`, `update_status_page_incident`, `delete_status_page_incident`, `list_scheduled_maintenances`, `schedule_maintenance`, `update_scheduled_maintenance`, `delete_scheduled_maintenance`, `list_status_page_issue_reports` |
| Team | `list_teams`, `list_team_members` (names and roles, no email addresses) |
Example requests:
- "What is going on in production now?"
- "Summarize INC-42 for the weekly report: what happened, when, and who did what."
- "The checkout monitor is down. Look at its recent checks and tell me why."
- "Declare a high-severity incident for slow API responses and make me the commander."
- "Write a postmortem for yesterday's incident from its timeline and save it."
- "Post on our status page that we are investigating slow API responses. Show me the text first."
- "Who is on call this weekend? Put Sam on call for me on Saturday from 09:00 to 17:00."
## How access works
- The connection belongs to you, not to a team. Each tool call names one team.
- On every call, Spectate checks that you are still a member of the team, the permissions of your current role, that the team is not being deleted or suspended, and the team's AI assistant setting. A change to any of these applies to the next call.
- The assistant acts as you. Changes show under your name in timelines, Slack and notifications. The activity log marks them as made through an AI assistant, with the assistant's name.
- The roles work as in the dashboard. Owners, managers and admins can use all tools. Members can read everything, work on incidents, change monitors, and acknowledge and resolve alerts. Members cannot delete things, add domains, or change on-call schedules or status pages. The billing role cannot read monitoring data, so it has no tools.
Some things are never available through the MCP server:
- API tokens, secrets of alert sources and channels, and status page access keys.
- Billing, members and invites, and team settings.
- Team deletion and status page subscribers.
## Confirmations
Some actions run only after you approve them in the chat:
- Deleting: an incident, a monitor, a domain, an on-call override, a public incident or a maintenance window.
- Public actions and emails to people outside your team: all changes to a status page and to its incidents and maintenance, and emails to subscribers.
The assistant first shows you what it will do. For a status page, it shows the exact public text and if subscribers get an email. Spectate refuses the action if the assistant does not send your approval with it. Your client can also ask you before each change. That is a setting of the client.
## Team setting
Owners and managers set the AI assistant access of each team in **Team → Settings → AI assistants**:
| Setting | Effect |
|---|---|
| Full (default) | Assistants can read and change what each member's role allows. |
| Read only | Assistants can read. Spectate refuses all tools that change something. |
| Off | Assistants cannot use the team. The team is not on the consent screen and not in `list_teams`. |
A change applies to existing connections immediately. You can change this setting only in the dashboard, not through MCP or the API.
## Manage your connections
**Account → AI assistants** shows the assistants that you connected. For each assistant, it shows when you connected it and when it was last used. **Disconnect** removes the access of an assistant immediately. To use it again, connect it again. A password reset disconnects all your assistants.
## Limits
- 120 requests a minute for each connection. Of these, 30 can change something.
- A connection stays signed in while you use it. After 30 days without use, you must approve it again. Access tokens are valid for one hour, and the client renews them.
## Safety
- Incident titles, alert data from other tools, monitor responses and status page issue reports can contain text from other people. Issue reports can come from anyone on the internet. Spectate tells assistants never to follow instructions in this text. Read what an assistant proposes before you approve it.
- For teams where assistants only answer questions, use **Read only**.
## Troubleshooting
| Problem | What to do |
|---|---|
| The consent screen says that no team allows AI assistants | An owner or manager turns them on in **Team → Settings → AI assistants**. |
| A team is not in the list | Check that you are a member and that the team allows AI assistants. |
| "Your role in this team does not allow this" | Your role does not have the permission that the message names. |
| "This team allows AI assistants to read only" | The team setting is **Read only**. |
| "Not done yet. Show the member exactly what this will do..." | The action needs your approval in the chat. Approve it, and the assistant tries again. |
| The client asks you to sign in again and again | Remove the Spectate server from the client. Then add it again with the URL above. |
---
## Document: Public API
Manage monitors, alerts, incidents, status pages and your team over HTTP with the Spectate REST API.
URL: /developers/api
# Public API
Use the Spectate public API to manage your team from scripts, CI pipelines and other tools. It covers monitors, hosts, domains, projects, alerting, on-call, incidents, status pages, members and billing information. Every endpoint, with its parameters and responses, is in the [API reference](/api-reference).
```text
https://api.spectate.net/v1
```
## Make your first request
1. Create a [team API token](/developers/api-tokens) with the `monitors:read` ability.
2. Send it as a bearer token:
```bash
curl https://api.spectate.net/v1/monitors \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
```
The response lists the monitors of the team that owns the token. To check a token and see its abilities, call `GET /v1/token`.
## Requests and responses
- Send JSON request bodies with `Content-Type: application/json`. Every response is JSON, errors too.
- IDs are UUIDs. Times are ISO 8601 in UTC, for example `2026-10-25T14:03:00+00:00`.
- `PATCH` changes only the fields that you send. To clear a field that can be empty, send `null`.
- The API never returns secrets that you send, such as passwords and webhook secrets.
## Pagination, filters and sorting
List endpoints return pages of results. Use `page` (from 1) and `per_page` (1 to 100, default 25).
| Response field | Meaning |
|---|---|
| `data` | The items on this page. |
| `current_page`, `last_page` | The page number and the number of the last page. |
| `per_page`, `total` | Items per page and the total number of items. |
| `from`, `to` | The positions of the first and the last item on this page. |
Filter with `filter[name]=value`. Sort with `sort=field`, or `sort=-field` for descending order. Each list endpoint in the reference shows its filters and sort fields.
```bash
curl "https://api.spectate.net/v1/incidents?filter[status]=investigating&sort=-started_at" \
-H "Authorization: Bearer YOUR_API_TOKEN"
```
## Errors
Every error has the same shape:
```json
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Monitor not found."
}
}
```
Use `error.code` in your code. It does not change. `error.message` is for people and can change. Some errors add `error.details`. For example, a `422` lists the invalid fields in `error.details.errors`.
| Status | Codes | Meaning |
|---|---|---|
| `400` | `INVALID_QUERY` | The query is not correct, for example an unknown filter or sort field. |
| `401` | `UNAUTHENTICATED`, `INVALID_TOKEN`, `TOKEN_EXPIRED` | No token, or the token is not valid, revoked or expired. |
| `403` | `FORBIDDEN`, `PLAN_LIMIT_REACHED`, `PLAN_FEATURE_UNAVAILABLE`, `TEAM_PENDING_DELETION`, `TEAM_SUSPENDED` | The token does not have the ability, the plan does not allow it, or the team is being deleted or is suspended. |
| `404` | `RESOURCE_NOT_FOUND`, `NOT_FOUND` | The resource is not in this team, or the endpoint does not exist. |
| `409` | `CONFLICT` | The request conflicts with the current state. |
| `422` | `VALIDATION_FAILED` | The request body is not valid. |
| `429` | `RATE_LIMITED` | Too many requests. See the next section. |
| `5xx` | `INTERNAL_ERROR` | A problem on our side. Try again later, with a longer wait each time. |
## Rate limits
Each token can send 300 requests a minute. Of these, 60 can change something (`POST`, `PUT`, `PATCH` and `DELETE`). Each response has the headers `X-RateLimit-Limit` and `X-RateLimit-Remaining`. When a token is over the limit, the API returns `429` with a `Retry-After` header in seconds.
## Versioning
This is version 1 of the API, under `/v1`. In version 1, changes only add things: new endpoints, new optional request fields, new response fields and new enum values. Your code must accept fields and enum values that it does not know. A change that can break a client comes in a new version. We announce a new version before we remove the old one.
## OpenAPI document
The API reference comes from an OpenAPI 3.1 document. Use it to generate a client or to import the API into a tool:
- [Download the OpenAPI document](/api-reference/1.0.0/spectate-openapi-v1.json)
- [The API reference as one Markdown file](/api-reference.md), for AI assistants and offline reading
## Related
Create tokens with only the abilities that a script needs.
Every endpoint, with examples in cURL, JavaScript, Python, PHP and Go.
---
## Document: API tokens
Create team API tokens for the public API, choose their abilities and expiry, and regenerate or revoke them.
URL: /developers/api-tokens
# API tokens
A team API token gives a script access to the [public API](/developers/api) for one team. The token belongs to the team, not to the member who created it. It continues to work when that member leaves the team.
## Create a token
Owners and managers can create tokens.
1. In the dashboard, go to **Team → API tokens**.
2. Select **Create token**.
3. Type a name that tells you where the token is used, for example `Terraform` or `CI deploy`.
4. Select when the token expires: **30 days**, **90 days**, **1 year** or **Never**.
5. Select the abilities. **Read only** selects all read abilities. **Full access** selects all abilities.
6. Select **Create token**.
7. Copy the token. Spectate shows it only once.
:::caution
Keep the token secret. Anyone with the token can do everything that its abilities allow. Do not put a token in client-side code or in a public repository.
:::
## Abilities
A token can only do what its abilities allow. There is no wildcard ability, so a token never gets new abilities later. You cannot change the abilities of a token after you create it. Create a new token instead.
You can only give abilities that your own role has. Each endpoint in the [API reference](/api-reference) shows the ability that it needs.
| Ability | What the token can do |
|---|---|
| `monitors:read` | Read monitors, their checks, uptime and certificates. |
| `monitors:write` | Create and change monitors, and pause or resume them. |
| `monitors:delete` | Delete monitors. |
| `hosts:read` | Read hosts, their metrics and metric conditions. |
| `hosts:write` | Change hosts, install tokens and metric conditions. |
| `hosts:delete` | Delete hosts. |
| `domains:read` | Read domains and their registration and DNS state. |
| `domains:write` | Add and change domains. |
| `domains:delete` | Delete domains. |
| `projects:read` | Read projects. |
| `projects:write` | Create and change projects. |
| `projects:delete` | Delete projects. |
| `alerting:read` | Read alerts, channels, escalation paths, alert sources and on-call schedules. |
| `alerting:write` | Create and change channels, escalation paths, alert sources and on-call schedules. |
| `alerting:delete` | Delete channels, escalation paths, alert sources, on-call schedules and resolved alerts. |
| `alerts:acknowledge` | Acknowledge alerts. This stops their escalation. |
| `alerts:resolve` | Resolve alerts by hand. |
| `incidents:read` | Read incidents, their updates, timeline and postmortem. |
| `incidents:write` | Declare, update, acknowledge and resolve incidents. |
| `incidents:delete` | Delete incidents. |
| `status-pages:read` | Read status pages, components, status page incidents, maintenances and subscribers. |
| `status-pages:write` | Create and change status pages, components, status page incidents and maintenances. |
| `status-pages:delete` | Delete status pages, components, status page incidents, maintenances and subscribers. |
| `members:read` | Read team members and pending invites. |
| `members:write` | Invite members, change their roles and remove them. |
| `team:update` | Change the name and settings of the team. |
| `billing:read` | Read the subscription, notification credits and plan usage. |
A token cannot manage API tokens, open support tickets, change billing or delete the team.
## Token format
Tokens start with `spct_`, followed by 46 letters and digits. The last 6 characters are a checksum. Secret scanners can use the prefix and the checksum to find leaked tokens. Spectate keeps only a hash of each token, so a lost token cannot be recovered.
## Regenerate or revoke a token
In **Team → API tokens**, each token has two actions:
- **Regenerate** gives the token a new secret. The name, abilities and expiry stay the same. The old secret stops working immediately.
- **Revoke** stops the token permanently. Revoked and expired tokens stop working immediately.
A team can have 50 active tokens at most.
## Changes made with a token
Spectate shows changes made with a token under the token's name, for example `API token "Terraform"`. You see this name in incident timelines, in Slack messages and in the activity log.
---
## Document: Domain monitoring
Track the registration of your domains with RDAP and WHOIS. See the expiry date, registrar, nameservers and DNSSEC, and get alerts before a domain lapses.
URL: /domains/introduction
# Domain monitoring
Domain monitoring watches the registration of your domains at the registry. Spectate reads the expiry date, the registrar, the nameservers and the DNSSEC records every 6 hours. It alerts your team before a domain expires, and when its registration changes.
## Add a domain
Owners, managers and admins can add domains.
1. In the dashboard, go to **Domains**.
2. Select **Add domain**.
3. In **Domain**, type the registered domain, for example `example.com`. Do not type `https://`, a path or a subdomain.
4. To add the domain paused, clear **Start monitoring immediately**.
5. Select **Add domain**.
Spectate looks up the domain at once. The domain joins the team's default [project](/account/projects). Domain names with non-ASCII characters, such as `bücher.de`, are also accepted.
Domains do not count towards the monitors and hosts of your plan. Every paid plan and the trial include an unlimited number of domains.
## How Spectate finds registry data
Spectate asks the registry of the domain's top-level domain (TLD) in this order:
1. **RDAP**, through the IANA list of RDAP servers. This covers every generic TLD, such as `.com` and `.net`, and many country TLDs.
2. **RDAP**, through Spectate's list of other country registries, such as `.de`, `.ch`, `.io`, `.me` and `.us`.
3. **WHOIS** on port 43, for registries without RDAP.
The domain page shows which source the data came from. Spectate limits how often it asks each registry. If a registry asks Spectate to wait, the lookup waits and does not count as a failure.
## What the dashboard shows
The **Domains** page lists each domain with its **Registrar**, **Nameservers**, **DNSSEC** state and **Expires** date. The filters are **All**, **At risk** (expired, or expiring within the alert threshold), **No DNSSEC** and **Paused**.
The domain page shows:
- **Expires**: the expiry date and the time left.
- **Registered**, **Last changed**, **Registry updated** and **Tracking since**.
- The **Registrar**, the **DNSSEC** state (**Signed**, **Unsigned** or **Unknown**) and **Last check**.
- **Nameservers**: the nameservers at the registry.
- **EPP statuses**: the status codes of the registry, such as `clientTransferProhibited`.
- **DNSSEC records**: the DS records at the registry.
- **Change history**: the registry and expiry alerts of the domain.
## Domains without registry data
Some registries publish less data, or none. The dashboard then shows one of these messages:
| Message | Meaning |
|---|---|
| **No registry data** | The registry publishes neither RDAP nor WHOIS, so Spectate cannot track expiry or the registrar. About 50 country TLDs are like this, for example `.gr` and `.vn`. |
| **Not published** | The registry does not publish expiry dates. Spectate still tracks the registrar, nameservers and status. Examples are `.de`, `.nl`, `.eu`, `.be`, `.at`, `.lu` and `.ch`. |
| **Not registered** | The registry has no record of the domain. Check the spelling, and enter the registered domain, not a subdomain. |
| **Retrying** | The registry did not answer the last lookup, after 5 tries. Spectate tries again later. |
The API returns these states in `registry_error` as `unsupported`, `not_registered` and `unavailable`. `registry_source` is `rdap` or `whois`.
## Pause a domain
A paused domain keeps its registry data, but Spectate does not look it up again and does not fire alerts.
1. Open the domain and go to **Settings**.
2. Clear **Monitoring enabled**.
3. Select **Save changes**.
To start again, select **Monitoring enabled**. If the team's monitoring is paused, you cannot start a domain again. See [plans and billing](/account/plans-and-billing).
## Delete a domain
Owners, managers and admins can delete domains.
1. Open the domain and go to **Settings**.
2. Under **Danger zone**, select **Delete domain**.
3. Type the domain name to confirm.
4. Select **Delete domain**.
Spectate stops the checks of the domain at once, and the domain no longer shows in the dashboard or the API. Nothing changes at the registrar. After 7 days, Spectate permanently deletes the domain with its registry data and its alerts. Incidents stay.
In the first 7 days, Spectate support can restore the domain. Send an email to [help@spectate.net](mailto:help@spectate.net).
## Related
- [Domain checks](/domains/checks): every alert that domain monitoring fires.
- [DNS monitors](/monitors/dns): check DNS records, such as A, MX or TXT records.
- [Certificates](/monitors/certificates): alert before a TLS certificate expires.
---
## Document: Domain checks
The alerts of Spectate domain monitoring, for expiry, lapsed registrations, and registrar, nameserver and DNSSEC changes, with severities and settings.
URL: /domains/checks
# Domain checks
Every 6 hours, Spectate looks up each domain at its registry and compares the result with the last lookup. This page lists the alerts that a lookup can fire, their severities, and the settings that control them. [Domain monitoring](/domains/introduction) explains how the lookup works.
## Alerts
| Alert | Severity | Fires when | Setting |
|---|---|---|---|
| `Domain example.com expires soon` | Medium | The expiry date is within the threshold. The default threshold is 30 days. | **Warn before expiry** |
| `Domain example.com has expired` | Critical | The expiry date is in the past. | Always on |
| `Domain example.com is no longer registered` | Critical | The registry has no record of a domain that had registry data before. | Always on |
| `Registrar changed for example.com` | Low | The registrar is different from the last lookup. | **Registry changes** |
| `Nameservers changed for example.com` | Low | The nameservers at the registry are different from the last lookup. | **Registry changes** |
| `DNSSEC keys changed for example.com` | Low | The DS records at the registry are different from the last lookup. | **Registry changes** |
The alerts go to the domain's [escalation paths](/alerting/escalation-paths). You cannot change the severity of a domain alert.
## Open alerts and how they resolve
Each kind of alert is separate. One open alert does not stop another kind from firing, and Spectate resolves each kind on its own:
| Alert | Open at a time | Resolves when |
|---|---|---|
| Expires soon or has expired | One of the two | A lookup shows an expiry date outside the threshold, for example after a renewal. Also when you lower **Warn before expiry** below the days left. |
| No longer registered | One | A lookup finds the domain at the registry again. |
| Registrar changed | One | A member resolves it on the alert page. |
| Nameservers changed | One | A member resolves it on the alert page. |
| DNSSEC keys changed | One | A member resolves it on the alert page. |
For example, a domain can have an open "Nameservers changed" alert and an open "expires soon" alert at the same time. A renewal resolves the "expires soon" alert. The "Nameservers changed" alert stays open until a member resolves it.
While a change alert is open, a new change of the same kind does not fire a second alert.
## Expiry
Spectate compares the expiry date from the registry with the threshold of the domain. The threshold is 30 days by default. You can set 1 to 365 days.
- If the domain expires within the threshold, Spectate fires the "expires soon" alert.
- If the expiry date is in the past, Spectate fires the "has expired" alert.
- When the registry shows a new expiry date after a renewal, Spectate resolves the alert at the next lookup.
The description of the alert gives the days left and the expiry date, for example "Expires in 12 days, on 9 Nov 2026." The title does not change from day to day. While the domain stays in the same state, the alert stays open, and Spectate updates the days left in the description. It does not fire a new alert or escalate again.
If an "expires soon" domain expires, Spectate resolves the "expires soon" alert and fires the "has expired" alert. The new alert goes through the escalation paths again.
Some registries do not publish expiry dates, for example `.de`, `.nl` and `.eu`. Spectate cannot fire expiry alerts for those domains. Renew them at your registrar on time.
## Lapsed registrations
If a domain had registry data and the registry then has no record of it, Spectate fires a critical alert. This usually means that the domain expired and the registry deleted it, or that it moved. An open "has expired" alert stays open next to it. When a lookup finds the domain again, Spectate resolves the "no longer registered" alert.
If the registry has no record of a domain that you added recently, Spectate does not fire an alert. The dashboard shows **Not registered**. Check the spelling, and use the registered domain instead of a subdomain.
## Registry changes
A change of registrar, nameservers or DNSSEC keys can be planned work, such as a transfer. It can also be a sign of a hijacked domain. Spectate fires a low severity alert for each change.
Spectate compares the records in a normalised form. A different order of records or fields, upper and lower case, and a trailing dot do not count as a change.
Spectate does not fire a change alert in these cases:
- It is the first lookup of the domain.
- The registry data came from another source than the last time, for example WHOIS instead of RDAP.
- **Registry changes** is off for the domain.
## Change the alert settings
Owners, managers and admins can change the settings.
1. Open the domain and go to **Settings**.
2. Under **Alerting**, find **Domain expires soon**.
3. In **Warn before expiry**, type the number of days, from 1 to 365.
4. Turn **Registry changes** on or off.
5. Select **Save changes**.
In the [public API](/api-reference/domains), the settings are `expiry_threshold_days` and `alert_on_registry_changes`.
## What domain monitoring does not check
Domain monitoring reads the registry only. It does not query DNS records or your nameservers. To alert on DNS records, such as A, MX or TXT records, add a [DNS monitor](/monitors/dns). To alert on TLS certificates, see [certificates](/monitors/certificates).
---
## Document: Webhooks
The request a Spectate webhook channel sends: headers, JSON payloads for fired, resolved and test events, retries, timeouts and URL rules.
URL: /alerting/webhooks
# Webhooks
A **webhook channel** sends each alert notification as a JSON `POST` request to a URL that you choose. Use it to connect Spectate to your own tools, for example a chat bot or a ticket system. This page describes the request, the payloads and the delivery rules. To receive alerts from other tools in Spectate, use an [alert source](/alerting/alert-sources) instead.
## Add a webhook channel
1. In the dashboard, select **Alerting**.
2. Select **New channel**.
3. Under **Integration**, select **Webhook**.
4. Enter a **Name** and the **Webhook URL**.
5. To send headers, select **Add header** and enter a name and a value.
6. Select **Create channel**.
7. Add the channel to an [escalation path](/alerting/escalation-paths) with a **Notify channel** step.
With the [public API](/api-reference/channels), send `type: "webhook"` and a `webhook` object with `url` and up to 20 `headers`. The URL and the header values are write-only. The API never returns them.
## The request
```http
POST /spectate HTTP/1.1
Host: hooks.example.com
Content-Type: application/json
User-Agent: Spectate/2.0
Authorization: Bearer YOUR_SECRET
{"event": "alert.fired", "alert": {...}, "chart_url": "..."}
```
| Part | Value |
|---|---|
| Method | `POST` |
| Body | JSON, UTF-8 |
| `Content-Type` | `application/json` |
| `User-Agent` | `Spectate/2.0` |
| Your headers | Each header that you added to the channel |
Spectate does not sign webhook requests. To make sure that a request comes from Spectate, add a secret header to the channel, for example `Authorization: Bearer YOUR_SECRET`, and check it in your receiver. Use an `https://` URL so that the secret is encrypted in transit.
You cannot set the headers `Connection`, `Content-Length`, `Host` and `Transfer-Encoding`.
## Events
| `event` | Sent when |
|---|---|
| `alert.fired` | An escalation step sends a firing alert to the channel. |
| `alert.resolved` | An alert that the channel got resolves, on its own or by hand. |
| `channel.test` | Someone sends a test from the dashboard or the API. |
Spectate does not send a webhook when someone acknowledges an alert. A channel gets one `alert.fired` for each escalation step that notifies it, and at most one `alert.resolved` per alert.
### `alert.fired`
```json
{
"event": "alert.fired",
"alert": {
"uuid": "9d3f6c2a-6a1e-4f8e-9b7d-2c5e8f1a4b30",
"title": "Checkout API is down",
"severity": "critical",
"source_type": "uptime",
"fired_at": "2026-10-27T09:14:03+00:00",
"metadata": {
"monitor_url": "https://api.example.com/health",
"protocol": "https",
"error": "Connection timed out after 30 seconds",
"location": "eu",
"checked_at": "2026-10-27T09:14:01+00:00"
}
},
"chart_url": "https://api.spectate.net/alert-charts/9d3f6c2a-6a1e-4f8e-9b7d-2c5e8f1a4b30/fired.png?expires=1764407643&signature=..."
}
```
### `alert.resolved`
```json
{
"event": "alert.resolved",
"alert": {
"uuid": "9d3f6c2a-6a1e-4f8e-9b7d-2c5e8f1a4b30",
"title": "Checkout API is down",
"severity": "critical",
"source_type": "uptime",
"fired_at": "2026-10-27T09:14:03+00:00",
"resolved_at": "2026-10-27T09:31:47+00:00",
"metadata": {
"monitor_url": "https://api.example.com/health",
"protocol": "https",
"error": "Connection timed out after 30 seconds",
"location": "eu",
"checked_at": "2026-10-27T09:14:01+00:00"
}
},
"chart_url": "https://api.spectate.net/alert-charts/9d3f6c2a-6a1e-4f8e-9b7d-2c5e8f1a4b30/resolved.png?expires=1764408707&signature=..."
}
```
### `channel.test`
```json
{
"event": "channel.test",
"title": "Test notification for Ops webhook",
"message": "200 OK - Test notification sent successfully"
}
```
### Fields
| Field | Type | Description |
|---|---|---|
| `event` | string | `alert.fired`, `alert.resolved` or `channel.test`. |
| `alert.uuid` | string | The alert ID. It is the same in both events of one alert, in the dashboard URL `/alerts/{uuid}` and in the [public API](/api-reference/alerts). |
| `alert.title` | string | What is wrong, for example `Checkout API is down`. |
| `alert.severity` | string | `critical`, `high`, `medium` or `low`. |
| `alert.source_type` | string | `uptime`, `performance`, `certificate`, `dns`, `host_metric`, `domain`, `status_page` or `external`. See [alerts](/alerting/alerts). |
| `alert.fired_at` | string | When the alert fired, ISO 8601. |
| `alert.resolved_at` | string | When the alert resolved, ISO 8601. Only in `alert.resolved`. |
| `alert.metadata` | object or `null` | Details from the source. The keys depend on the source type. |
| `chart_url` | string or `null` | A PNG chart of the data around the alert. `null` when there is no chart. |
The keys in `alert.metadata` are not fixed. For an uptime alert they include `monitor_url`, `protocol`, `error`, `status_code`, `location`, `response_time` and `checked_at`, when the check had them. For an alert from an [alert source](/alerting/alert-sources), they include `provider`, `labels`, `links` and the metadata that the tool sent. Read the keys that you need, and ignore keys that you do not know.
The `chart_url` link is signed and works for 30 days. Uptime, performance and host metric alerts can have a chart.
## Delivery
| Rule | Value |
|---|---|
| Connect timeout | 2 seconds |
| Request timeout | 5 seconds |
| Success | Any `2xx` response |
| Redirects | Not followed. A `3xx` response is a failure that Spectate does not retry. |
| Tries | 3: at once, after 30 seconds, and 2 minutes after that |
| No retry | HTTP `401`, `403`, `404` and `410` |
Answer fast, with a `2xx` status, and do slow work after you answer. A request that takes longer than 5 seconds fails, even if your receiver processed it. After a timeout, Spectate sends the same event again. Use `event` and `alert.uuid` to find repeated deliveries.
A webhook that keeps failing is disabled automatically. See [when Spectate disables a channel](/alerting/channels#when-spectate-disables-a-channel).
## URL rules
Spectate sends webhooks only to public addresses. A URL must meet these rules:
- The scheme is `http` or `https`.
- The URL has no user name or password in it.
- The host is not `localhost`, and does not end in `.localhost` or `.internal`.
- Every IPv4 and IPv6 address of the host is public. Private, reserved and carrier-grade NAT (`100.64.0.0/10`) addresses are refused, as are IPv4-mapped and NAT64 IPv6 addresses.
Spectate checks the URL when you save the channel and again before each request. The request goes to the IP address that Spectate checked. A DNS change after the check cannot send it to another address. If the URL redirects, use the final URL in the channel.
## Related
- [Channels](/alerting/channels): all channel types, tests and auto-disable.
- [Alert sources](/alerting/alert-sources): send alerts from your tools into Spectate.
---
## Document: Telegram and phone
Get Spectate alerts in Telegram, by SMS and by voice call, acknowledge them with a button or by pressing 1, and buy SMS and call credits.
URL: /alerting/telegram-and-phone
# Telegram and phone
Spectate can send alerts to Telegram chats, as text messages (SMS) and as voice calls. In Telegram you acknowledge an alert with a button. In a voice call you press 1. SMS and calls use notification credits. Telegram is free.
## Telegram
The Spectate Telegram bot is `@SpectateAlertBot`. It posts alerts to private chats and to groups.
### Connect a Telegram chat
1. In the dashboard, select **Alerting → New channel**.
2. Under **Integration**, select **Telegram**.
3. Optional: enter a **Name**. The default is `Telegram: CHAT NAME`.
4. Select **Connect Telegram**.
5. Select **Open Telegram** for a private chat, or **Add to a group** for a group.
6. In Telegram, select **Start**, or select the group.
You can also send the command that the dashboard shows, `/start YOUR_LINK_TOKEN`, to the bot. The link works one time and expires after 30 minutes. When the bot gets the link, it creates the channel and replies with a confirmation. The dashboard closes the dialog. Then add the channel to an [escalation path](/alerting/escalation-paths).
To move a channel to another chat, open the channel, select **Edit**, and select **Connect a different chat**. If Telegram upgrades a group to a supergroup, Spectate moves the channel to the new chat by itself.
### Telegram messages
An alert message shows the severity and title, the description, the resource, the source, the URL and the time the alert fired. It has two buttons: **Acknowledge** and **View in Spectate**.
When someone acknowledges or resolves the alert, anywhere, Spectate edits the message. The status line changes to, for example, "Acknowledged by Ada" or "Resolved after 14m". When the alert resolves, the bot also replies to the alert message.
### Link your Telegram account
The **Acknowledge** button acts as the Spectate member whose Telegram account pressed it. Link your Telegram account before you use it:
1. In the dashboard, open **Account → Profile**.
2. Under **Telegram**, select **Link Telegram**.
3. In the private chat with the bot, select **Start**.
One Telegram account links to one Spectate account. If you connect a private chat as a channel, Spectate also links your Telegram account to you, unless one of the two is already linked. To remove the link, select **Unlink** under **Account → Profile → Telegram**.
If a Telegram user without a link presses **Acknowledge**, Telegram shows a message that explains how to link. The alert stays unacknowledged. The linked member's role decides: members, admins, managers and owners can acknowledge, billing members cannot.
## SMS
An SMS channel sends a text message to one phone number. Enter the number in international format, for example `+31612345678`.
The message is the alert title and the source, for example `Checkout API is down (source: Uptime)`. You cannot reply to acknowledge. Acknowledge the alert in the dashboard, in Slack or in Telegram.
Each SMS uses 1 credit. The resolved notification is also an SMS.
## Voice calls
A voice channel calls one phone number. Enter the number in international format.
The call goes like this:
1. Spectate says: "This is Spectate. Critical severity alert: TITLE. Press 1 to acknowledge the alert."
2. Spectate waits for a key, says the alert again, and waits again.
3. If you press 1, Spectate acknowledges the alert. It says that the escalation has stopped.
4. If you press no key, Spectate says that the alert was not acknowledged, and ends the call.
If the alert is already acknowledged or resolved when you press 1, Spectate tells you. A call can acknowledge its alert for 2 hours after Spectate places it.
Each call uses 2 credits. A voice channel gets the resolved notification as an SMS, which uses 1 credit.
### Who acknowledged
| Call from | Spectate records |
|---|---|
| A voice channel | "phone call to CHANNEL NAME", for example "Acknowledged by phone call to Ops line" |
| An on-call page | The member who was paged. If the member's role cannot acknowledge alerts, the call says so. |
For on-call pages by SMS or voice call, see [how Spectate pages a member](/alerting/on-call#how-spectate-pages-a-member).
## Credits
SMS and voice calls use notification credits:
- One SMS: 1 credit per recipient.
- One voice call: 2 credits per number.
- A test SMS or test call uses credits too.
Spectate takes the credits only after the SMS or call went out. A retry does not use credits again.
Each paid plan includes credits every month: 10 on Starter, 50 on Team and 200 on Business. The trial includes no monthly credits. Buy more in packs of 100 under **Billing → SMS and call credits**. Bought credits never expire. Owners and billing members can buy credits.
:::caution
Without credits, Spectate sends no SMS and places no calls. Escalation continues with the other steps, and on-call pages go out by email only.
:::
See [channels](/alerting/channels#sms-and-call-credits) for the details and [pricing](https://spectate.net/pricing) for the price of a pack.
---
## Document: Slack
Connect the Spectate Slack app to act on alerts, run incidents and status pages with /spectate, and handle on-call shifts, pages and cover requests in Slack.
URL: /alerting/slack
# Slack
The Spectate Slack app connects one Slack workspace to your Spectate team. Alerts arrive in Slack with **Acknowledge** and **Resolve** buttons, and you can declare, update and resolve incidents with the `/spectate` command. Each incident can get its own Slack channel, which Spectate keeps in sync with the dashboard. On-call members get pages, shift reminders and cover requests as direct messages from the app.
## Connect Slack
Owners, managers and admins can connect Slack.
1. In the dashboard, select **Integrations**.
2. Under **Slack**, select **Add to Slack**.
3. In Slack, select the workspace and allow the app.
One Slack workspace connects to one Spectate team. After you connect, choose the channels: an alert channel for alerts, and the settings for incidents.
If **Integrations → Slack** shows **Needs reconnect**, the workspace was connected before some features existed. Select **Reconnect** to give the app the new Slack permissions. Alert channels continue to post until you do.
## Get alerts in a Slack channel
1. Select **Alerting → New channel**.
2. Under **Integration**, select **Slack**.
3. Enter a **Name**.
4. Under **Slack channel**, select the channel.
5. Select **Create channel**.
6. Add the channel to an [escalation path](/alerting/escalation-paths) with a **Notify channel** step.
The list shows public channels, and private channels that the Spectate app is a member of. To use a private channel, invite the app to it in Slack first.
### Alert messages
An alert message has the colour of the severity, the resource and the reason, and a chart when there is data. It has these buttons:
| Button | What it does |
|---|---|
| **Acknowledge** | Acknowledges the alert after you confirm. The escalation stops. |
| **Declare incident** | Opens the declare form for the alert. If the alert already has an open incident, Spectate links to it instead. |
| **Resolve** | Resolves the alert after you confirm. Spectate sends the resolved notifications. If the problem is still there, the alert fires again. |
| **View in Spectate** | Opens the alert in the dashboard. |
Spectate updates the message in place when someone acknowledges or resolves the alert, in Slack or anywhere else. The **Acknowledge** button goes away, and a line such as "Acknowledged by Ada" shows who did it. When the alert resolves, Spectate also posts a reply in the message's thread, which also shows in the channel.
## Who is acting in Slack
Everything you do in Slack, Spectate does as your Spectate account, with your role's permissions. Spectate links your Slack user to your Spectate account the first time you use the app. The email address of your Slack profile must be the verified email address of a member of the team.
If Spectate cannot find a match, it shows a message only to you, and nothing happens. Sign in to Spectate with the same email address as your Slack profile, or ask an admin to invite you. A member who leaves the team loses the link.
## Slash commands
`/spectate` has two aliases: `/inc` and `/incident`. In an incident channel, the commands act on that incident. In other channels, Spectate first asks you to pick an open incident.
| Command | What it does |
|---|---|
| `/spectate` or `/spectate help` | Shows the commands. In an incident channel, also the incident's buttons. |
| `/spectate declare [title]` | Opens the form to declare an incident, with the title filled in. |
| `/spectate update` | Posts an update and can change the incident's status. |
| `/spectate status-page` | Publishes an update to a status page. Outside an incident channel, it can also start or update a status page incident without a Spectate incident. See [status pages from Slack](#status-pages-from-slack). |
| `/spectate ack` | Acknowledges the incident. |
| `/spectate resolve` | Resolves the incident, with an optional closing message. |
| `/spectate roles` | Assigns the commander and the communications lead. |
| `/spectate lead` or `/spectate lead me` | Makes you the commander. |
| `/spectate rename [title]` | Changes the title. |
| `/spectate summary [text]` | Changes the summary. |
| `/spectate sev [level]` | Changes the severity to `critical`, `high`, `medium` or `low`. |
| `/spectate list` | Lists the open incidents. Only you see the list. |
| `/spectate oncall [schedule]` | Shows who is on call now and next for each schedule, and your next shift. Add part of a schedule name to show only matching schedules. Only you see the answer. |
| `/spectate cover` | Asks the others on an on-call schedule to cover one of your shifts. See [cover requests](#cover-requests). |
In an incident channel, `rename`, `summary`, `sev` and `lead` with a value change the incident at once. Without a value, or in another channel, they open a form.
You can also use the **Declare incident** shortcut. On a message, the shortcut makes the message the incident summary, with a link back to the message.
## Incident channels
When **Create a channel for each incident** is on, every new incident gets its own Slack channel. This includes incidents declared in Slack, in the dashboard, with the API, and by an escalation path. In the Slack declare form, you can clear **Create a channel for this incident** for one incident.
The channel name is the prefix, the incident number and the title, for example `inc-42-checkout-errors`. Spectate pins a header message in the channel. The header shows the reference, title, severity, status and commander, with these buttons:
- **Post update**
- **Status page**
- **Roles**
- **Acknowledge**, until someone acknowledges the incident
- **Resolve**
- **View in Spectate**
Spectate posts updates, status and severity changes, role changes and status page updates into the channel, from Slack and from the dashboard. If an incident has no channel, select **Create Slack channel** on the incident page.
### Pin messages to the timeline
To add a message from the incident channel to the timeline, react to it with an emoji. Use the pushpin (`:pushpin:`), round pushpin (`:round_pushpin:`) or bookmark (`:bookmark:`). Spectate adds the text, the author and a link to the message. The timeline shows that you pinned it. Spectate adds each message once, and only for members who can update the incident.
### Nudges
If an open incident gets no update for 30 minutes, Spectate posts a reminder in its channel. The reminder has **Post update** and **Status page** buttons. When someone posts an update or resolves the incident, Spectate removes the reminder. Change the time, or turn nudges off, with **Nudge quiet incidents** in the [settings](#settings).
## Status pages from Slack
In an incident channel, `/spectate status-page` publishes the incident to a status page. In other channels, it asks what to publish:
- **New status page incident** starts a public incident without a Spectate incident. Enter a title, a status, the impact on each component and the public message.
- An open status page incident: post its next update, or resolve it.
- An open Spectate incident: publish it, the same as in its channel.
`/spectate status-page new [title]` opens the form for a new status page incident at once. Both forms can backdate the update with **Happened at**. **Notify subscribers by email** is on by default. Only owners, managers and admins can publish, and Spectate only offers status pages that you can publish to. See [status page incidents](/status-pages/incidents).
## On-call in Slack
For on-call, Spectate sends direct messages from the app. You find them under the Spectate app in Slack. Spectate finds your Slack account by the verified email address of your Spectate account.
### Pages
An escalation path can page you as the person [on call](/alerting/on-call). Spectate then also sends the alert as a direct message, with **Acknowledge**, **Declare incident** and **Resolve**. The message updates when someone acknowledges or resolves the alert. Slack pages do not use credits. To turn them off, clear **Also page me in Slack** under **Your on-call**.
### Cover requests
When you cannot do a shift, ask the others on the schedule to cover it.
1. Enter `/spectate cover`.
2. Under **Shift**, select one of your shifts of the next 4 weeks.
3. Optional: enter **From** and **Until** to ask for part of the shift.
4. Optional: enter a **Note**.
5. Select **Ask**.
Spectate asks every other member of the schedule's rotations. Each one gets a direct message with **Accept** and **Can't cover**. The first person to accept gets an override for the whole window, and Spectate updates all the messages. You get the answers in a thread under your own message, which has **Send reminder** and **Cancel request**. Members that Spectate cannot find in Slack get an email instead. See [cover requests](/alerting/on-call#ask-for-cover) for the full rules.
### Shift messages and handovers
Before each of your shifts, Spectate sends a reminder with **Request cover** and **View schedule**. It also sends a message when your shift starts and when it ends. Choose the time of the reminder, or turn the messages off, with **Shift messages in Slack** under **Your on-call**. The default is **Also 1 hour before**.
A schedule can also announce each handover in a channel. The message mentions who is on call now, until when, and who they take over from. If there is no handoff in the next 90 days, the messages say so. Select the channel under **Slack → Handover channel** on the schedule page.
### On-call user groups
Spectate can create a Slack user group for a schedule and keep it up to date. Mention the group to reach the right people.
1. Open the schedule on the **On-call** page.
2. Under **Slack**, select **Keep an on-call user group**.
3. Enter the **Handle**. Spectate proposes the schedule name with `-oncall`, for example `platform-oncall`.
4. Under **Keep it set to**, select **Whoever is on call** or **Everyone on the schedule**.
5. Select **Save**.
Spectate creates the group in Slack. If a group with this handle exists, Spectate uses that group. If you change the handle later, Spectate renames the group. If you clear **Keep an on-call user group**, Spectate disables the group in Slack.
Spectate updates the group at each handover and when the rotations change. Slack does not allow an empty group. When nobody is on call, Spectate disables the group, and enables it again at the next handover. Members that Spectate cannot find in Slack are not added.
:::caution
By default, Slack only lets workspace admins create and change user groups. A Slack admin must let everyone manage user groups, in the workspace settings under **Permissions → User Groups**. Until then, the schedule page shows that Slack refused the group.
:::
## The Spectate tab
Open the Spectate app in Slack and select **Home**. The tab shows:
- **Declare incident**, **Request cover** and **Open Spectate**.
- **Your on-call**: your shifts of the next 2 weeks, each with **Request cover**.
- **Cover requests**: requests that you can answer, and your own open requests.
- **Open incidents**: up to 10, with **Post update**.
The tab updates after you use one of its buttons.
## Settings
Find the settings under **Integrations → Slack**. Owners, managers and admins can change them.
| Setting | Default | What it does |
|---|---|---|
| **Announcements channel** | **No announcements** | Spectate announces each new incident in this channel, and keeps the announcement up to date. |
| **Create a channel for each incident** | On | Each new incident gets its own Slack channel. |
| **Channel prefix** | `inc` | The start of incident channel names. Lowercase letters, numbers, `-` and `_` only. |
| **Nudge quiet incidents** | **After 30 minutes** | Posts a reminder in an incident channel when nobody posted an update for this long. **Never** turns nudges off. |
## Disconnect Slack
1. Select **Integrations**.
2. Under **Slack**, select **Disconnect**.
3. Select **Disconnect** to confirm.
Spectate disables the alert channels that post through the workspace. If you connect Slack again, they turn on again. Existing incident channels stay in Slack, but Spectate stops posting to them. If someone removes the app in Slack, Spectate disables the alert channels and sends an email, the same as for a [disabled channel](/alerting/channels#when-spectate-disables-a-channel).
## Related
- [Incidents](/incidents/introduction): declare and resolve incidents.
- [Updates and roles](/incidents/updates-and-roles): what Spectate mirrors into the incident channel.
- [Alerts](/alerting/alerts): acknowledge and resolve alerts.
- [On-call](/alerting/on-call): schedules, overrides and cover requests.
---
## Document: On-call
Set up on-call schedules with rotations, overrides and cover requests, see who is on call now, and page that person from an escalation path.
URL: /alerting/on-call
# On-call
An **on-call schedule** decides which team member is on call at each moment. A schedule has rotation layers that hand off between members, overrides for swaps and holidays, and cover requests when someone cannot do a shift. A **Notify on-call** step in an [escalation path](/alerting/escalation-paths) pages whoever is on call when the step runs. On-call schedules are part of the Team and Business plans.
## Create a schedule
1. In the dashboard, select **Alerting → On-call**.
2. Select **New schedule**.
3. Enter a **Name**, for example `Platform on-call`. The **Description** is optional.
4. Select the **Time zone**. Handoffs and set hours use this time zone.
5. Select **Create schedule**.
A new schedule has nobody on call. Add a rotation next.
## Add a rotation
A **rotation** is a layer of the schedule. It hands off between its participants in order, at a fixed interval.
1. Open the schedule.
2. Select **Add rotation**.
3. Enter a **Name**, for example `Primary`.
4. Under **Participants**, add team members in the order of their turns.
5. Under **Hand off every**, enter a number and select **Hours**, **Days** or **Weeks**.
6. Enter the date of the **First handoff** and the **Handoff time**.
7. Select **Add rotation**.
The first participant's turn starts at the first handoff. After each interval, the next participant takes over. After the last participant, the first one starts again.
| Setting | API field | Values |
|---|---|---|
| **Participants** | `participants` | 1 to 50 team members, in order |
| **Hand off every** | `shift_length`, `shift_unit` | 1 to 720 `hours`, 1 to 90 `days`, or 1 to 12 `weeks` |
| **First handoff** | `start_date` | A date, `YYYY-MM-DD`, in the schedule's time zone |
| **Handoff time** | `handoff_time` | A time, `HH:MM`, in the schedule's time zone |
| **Only cover set hours** | `restrictions` | Optional days and a time window, see below |
`days` and `weeks` follow the calendar in the schedule's time zone. The handoff stays at the same clock time when daylight saving time starts or ends. `hours` are exact hours, so a 12-hour shift is always 12 hours long.
### Cover set hours only
Select **Only cover set hours** to limit a rotation to some days and times, for example weekdays from 09:00 to 17:00. Outside these hours, the layers below take over, or nobody is on call. If **Until** is earlier than **From**, the window runs overnight.
## Layers
A schedule can have more than one rotation. The dashboard shows them under **Rotation layers**. Where layers overlap, the top layer wins. Use this to combine a business-hours rotation on top of a round-the-clock rotation.
You can change the order of the layers. Spectate skips a participant who is no longer a member of the team.
## Add an override
An **override** puts one member on call for a period, over all layers. Use it for swaps, sick days and holidays.
1. Open the schedule.
2. Select **Override**.
3. Under **Who covers**, select the team member.
4. Enter **From** and **Until** in the schedule's time zone.
5. Optional: enter a **Note**, for example `Swapping with Bob for the release`.
6. Select **Add override**.
An override is at most 90 days long. Where overrides overlap, the newest override wins. The **Overrides** panel shows upcoming and active overrides.
## Ask for cover
A **cover request** asks the other members of a schedule to take a shift of yours. The first member to accept gets an override for the whole window. Nothing changes on the schedule until someone accepts.
1. Select **Alerting → On-call**.
2. Under **Your on-call**, select **Request cover** next to the shift.
3. Change **From** and **Until** if you need cover for part of the shift only.
4. Optional: enter a **Note**, for example the reason.
5. Select **Ask for cover**.
In Slack, use `/spectate cover`. See [cover requests in Slack](/alerting/slack#cover-requests).
Spectate asks every other member of the schedule's rotations. If the team [connected Slack](/alerting/slack) and Spectate finds the member in Slack, the member gets a direct message with **Accept** and **Can't cover**. Other members get an email. They answer under **Your on-call**, or on the schedule page under **Waiting for cover**.
These rules apply:
- You must be on call for all of the window. A window that already started covers the rest of it.
- A window is at most 90 days long. You can have one open request for the same time.
- Any member of the team can accept, also a member that Spectate did not ask. You cannot accept your own request.
- If someone accepts, Spectate tells you. If everyone says they cannot, Spectate tells you too, and the request stays open. A member who said no can still accept.
- **Send reminder** asks again the members who did not answer, at most every 30 minutes.
- If nobody accepts before the window ends, the request expires. You stay on call.
- You can cancel your own request. Owners, managers and admins can cancel any request.
The public API and the MCP server do not have cover requests yet.
## See who is on call
The schedule page shows **On call now**, the **Next handoff** and a **Timeline** of 1 week or 2 weeks. The timeline has a row for each layer, a row for overrides, and the **Final schedule** row. The **Final schedule** is who Spectate pages.
The **On-call** page lists all schedules with the person on call now. **Your on-call** shows your own shifts for the next 14 days.
With the [public API](/api-reference/on-call), `GET /v1/on-call-schedules/{schedule}/now` returns who is on call, and `GET /v1/on-call-schedules/{schedule}/timeline` returns the shifts for a period.
## Page the person on call
1. Open an [escalation path](/alerting/escalation-paths).
2. Add a **Notify on-call** step.
3. Under **Schedule**, select the on-call schedule.
4. Select **Save flow**.
Spectate finds the person on call when the step runs, not when the alert fires. If nobody is on call, Spectate skips the step and runs the next step at once. The alert's **Escalation** panel shows who Spectate paged, or why it skipped the step.
The schedule page shows the escalation paths that use the schedule under **Used by**.
### How Spectate pages a member
Spectate always sends an email to the member on call. If the team [connected Slack](/alerting/slack), Spectate also sends the alert as a direct message in Slack, with **Acknowledge** and **Resolve**. Slack pages do not use credits. To turn them off, clear **Also page me in Slack** under **On-call contact**.
Spectate also sends an SMS or calls the member if these are true:
- The member added a phone number under **On-call contact**.
- The team has [SMS and call credits](/alerting/channels#sms-and-call-credits).
Each member sets this in **Account → Profile → On-call contact**, or under **Your on-call** on the **On-call** page:
| **Page me by** | What happens | Credits |
|---|---|---|
| **Text** | Spectate sends the alert by SMS. Acknowledge it in Spectate to stop the escalation. | 1 |
| **Voice call** | Spectate calls and reads the alert. Press 1 to acknowledge it as you and stop the escalation. | 2 |
When the alert resolves, Spectate sends the paged member an email only, and updates the Slack message. See [Telegram and phone](/alerting/telegram-and-phone) for the voice call.
## Shifts in Slack
If the team connected Slack, Spectate sends each member a reminder before a shift, and a message when the shift starts and ends. The reminder has a **Request cover** button. Each member chooses with **Shift messages in Slack** under **On-call contact**:
| Choice | Messages |
|---|---|
| **Off** | None |
| **When a shift starts and ends** | At the start and at the end |
| **Also 15 minutes before** | A reminder 15 minutes before, then at the start and at the end |
| **Also 1 hour before** (default) | A reminder 1 hour before, then at the start and at the end |
| **Also 1 day before** | A reminder 1 day before, then at the start and at the end |
On the schedule page, the **Slack** panel has two more options:
- **Handover channel** announces each handover in a Slack channel.
- **Keep an on-call user group** creates a Slack user group, for example `@platform-oncall`. Spectate keeps it set to whoever is on call, or to everyone on the schedule.
See [on-call in Slack](/alerting/slack#on-call-in-slack).
## Who can do what
| Action | Owner, manager, admin | Member |
|---|---|---|
| See schedules | Yes | Yes |
| Create and change schedules and rotations | Yes | No |
| Delete schedules | Yes | No |
| Add an override | For any member | For themselves only |
| Remove an override | Any override | Overrides for themselves, or that they added |
| Ask for cover of their own shift | Yes | Yes |
| Accept a cover request | Yes, not their own | Yes, not their own |
| Cancel a cover request | Any request | Their own requests |
| Change the schedule's **Slack** settings | Yes | No |
## Plans
On-call schedules and **Notify on-call** steps are part of the Team and Business plans, and of the trial. The Starter plan does not include them. See [plans and billing](/account/plans-and-billing) and [pricing](https://spectate.net/pricing).
---
## Document: Escalation paths
Decide who gets notified about an alert, in which order and after which delay, with branches, working hours and on-call steps.
URL: /alerting/escalation-paths
# Escalation paths
An **escalation path** decides who Spectate notifies about an alert, in which order, and when it opens an incident. A path is a list of steps. For example: notify the Slack channel, wait 5 minutes, page the person on call, then create an incident. Escalation stops when someone acknowledges or resolves the alert.
## Which paths an alert uses
When an alert fires, Spectate looks for escalation paths in this order and uses the first match:
1. The paths of the resource itself. These are the monitor, host, domain, status page or alert source that fired the alert.
2. The paths of the resource's [project](/account/projects).
3. The team default path.
If the resource has more than one path, every enabled path runs, each on its own. A disabled path does not run. If a resource has only disabled paths, nobody gets the alert, because Spectate does not fall back to the project or the team default.
If no path matches, the alert fires but nobody gets a notification. The dashboard warns about this in the **Alerting** section of the resource settings.
### Attach a path to a resource
Each monitor, host, domain, status page and alert source has an **Alerting** section in its settings.
1. Open the settings of the resource.
2. In the **Alerting** section, select **Specific paths**.
3. Select one or more escalation paths.
4. Save the settings.
**Default routing** uses the project paths, or else the team default path. Projects have the same choice of paths.
## Create an escalation path
1. In the dashboard, select **Alerting**.
2. Select **New path**.
3. Enter a **Name**. The **Description** is optional.
4. To make this the fallback for resources without a path, select **Use as team default**.
5. Select **Create and open builder**.
6. Select a step to edit it, or select **+** to add a step.
7. Select **Save flow**.
A new path starts with the alert trigger and one notify step for your first channel. A team has one default path. If you make a path the team default, the previous default path stops being the default.
## Steps
| Step in the builder | `type` in the API | What it does |
|---|---|---|
| **Notify channel** | `notify_channel` | Sends the alert to a [channel](/alerting/channels): email, Slack, a webhook, SMS and more. |
| **Notify on-call** | `notify_on_call` | Pages the person who is on call in an [on-call schedule](/alerting/on-call) at the time the step runs. |
| **Create incident** | `create_incident` | Declares an [incident](/incidents/introduction) with the alert's title and severity. |
| **Branch** | `branch` | Splits the path. Alerts that meet all conditions continue on the **Yes** side, other alerts on the **No** side. |
Each step runs at most one time per alert. A **Create incident** step does not open a second incident for an alert that already has one.
### Delays
Each step except a branch has a **Wait before this step** setting:
| Option | `delay_until` | Behaviour |
|---|---|---|
| **Time** | `null` | Waits a number of minutes, 0 to 1440, after the step before it. The first step waits from the moment the alert fires. The default is 0. |
| **Hours begin** | `working_hours_start` | Outside working hours, waits until they begin. During working hours, the step runs at once. |
| **Hours end** | `working_hours_end` | During working hours, waits until they end. Outside working hours, the step runs at once. |
If a step reaches nobody, Spectate logs it as skipped and runs the next step at once, without its delay. A step reaches nobody when its channel is disabled or deleted, or when nobody is on call. A step that waits for working hours still waits.
### When escalation stops
Spectate checks the alert before each step. If someone acknowledged the alert, or the alert resolved, the remaining steps do not run. See [alerts](/alerting/alerts) for the places where you can acknowledge an alert.
## Branches
A branch has 1 to 10 conditions. The alert takes the **Yes** side only if all conditions hold. Spectate decides the branch when the escalation reaches it, not when the alert fires. A side without steps ends the escalation.
| Field | Operators | Values |
|---|---|---|
| Severity (`severity`) | is one of (`is_one_of`), is not one of (`is_not_one_of`) | `critical`, `high`, `medium`, `low` |
| Working hours (`working_hours`) | within (`within`), outside (`outside`) | None. Spectate uses the path's working hours. |
| Source (`source`) | is one of, is not one of | An alert kind, or a specific external tool. See the list below. |
| Label (`label`) | is one of, is not one of, is set (`exists`), is not set (`not_exists`) | The value of a label that an alert source sent, for example `env` is `production`. |
Source values:
- Alert kinds: `uptime`, `performance`, `certificate`, `dns`, `domain`, `host_metric`, `status_page`, and `external` for any external tool.
- External tools: `external:alertmanager`, `external:grafana`, `external:sentry`, `external:webhook`, `external:email`.
Labels come from [alert sources](/alerting/alert-sources) that send labels: Prometheus Alertmanager and Grafana. An alert without the label does not match "is one of", and does match "is not one of".
## Working hours
Each path has its own working hours. Branches on working hours and the **Hours begin** and **Hours end** delays use them. The default is Monday to Friday, 09:00 to 17:00, in the team's time zone.
1. Open the path in the builder.
2. Open **Path settings**.
3. Under **Working hours**, select the days.
4. Enter **From** and **Until**, and select the **Time zone**.
5. Select **Save flow**.
If **Until** is earlier than **From**, the working hours run past midnight. They belong to the day on which they start.
## Changes apply to new alerts only
When an alert fires, Spectate takes a copy of the path's steps and working hours. The alert runs from that copy until it stops. If you change or delete the path, alerts that already fired keep their copy. New alerts use the new version.
Spectate checks two things when a step runs, not when the alert fires:
- The channel. Spectate skips a channel that is disabled or deleted at that time.
- The person on call. A **Notify on-call** step pages whoever is on call when the step runs.
## Warnings
The dashboard and the API (`warnings`) show a warning when a path cannot reach everyone:
| Code | Meaning |
|---|---|
| `no_deliverable_steps` | Every notify step targets a disabled channel or a deleted schedule. Alerts on this path reach nobody. |
| `disabled_channels` | Some channels are disabled. Spectate skips their steps. |
| `missing_schedules` | An on-call step points to a deleted schedule. Spectate skips the step. |
Channels can be disabled automatically after repeated delivery failures. See [channels](/alerting/channels) for how to turn them on again.
## Plans and limits
| Limit | Value |
|---|---|
| Escalation paths on the Starter plan | 1, the team default path |
| Escalation paths on the Team and Business plans | No limit |
| **Notify on-call** steps | Team and Business plans |
| Steps per path | 99 |
| Conditions per branch | 10 |
| Values per condition | 20 |
| Delay per step | 0 to 1440 minutes |
See [plans and billing](/account/plans-and-billing) and [pricing](https://spectate.net/pricing).
Owners, managers and admins can create and change escalation paths. Members can see them. See [teams and roles](/account/teams-and-roles).
## Create a path with the API
The [escalation paths API](/api-reference/escalation-paths) shows a path as a list of steps. A `branch` is the last step of its list, and continues in its `then` and `else` lists. This path notifies a channel, then pages the person on call after 5 minutes for critical alerts. Other alerts go to a channel when working hours begin.
```json
{
"name": "Production",
"is_default": true,
"working_hours": {
"timezone": "Europe/Amsterdam",
"days": [1, 2, 3, 4, 5],
"start_time": "09:00",
"end_time": "17:00"
},
"steps": [
{ "type": "notify_channel", "channel_id": "CHANNEL_ID" },
{
"type": "branch",
"conditions": [
{ "field": "severity", "operator": "is_one_of", "values": ["critical"] }
],
"then": [
{ "type": "notify_on_call", "schedule_id": "SCHEDULE_ID", "delay_minutes": 5 }
],
"else": [
{ "type": "notify_channel", "channel_id": "OTHER_CHANNEL_ID", "delay_until": "working_hours_start" }
]
}
]
}
```
A path that you make with the API opens in the dashboard builder, and the other way around.
---
## Document: Channels
Add email, Slack, Discord, Microsoft Teams, Telegram, Pushover, webhook, SMS and voice channels, test them, and learn when Spectate disables a channel.
URL: /alerting/channels
# Channels
A **channel** is a destination for alert notifications, for example an email address, a Slack channel or a phone number. Each **Notify channel** step of an [escalation path](/alerting/escalation-paths) sends the alert to one channel. A channel does nothing until an escalation path uses it.
## Add a channel
1. In the dashboard, select **Alerting**.
2. Select **New channel**.
3. Under **Integration**, select the channel type.
4. Enter a **Name**, for example `Primary on-call`.
5. Fill in the fields for the type. The table below lists them.
6. Select **Create channel**.
Then add the channel to an escalation path with a **Notify channel** step. Owners, managers and admins can add, change and delete channels. Members can see them.
## Channel types
| Type | `type` | What you enter | What the alert looks like |
|---|---|---|---|
| Email | `email` | **Email address** | An email with the subject `[CRITICAL] Title`. It explains what failed, shows a chart when there is data, and has a **View alert** button. |
| Slack | `slack` | **Slack channel**, after you connect your Slack workspace | A message with the colour of the severity and the buttons **Acknowledge**, **Declare incident** and **View in Spectate**. See [Slack](/alerting/slack). |
| Discord | `discord` | **Discord webhook URL** | An embed in the colour of the severity, with a link to the alert, the cause and what to check, the facts, a chart and the times in the reader's own time zone. A resolved alert posts a green message with the duration. The message never mentions people or roles. |
| Microsoft Teams | `microsoft_teams` | **Microsoft Teams connector URL** | An adaptive card with the alert fields, a chart and an **Open alert** button. |
| Telegram | `telegram` | Select **Connect Telegram** and open the link | A message with an **Acknowledge** button. See [Telegram and phone](/alerting/telegram-and-phone). |
| Webhook | `webhook` | **Webhook URL** and optional headers | A JSON `POST` to your URL. See [webhooks](/alerting/webhooks). |
| Pushover | `pushover` | **User key**, **Application token** and **Priority** | A push notification with the chart attached. |
| SMS | `sms` | **Phone number** in international format, for example `+31612345678` | A text message: `Title (source: Uptime)`. Uses 1 credit. |
| Voice call | `voice` | **Phone number** in international format | A phone call that reads the alert. Press 1 to acknowledge. Uses 2 credits. See [Telegram and phone](/alerting/telegram-and-phone). |
Discord, Microsoft Teams and webhook URLs must resolve to a public address. Spectate checks this when you save the channel and again each time it sends. See [webhooks](/alerting/webhooks) for the rules.
### Pushover priority
**Priority** is a Pushover priority from `-2` to `2`:
| Option | Value |
|---|---|
| **Lowest** | `-2` |
| **Low** | `-1` |
| **Normal** (default) | `0` |
| **High** | `1` |
| **Emergency** | `2` |
With **Emergency**, Pushover repeats the notification every 30 seconds for up to 1 hour, until you acknowledge it in Pushover. This does not acknowledge the alert in Spectate.
## What an alert notification contains
Every notification about a firing alert has the alert title and these fields:
- Severity, source and resource.
- The time the alert fired.
- Fields for the source type, for example the monitor URL and the region for an uptime alert.
Uptime, performance and host metric alerts also get a chart of the data around the alert. Spectate leaves the chart out when there is no data.
When the alert resolves, Spectate sends a resolved notification to every enabled channel that got the alert. In Slack and Telegram, it is a reply to the alert message. A voice channel gets the resolved notification as an SMS, which uses 1 credit.
## Test a channel
Send a test to make sure that the channel delivers:
1. Select **Alerting**.
2. In the channel's row, select **Send test**.
On the channel's own page, the **Test delivery** panel has the same action and shows the result of each test. Each member can send 10 tests a minute.
A test to an SMS channel sends a test SMS and uses 1 credit. A test to a voice channel places a short test call and uses 2 credits. The test call has nothing to acknowledge.
A failed test does not count towards disabling the channel. A successful test resets the failure counter.
## When Spectate disables a channel
Spectate tries each delivery 3 times: at once, after 30 seconds and after 2 more minutes. If all tries fail, the delivery counts as one failure for the channel. Spectate disables the channel in these cases:
- 5 failed deliveries in a row.
- 2 failed deliveries in a row, where the last one is a permanent error. Permanent errors are HTTP `401`, `403`, `404` and `410`, a revoked token, or an unknown chat. Spectate does not retry permanent errors.
- At least 2 failed deliveries in a row over more than 24 hours.
A successful delivery resets the count. When Spectate disables a channel, it sends an email to the team's owners, managers and admins. Escalation steps for a disabled channel are skipped, and the next step runs at once. The escalation path shows a [warning](/alerting/escalation-paths#warnings).
To turn the channel on again:
1. Fix the destination, for example a new webhook URL.
2. Select **Test & re-enable** on the **Alerting** page.
If the test arrives, Spectate turns the channel on again. You can also open the channel, select **Edit**, and select **Enabled**.
## Turn a channel off
1. Open the channel.
2. Select **Edit**.
3. Clear **Enabled**.
4. Select **Save changes**.
Escalation paths skip a disabled channel. In the dashboard, you can change the name of a channel, but not its delivery details. To send to another address or URL, add a new channel, or change the channel with the [API](/api-reference/channels). A Slack channel can move to another Slack channel, and a Telegram channel to another chat.
## SMS and call credits
SMS, voice calls and on-call pages by phone use notification credits:
| What | Credits |
|---|---|
| One SMS | 1 per recipient |
| One voice call | 2 per number |
Spectate takes credits only after the SMS or the call went out. A retry does not use credits again.
Each paid plan includes credits every month. Unused monthly credits do not carry over. The trial includes no monthly credits.
| Plan | Credits a month |
|---|---|
| Starter | 10 |
| Team | 50 |
| Business | 200 |
You can buy more in packs of 100 under **Billing → SMS and call credits**. Bought credits never expire, and Spectate uses them after the monthly credits. Owners and billing members can buy credits. Owners, admins and billing members get an email when the balance drops to 20% of the monthly credits, and when it reaches zero.
:::caution
Without credits, SMS and voice channels send nothing, and on-call pages go out by email only. Other channel types do not use credits.
:::
See [plans and billing](/account/plans-and-billing) and [pricing](https://spectate.net/pricing).
## Related
- [Channels API](/api-reference/channels): add, change, test and delete channels.
- [Escalation paths](/alerting/escalation-paths): send alerts to channels.
---
## Document: Alerts
What a Spectate alert is, where alerts come from, how to acknowledge, resolve and delete them, and when they resolve on their own.
URL: /alerting/alerts
# Alerts
An **alert** is a signal that something is wrong with one of your resources, for example a monitor that is down. Spectate fires the alert, sends it through the [escalation paths](/alerting/escalation-paths) of the resource, and resolves it when the problem is over. An alert is not an [incident](/incidents/introduction). An incident is the work your team does on a problem, with updates, roles and a postmortem.
## Where alerts come from
Every alert has a source type (`source_type` in the API). The source type also sets the default severity.
| Source | `source_type` | Spectate fires an alert when | Severity |
|---|---|---|---|
| [Uptime monitors](/monitors/introduction) | `uptime` | A monitor is down: a check failed, and a second check from the same region about 5 seconds later also failed. | `critical` |
| [Performance](/monitors/performance) | `performance` | The response time is over the threshold, or deviates from normal. | `high` over the threshold, `medium` for a deviation |
| [Certificates](/monitors/certificates) | `certificate` | A TLS certificate is invalid, expires soon, or its issuer changed. | Depends on the problem, `low` for an issuer change |
| [DNS monitors](/monitors/dns) | `dns` | The DNS answer changed, if the monitor alerts on changes. | `low` |
| [Hosts](/hosts/health-checks) | `host_metric` | A [metric condition](/hosts/metric-conditions) holds, a health check fails, or the host stopped sending data. | Set per condition and per health check. `high` for no data. |
| [Domains](/domains/checks) | `domain` | A domain expires soon, has expired, or its registration changed. | `medium`, `critical` when expired, `low` for a change |
| [Status pages](/status-pages/issue-reports) | `status_page` | Visitors report problems over your threshold, or traffic spikes. | `high` for reports, `medium` for a traffic spike |
| [Alert sources](/alerting/alert-sources) | `external` | An external tool, such as Grafana or Sentry, sends an alert. | From the tool, else the source's default (`high` unless you change it) |
## States and severity
An alert has two statuses (`status`):
| Status | Meaning |
|---|---|
| `firing` | The problem is ongoing. The alert escalates until someone acknowledges it. |
| `resolved` | The problem is over, or someone resolved the alert by hand. |
Acknowledged is not a separate status. An acknowledged alert is still `firing`, with a value in `acknowledged_at`. The dashboard shows it as **acknowledged**.
Severity (`severity`) is one of four values:
| Severity | Use |
|---|---|
| `critical` | Customers are affected right now. |
| `high` | Serious, needs attention soon. |
| `medium` | Should be looked at. |
| `low` | Informational. |
## One alert per problem
Spectate does not fire a second alert for a problem that already has a firing alert. For alerts from Spectate itself, a resource has one firing alert per source type and title. For example, a monitor that stays down keeps one `uptime` alert, whatever the number of failed checks.
For [alert sources](/alerting/alert-sources), the key is the dedupe key (`dedupe_key`) that the tool sends. One firing alert exists per alert source and dedupe key. A repeat of the same key keeps that alert firing.
## Find alerts
Select **Alerts** in the dashboard. The tabs **Firing**, **Resolved** and **All** filter by status. You can also filter by source and by severity.
Open an alert to see what fired it, the labels and links that an external tool sent, and the **Escalation** panel. The **Escalation** panel shows each step of the escalation path, when it ran, and why a step was skipped.
## Acknowledge an alert
Acknowledge an alert to tell your team that you work on it. Acknowledging stops the escalation: steps that did not run yet do not run. The alert keeps firing until its source recovers or someone resolves it.
1. Open the alert in the dashboard.
2. Select **Acknowledge**.
You can also acknowledge an alert in these places:
- The **Acknowledge** button on an alert message in [Slack](/alerting/slack) or [Telegram](/alerting/telegram-and-phone).
- A voice call from Spectate: press 1. See [Telegram and phone](/alerting/telegram-and-phone).
- The [public API](/api-reference/alerts) and the [MCP server](/developers/mcp).
- Acknowledging the [incident](/incidents/introduction) that the alert opened.
Spectate records who acknowledged the alert. Slack and Telegram messages about the alert change to show it.
## Resolve an alert
Most alerts resolve on their own. When the monitor is up again, the metric is back under its threshold, or the alert source sends a resolve, Spectate resolves the alert.
To resolve an alert by hand:
1. Open the alert in the dashboard.
2. Select **Resolve**.
3. Select **Resolve alert** to confirm.
If the problem is still there, the next check fires a new alert. An alert about a change, for example `DNS records changed for api.example.com`, has no recovery. Resolve it by hand after you examine the change.
When an alert resolves, by hand or on its own, Spectate does these things:
- It stops the escalation.
- It sends a resolved notification to every enabled channel that got the alert.
- It sends an email to each on-call member that Spectate paged for the alert.
- It updates the alert messages in Slack and Telegram.
Spectate records who resolved an alert by hand (`resolved_by`). For an alert that resolved on its own, `resolved_by` is `null`.
## Delete an alert
You can delete resolved alerts only. Resolve a firing alert first.
1. Open the resolved alert.
2. Select **Delete**.
3. Select **Delete alert** to confirm.
Spectate deletes the alert and its escalation history. Incidents that the alert opened stay. Messages that Spectate posted in Slack or Telegram stay in their channels.
## Who can do what
| Action | Owner | Manager | Admin | Member | Billing |
|---|---|---|---|---|---|
| See alerts | Yes | Yes | Yes | Yes | No |
| Acknowledge and resolve | Yes | Yes | Yes | Yes | No |
| Delete resolved alerts | Yes | Yes | Yes | No | No |
See [teams and roles](/account/teams-and-roles) for all permissions.
## Related
- [Escalation paths](/alerting/escalation-paths): who gets an alert, in which order.
- [Channels](/alerting/channels): where Spectate sends alerts.
- [Alerts API](/api-reference/alerts): list, get, acknowledge, resolve and delete alerts.
---
## Document: Alert sources
Send alerts from Grafana, Prometheus Alertmanager, Sentry, email or any script into Spectate, with payload formats, dedupe keys and the event log.
URL: /alerting/alert-sources
# Alert sources
An **alert source** receives alerts from another tool and turns them into Spectate alerts. The alerts go through [escalation paths](/alerting/escalation-paths), on-call, Slack, phone calls and incidents, the same as alerts from Spectate's own monitors. Each alert source has its own URL, or its own email address for email sources.
## Supported tools
| Tool | `type` | Spectate reads | Resolves when |
|---|---|---|---|
| Webhook | `webhook` | Spectate's own JSON format, for scripts, CI and anything that can call a URL | The request has `"status": "resolved"` |
| Email | `email` | The subject is the alert, the body is the description | The subject starts with `RESOLVED`, `RECOVERED`, `RECOVERY`, `OK` or `CLEARED`, or after the auto-resolve time |
| Prometheus Alertmanager | `alertmanager` | The `webhook_configs` payload, version 4 | Alertmanager sends `resolved`, with `send_resolved: true` |
| Grafana | `grafana` | A Grafana Alerting webhook contact point, Grafana Cloud or self-hosted | Grafana sends `resolved` |
| Sentry | `sentry` | An internal integration on sentry.io or self-hosted Sentry, or the legacy WebHooks plugin | The issue is resolved, ignored or archived, or the metric alert resolves |
## Add an alert source
Owners, managers and admins can add alert sources.
1. In the dashboard, select **Alerting**.
2. Under **Alert sources**, select **Add alert source**.
3. Select the tool.
4. Enter a **Name**, for example `Grafana production`. Spectate shows the name on the alerts.
5. Optional: select a **Project**.
6. Select who gets the alerts: **Default routing** or **Specific paths**.
7. Optional: open **Severity and auto-resolve** and change the **Default severity** or **Resolve automatically**.
8. Select **Create and connect**.
9. Follow the setup steps for the tool. Spectate fills in the URL.
The **Live check** panel shows the first request that arrives and what Spectate made of it.
**Default routing** uses the project's escalation paths, or else the team default path.
### The URL and the email address
Each alert source gets a secret URL:
```text
https://api.spectate.net/integrations/alerts/YOUR_SOURCE_TOKEN
```
An email source gets a secret address:
```text
YOUR_SOURCE_TOKEN@alerts.spectate.net
```
The token in the URL or address is the credential. Anyone with the URL can send alerts to the source. Keep it secret.
## Webhook format
Send a `POST` request with a JSON body. Only `title` is required.
```bash
curl -X POST "https://api.spectate.net/integrations/alerts/YOUR_SOURCE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Disk almost full on db-1",
"severity": "high",
"dedupe_key": "db-1/disk",
"description": "Less than 5% free on /var/lib/postgresql",
"links": [{ "label": "Runbook", "url": "https://wiki.example.com/disk" }],
"metadata": { "host": "db-1" }
}'
```
To resolve the alert, send the same `dedupe_key` with `"status": "resolved"`:
```bash
curl -X POST "https://api.spectate.net/integrations/alerts/YOUR_SOURCE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "dedupe_key": "db-1/disk", "title": "Disk almost full on db-1", "status": "resolved" }'
```
| Field | Required | Description |
|---|---|---|
| `title` | Yes | What is wrong, up to 250 characters. Spectate also reads `summary` or `name`. |
| `status` | No | `firing` (default) or `resolved`. Spectate also reads `ok`, `recovered` and `closed` as resolved. |
| `dedupe_key` | No | Your ID for the problem. Requests with the same key keep one alert firing. The default is the title. Spectate also reads `id`. |
| `severity` | No | `critical`, `high`, `medium` or `low`, or a word from the severity table below. Spectate also reads `priority`. |
| `description` | No | More about the problem, up to 4000 characters. Spectate also reads `message`. |
| `links` | No | Up to 5 links, each `{"label": "...", "url": "https://..."}`. A single URL string also works. |
| `metadata` | No | Up to 20 keys with text, number or boolean values. |
To send more than one alert in one request, put them in an `alerts` list, up to 100 alerts:
```json
{ "alerts": [ { "title": "Disk almost full on db-1" }, { "title": "Backup failed", "severity": "critical" } ] }
```
To check the connection without alerting anyone, send `{"test": true}`.
### Response
Spectate answers a valid request with `202 Accepted` and what it did:
```json
{
"outcome": "fired",
"summary": "Fired 1",
"error": null,
"alerts": [{ "action": "fired", "dedupe_key": "db-1/disk" }]
}
```
| Status | Meaning |
|---|---|
| `202` | Received. `outcome` says what happened. |
| `401` | The signature or bearer token does not match the source's secret. |
| `404` | No alert source has this URL. The token is wrong, or someone made a new URL. |
| `413` | The body is larger than 512 KB. |
| `422` | Spectate cannot read the body, for example JSON without a title. |
| `429` | More than 300 requests in a minute for this URL. |
Rejected requests fire nothing.
## Prometheus Alertmanager
Add a receiver to `alertmanager.yml`, then reload Alertmanager:
```yaml
receivers:
- name: spectate
webhook_configs:
- url: "https://api.spectate.net/integrations/alerts/YOUR_SOURCE_TOKEN"
send_resolved: true
route:
receiver: spectate
```
- Each alert becomes its own Spectate alert. The dedupe key is the alert's `fingerprint`.
- The title is the `summary` annotation. Without it, the title is the `alertname` label, followed by `on` and the `instance` label.
- The severity comes from the `severity` label, or else the `priority` label.
- The labels are kept. Escalation path [branches](/alerting/escalation-paths#branches) can test them, for example `env` is `production`.
If you set a secret on the source and Alertmanager sends an `Authorization: Bearer` header, the token must be the secret.
## Grafana
1. In Grafana, go to **Alerting → Contact points → + Add contact point**.
2. Name it `Spectate` and select the **Webhook** integration.
3. Paste the alert source URL.
4. Under **Optional Webhook settings → HMAC signature**, paste a secret.
5. Select **Test** in Grafana. Spectate shows **Grafana test notification received**.
6. In **Alerting → Notification policies**, use the Spectate contact point.
Generate the secret in Spectate with **Generate a secret** in the setup steps. With a secret, Spectate rejects requests without a valid `X-Grafana-Alerting-Signature` header. The Grafana **Test** button fires no alert. Grafana alerts use the Alertmanager format, so titles, severity and labels work as above.
## Sentry
1. In Sentry, go to **Settings → Developer Settings → Custom Integrations**.
2. Select **Create New Integration → Internal Integration** and name it `Spectate`.
3. Paste the alert source URL as the webhook URL, and turn on **Alert Rule Action**.
4. Give **Issue & Event** read access, and under **Webhooks** select **issue**.
5. Save, then paste the **Client Secret** in the Spectate setup steps.
6. In your Sentry alert rules, add the action **Send a notification via Spectate**.
| Sentry sends | Spectate does |
|---|---|
| An issue alert rule fires | Fires an alert for the issue |
| A metric alert is `critical` or `warning` | Fires an alert for the metric alert |
| A metric alert resolves | Resolves its alert |
| An issue is resolved, ignored or archived | Resolves the issue's alert |
| A new issue | Fires an alert only if you select **Also alert on every new issue** |
With the client secret saved, Spectate checks the `Sentry-Hook-Signature` header of each request. Very old self-hosted Sentry versions can use the legacy **WebHooks** plugin with the same URL. That plugin does not sign requests.
## Email
Send or forward alert emails to the source's address. Backup jobs, NAS and UPS alerts, cron, Zabbix and Nagios can all send email.
- The subject is the alert title. The body is the description.
- The same subject again keeps the alert firing.
- A subject that starts with `RESOLVED`, `RECOVERED`, `RECOVERY`, `OK` or `CLEARED` resolves the alert with the same subject.
- A word such as `[CRITICAL]` or `Warning:` at the start of the subject sets the severity.
Email has no standard way to say that a problem is over. Email sources resolve their alerts after 60 minutes without a repeat by default.
## Dedupe keys
One alert source has one firing alert per dedupe key. A repeat of a firing key keeps the alert firing and does not notify anyone again. A resolve resolves the alert with that key.
| Tool | Dedupe key |
|---|---|
| Webhook | `dedupe_key`, else `id`, else the title |
| Email | The subject, without `RESOLVED`, `[PROBLEM]` and similar words |
| Alertmanager and Grafana | The alert's `fingerprint` |
| Sentry | The issue, or the metric alert |
## Severity
If the tool sends a severity, Spectate maps it to its own four values. If the tool sends none, or a word not in this table, the alert gets the source's **Default severity**. The default is `high`.
| Spectate severity | Words that map to it |
|---|---|
| `critical` | critical, crit, fatal, emergency, alert, page, p1, sev1, disaster |
| `high` | high, error, err, major, p2, sev2 |
| `medium` | medium, warning, warn, average, p3, sev3 |
| `low` | low, info, information, informational, minor, notice, debug, p4, p5, sev4, sev5 |
## Resolve automatically
Some tools never say that a problem is over. For these, set **Resolve automatically**. Spectate then resolves an alert when the tool has not repeated it for that time.
| Option | `auto_resolve_minutes` |
|---|---|
| **Never** | `null` (default, except for email) |
| **After 30 minutes** | `30` |
| **After 1 hour** | `60` (default for email) |
| **After 4 hours** | `240` |
| **After 24 hours** | `1440` |
With the API, any value from 5 to 10080 minutes is allowed.
## Recent events
The source page shows **Recent events**: every request of the last 7 days, with the outcome and the request itself. Look here first when an alert did not arrive. Spectate stores the first 32 KB of each request.
| Outcome | Meaning |
|---|---|
| `fired` | It fired at least one new alert. |
| `resolved` | It resolved at least one alert. |
| `updated` | It repeated alerts that were already firing. |
| `test` | A test from the tool's own test button. No alert. |
| `ignored` | Valid, but nothing to do. For example, a resolve for an alert that is not firing, or a request to a source that is turned off. |
| `rejected` | Refused: a bad signature or a body that Spectate cannot read. The event shows the error. |
## Send a test alert
1. Open the alert source.
2. Select **Send test alert**.
3. Confirm.
Spectate fires a real alert, `Test alert from SOURCE NAME`, through the source's escalation paths. The test alert resolves itself after 5 minutes.
## Make a new URL
If the URL or address leaked, make a new one:
1. Open the alert source.
2. Select **New URL**, or **New address** for an email source.
3. Select **Create new URL** or **Create new address** to confirm.
:::caution
The old URL or address stops working at once. Update the tool with the new one, or its alerts do not arrive.
:::
## Turn off or delete a source
To stop a source without deleting it, open its **Settings** and clear **Receiving alerts**. Spectate still logs the requests, but fires nothing. When you delete a source, Spectate resolves its firing alerts first.
## Related
- [Alert sources API](/api-reference/alert-sources): create sources, rotate the URL, send a test alert and read events.
- [Escalation paths](/alerting/escalation-paths): route alerts by source and label.
---
## Document: Teams and roles
How Spectate teams work, how to create and switch teams, and what each of the five roles (owner, manager, admin, member, billing) can do.
URL: /account/teams-and-roles
# Teams and roles
A team holds everything you monitor in Spectate: monitors, hosts, domains, alerts, incidents and status pages. Each team has its own plan, its own members and its own settings. Each member of a team has one role, and the role decides what the member can do in that team.
## Teams
When you sign up, Spectate creates a team for you, named after you, for example "Jane Doe's Team". You are its owner. You can rename it under **Team → Settings**.
You can be a member of more than one team, for example one per company or customer. Every team has a separate plan and a separate bill. Data never moves between teams.
### Create a team
1. In the dashboard, go to **Team**.
2. Select **Create team**.
3. Type the **Team name**.
4. Select **Create team**.
You become the owner of the new team. The dashboard switches to it. A new team starts with its own 14-day trial. See [plans and billing](/account/plans-and-billing).
A new team has a [default project](/account/projects#the-default-project) named **Default**, the same as the team you get when you sign up. New monitors, hosts and domains join it when you do not select a project.
### Switch teams
The dashboard shows one team at a time, the current team.
1. Select the team name at the top of the sidebar.
2. Select the team that you want to use.
**Manage teams** in the same menu opens the **Team** page.
### Team settings
Owners and managers can change the team settings under **Team → Settings**:
| Setting | What it does |
|---|---|
| **Team name** | The name in the dashboard and in emails. |
| **Contact email** | Optional. At the team's first checkout for a plan or credits, Spectate gives this address to Vatly for invoices and receipts. Without it, Spectate gives Vatly the address of the member who starts the checkout. |
| **Default timezone** | The time zone for schedules and reports. |
| **AI assistants** | Whether AI assistants can use the team through the [MCP server](/developers/mcp): **Full**, **Read only** or **Off**. |
The **Reference** section shows the **Team ID**. Support may ask for it.
## Roles
A team has five roles:
| Role | In short |
|---|---|
| Owner | Everything, including billing and deleting the team. A team has one owner. |
| Manager | Everything except billing and deleting the team. |
| Admin | Configures monitoring, alerting, incidents and status pages. Cannot change team settings, members or API tokens. |
| Member | Sees everything. Creates and changes monitors and incidents, and acknowledges and resolves alerts. |
| Billing | Billing and support only. |
## What each role can do
| What you can do | Owner | Manager | Admin | Member | Billing |
|---|---|---|---|---|---|
| See monitors, hosts, domains, alerts, incidents, status pages, projects and members | Yes | Yes | Yes | Yes | No |
| Create, change, pause and resume monitors | Yes | Yes | Yes | Yes | No |
| Delete monitors | Yes | Yes | Yes | No | No |
| Add, change and delete hosts and their metric conditions | Yes | Yes | Yes | No | No |
| Add, change and delete domains | Yes | Yes | Yes | No | No |
| Acknowledge and resolve alerts | Yes | Yes | Yes | Yes | No |
| Delete resolved alerts | Yes | Yes | Yes | No | No |
| Manage channels, escalation paths, alert sources and on-call schedules | Yes | Yes | Yes | No | No |
| Declare, update and resolve incidents | Yes | Yes | Yes | Yes | No |
| Delete incidents | Yes | Yes | Yes | No | No |
| Create, change and delete status pages, their incidents and maintenance | Yes | Yes | Yes | No | No |
| Create, change and delete projects | Yes | Yes | Yes | No | No |
| Change team settings | Yes | Yes | No | No | No |
| Invite members, change roles and remove members | Yes | Yes | No | No | No |
| Create and revoke team API tokens | Yes | Yes | No | No | No |
| Choose a plan, buy credits, see invoices | Yes | No | No | No | Yes |
| Delete the team, or restore it during the grace period | Yes | No | No | No | No |
| Transfer ownership to another member | Yes | No | No | No | No |
| Open and read support tickets | Yes | Yes | Yes | Yes | Yes |
The [public API](/developers/api) and the [MCP server](/developers/mcp) check the same permissions. A [team API token](/developers/api-tokens) can only get the abilities that the role of its creator has.
## Change a role
Owners and managers can change the role of a member. See [members](/account/members#change-a-role). A role change cannot make a member the owner or change the owner's role.
## Transfer ownership
The owner can make another member of the team the owner. The owner confirms with their password. The new owner gets the owner role, and the previous owner becomes a manager. Both get an email. A team always has exactly one owner. See [transfer ownership](/account/members#transfer-ownership) for the steps.
## Related
- [Members](/account/members): invite people, change roles, remove members and transfer ownership.
- [Plans and billing](/account/plans-and-billing): the member limit of each plan.
---
## Document: Sign-in and security
Sign in to Spectate with a password or with GitHub, Google or Microsoft, verify your email, and protect your account with two-factor authentication.
URL: /account/sign-in-and-security
# Sign-in and security
You sign in to the Spectate dashboard with your email address and a password, or with a GitHub, Google or Microsoft account. You must verify your email address before you can use the dashboard. Two-factor authentication adds a code from an authenticator app to every sign-in.
## Sign in
- **Email and password**: type your **Email** and **Password**, then select **Sign in**. Select **Keep me signed in** to stay signed in on this browser.
- **GitHub, Google or Microsoft**: select the button of the provider above the email form.
If you forgot your password, select **Forgot password?** on the sign-in page. Spectate sends a reset link that is valid for 60 minutes.
## Verify your email address
Spectate sends alerts, incident updates and account emails only to a verified address. Until you verify, you can sign in and manage your account, but you cannot use the rest of the dashboard.
1. Open the email from Spectate.
2. Select the verification link. The link is valid for 24 hours.
The **Verify your email** page continues on its own when you verify. On that page you can also send the email again, change the address, or log out. To accept a [team invite](/account/members#accept-an-invite), you also need a verified address.
Some sign-in providers verify the address for you:
| Provider | Verifies your email |
|---|---|
| GitHub | Yes |
| Google | Yes, if Google marks the address as verified |
| Microsoft | No. Spectate sends a verification email. |
An existing account also becomes verified when you sign in with GitHub or Google with the same email address.
## Sign in with GitHub, Google or Microsoft
If no Spectate account has the provider's email address, Spectate creates an account and a team for you.
If a Spectate account already uses that email address, the provider cannot create a second account. Connect the provider to your existing account first:
1. Sign in with your email and password.
2. Go to **Account → Security**.
3. Under **Sign-in providers**, select **Connect** next to the provider.
4. Sign in at the provider.
To stop using a provider, select **Disconnect** next to it. An account that you created with a provider has a random password. To set your own password, use **Forgot password?** on the sign-in page.
## Two-factor authentication
Two-factor authentication (2FA) asks for a 6-digit code from an authenticator app every time you sign in. It also applies when you sign in with GitHub, Google or Microsoft.
### Turn on two-factor authentication
1. Go to **Account → Security**.
2. Under **Two-factor authentication**, select **Enable 2FA**.
3. Type your **Current password** and select **Continue**.
4. Scan the QR code with your authenticator app.
5. Type the 6-digit code from the app.
6. Select **Confirm and enable**.
7. Save the recovery codes. Select **Download**, or copy them to a password manager.
### Recovery codes
A recovery code lets you sign in if you lose your authenticator app. Each code works once. On the sign-in page, select **Use a recovery code instead**, then type a code.
To see your codes or make new ones, go to **Account → Security** and select **Recovery codes**. Select **Regenerate** to replace all codes. The old codes stop working.
### Turn off two-factor authentication
1. Go to **Account → Security**.
2. Under **Two-factor authentication**, select **Disable**.
3. Type your **Current password**.
4. Select **Disable 2FA**.
## Change your password or email address
- **Password**: go to **Account → Security**. Under **Password**, type your **Current password** and the new password twice. Select **Change password**.
- **Email address**: go to **Account → Profile**. Change **Email address** and select **Save profile**. You must verify the new address. Spectate also sends a notice to the old address.
## Security emails
Spectate sends you an email when one of these things happens to your account:
- Your email address changes. Spectate sends this email to the old address.
- Your password changes or is reset.
- Two-factor authentication is turned on or off.
- Your recovery codes are regenerated.
- A sign-in provider is connected or disconnected.
If you did not make the change, reset your password and contact [help@spectate.net](mailto:help@spectate.net).
## Sessions
**Account → Sessions** shows the browser that you use now. Select **Sign out** to end this session.
## AI assistants
**Account → AI assistants** lists the AI assistants that you connected to Spectate through the [MCP server](/developers/mcp). You can disconnect each one there.
## Related
- [Data and privacy](/account/data-and-privacy): how to delete your account.
- [Teams and roles](/account/teams-and-roles): what you can do in each team.
---
## Document: Projects
Group monitors, hosts and domains in projects, give each project its own escalation paths and metric conditions, and filter API results by project.
URL: /account/projects
# Projects
A project groups monitors, hosts and domains of a team, for example per product, customer or environment. A project can have its own [escalation paths](/alerting/escalation-paths), so alerts of its resources go to the right people. A project can also have [metric conditions](/hosts/metric-conditions) that apply to all its hosts.
## The default project
Every team has a default project, named **Default**. Spectate creates it with the team: the team you get when you sign up, and every team you create later. These resources join the default project when you do not select a project:
- New monitors.
- New hosts. The agent always registers a host in the default project.
- New domains.
You cannot delete the default project. Every plan includes an unlimited number of projects.
## Create a project
Owners, managers and admins can create, change and delete projects.
1. In the dashboard, go to **Projects**.
2. Select **Create project**.
3. Type a **Name**, for example `Production`.
4. Optional: select the escalation paths for alerts of the project.
5. Select **Create project**.
## Move a resource to a project
- **Monitor**: select the **Project** when you create the monitor, or change it in the monitor's settings.
- **Host**: open the host, go to **Settings & alerts** and change **Project** under **General**.
- **Domain**: open the domain, go to **Settings** and change **Project** under **General**.
Select **Save changes** after a change.
## How alerts use a project
The **Alerting** section of a monitor, host or domain has two choices:
- **Default routing**: alerts go to the escalation paths of the resource's project. If the project has no escalation paths, alerts go to the team's default path.
- **Specific paths**: alerts go only to the escalation paths that you select for the resource.
To change the escalation paths of a project:
1. Open the project.
2. Select **Edit**.
3. Select the escalation paths.
4. Select **Save changes**.
The project page shows the paths under **Escalation routing**. If the project has none, the page says "Alerts fall back to the team default path."
## Metric conditions on a project
A metric condition on a project applies to every host in the project, also to hosts that you add later. Add them on the project page under **Metric conditions**. See [add a condition to a project](/hosts/metric-conditions#add-a-condition-to-a-project).
## Delete a project
1. Open the project.
2. Under **Delete this project**, select **Delete project**.
3. Type the project name to confirm, then select **Delete project**.
Spectate does not delete the monitors, hosts and domains of the project. They stay without a project. Their alerts with default routing then go to the team's default escalation path. The metric conditions of the project stop applying to its hosts.
## Filter by project in the API
The [public API](/api-reference/projects) manages projects. These lists accept `filter[project_id]` with the project ID:
- [Monitors](/api-reference/monitors)
- [Hosts](/api-reference/hosts)
- [Domains](/api-reference/domains)
- [Metric conditions](/api-reference/metric-conditions)
```bash
curl "https://api.spectate.net/v1/monitors?filter[project_id]=YOUR_PROJECT_ID" \
-H "Authorization: Bearer YOUR_API_TOKEN"
```
The dashboard's monitor, host and domain lists have no project filter. The project page shows the number of monitors and the metric conditions of the project.
---
## Document: Plans and billing
Spectate plans and their limits, the trial, paying per monitor or host, SMS and call credits, what happens over a limit or without a plan, and invoices.
URL: /account/plans-and-billing
# Plans and billing
Spectate has three plans: Starter, Team and Business. The plan decides the features and limits of a team. You choose how many monitors and hosts you pay for, so one more monitor never costs a whole plan. For prices, see [spectate.net/pricing](https://spectate.net/pricing).
Only the owner and members with the Billing role can choose a plan, buy credits and see invoices. See [teams and roles](/account/teams-and-roles).
## Plans
| | Starter | Team | Business |
|---|---|---|---|
| Minimum number of monitors and hosts | 20 | 80 | 250 |
| Shortest check interval | 60 seconds | 30 seconds | 30 seconds |
| Members | 3 | No limit | No limit |
| On-call schedules and more escalation paths | No. Alerts use the team's default path. | Yes | Yes |
| Status pages | 1 | 5 | No limit |
| Private status pages | No | Yes | Yes |
| Status page subscribers | 250 | 2,500 | 25,000 |
| SMS and call credits a month | 10 | 50 | 200 |
Every plan includes domain monitoring, projects, all channel types, alert sources, incidents and postmortems, failure screenshots, and custom domains and password protection on status pages. Domains and projects have no limit.
Monitors and hosts share one limit. A team on the Team plan that pays for 100 can run, for example, 70 monitors and 30 hosts. You can pay for up to 2,000 in the dashboard, in steps of 5. For more, contact [help@spectate.net](mailto:help@spectate.net).
## Trial
A new team gets a 14-day trial of the Team plan. You do not need payment details.
- The trial allows 80 monitors and hosts.
- The trial includes no SMS and call credits. Credits that you buy work during the trial.
- Spectate sends a reminder 3 days and 1 day before the trial ends.
- When the trial ends without a plan, monitoring pauses. Spectate deletes nothing at that time. See [without a plan](#without-a-plan).
## Choose a plan
1. In the dashboard, go to **Billing**.
2. Under **Billing**, select **Monthly** or **Yearly**.
3. Select the **Plan**.
4. Under **Monitors and hosts**, set the number that you want to pay for.
5. Select **Continue to checkout**.
6. Pay on the checkout page of Vatly.
When you subscribe, the trial ends and the plan starts. If monitoring was paused because the team had no plan, it resumes at once.
## Change your plan
On the **Billing** page, select another plan, interval or number of monitors and hosts.
- If the new price is higher, the change applies at once. On a monthly plan, the difference for the rest of the month goes on your next invoice. On a yearly plan, Vatly charges the difference at once.
- If the new price is lower, or you change between monthly and yearly, the change applies at the next renewal. The button says **Schedule change**.
If you pay for fewer monitors and hosts than you use, Spectate pauses the newest ones when the change applies.
## Over a limit
Spectate never deletes resources because of a limit. It pauses them instead.
- **Adding a monitor at the limit**: Spectate refuses the new monitor with the error `PLAN_LIMIT_REACHED`. The dialog offers to add 5 more monitors and hosts to your plan.
- **Adding a host at the limit**: the agent cannot register the host. Registration fails with `PLAN_LIMIT_REACHED`.
- **Inviting a member at the limit**: Spectate refuses the invite. Pending invites count towards the limit.
- **A smaller plan or a lower number**: the oldest monitors, hosts, domains and status pages stay active. Spectate pauses the newest ones above the limit. Monitors that check more often than the plan allows change to the shortest interval of the plan.
When Spectate pauses resources, the dashboard shows a banner. Owners, admins and billing members get an email. When the team has room again, Spectate resumes the paused resources, oldest first. It checks every hour, and at once when the plan changes.
On-call schedules, escalation paths and private status pages that you made on a larger plan keep working after a downgrade.
## SMS and call credits
Spectate uses credits for SMS messages and phone calls to people:
| Notification | Credits |
|---|---|
| SMS | 1 per phone number |
| Phone call | 2 per phone number |
- **Monthly credits**: every plan includes credits each month, also on a yearly plan. Unused credits do not carry over to the next month.
- **Bought credits**: on the **Billing** page under **SMS and call credits**, buy packs of 100 credits. You can buy 1 to 50 packs at a time. Bought credits never expire. Spectate uses them after the monthly credits.
Owners, admins and billing members get an email when 20% of the monthly credits is left, and when no credits are left. Alerts continue on all other channels when you have no credits. See [Telegram and phone](/alerting/telegram-and-phone).
## Cancel
1. Go to **Billing**.
2. Select **Cancel subscription**, then confirm.
The plan continues until the end of the paid period. Then monitoring pauses and owners get an email. To undo the cancellation before that date, select **Resume subscription**.
## Without a plan
A team has no plan when its trial ends, or when its subscription ends. Then:
1. Monitoring pauses for the whole team. Spectate stops checking monitors and domains. Your settings and history stay.
2. After 90 days without a plan, Spectate schedules the team for deletion. Owners, admins and billing members get a final warning by email.
3. 14 days after the warning, Spectate deletes the team and all its data.
If you subscribe at any time before the deletion, monitoring resumes and Spectate cancels the deletion. See [data and privacy](/account/data-and-privacy#delete-a-team).
## Invoices and payment
Vatly sells Spectate subscriptions as the merchant of record. Vatly charges the VAT, sends the invoices and receipts, collects the payments and sends payment reminders. Vatly's billing emails are in English.
To see invoices, or to change the payment method, VAT number or company name, go to **Billing** and select **Invoices and payment**. This opens the Vatly customer portal.
Prices are in euros and exclude VAT.
---
## Document: Members
Invite people to your Spectate team by email, accept an invite, change a member's role, remove members and transfer ownership of the team.
URL: /account/members
# Members
Members are the people in your team. You add a member with an invite by email. Each member has one [role](/account/teams-and-roles), which decides what the member can do. Owners and managers can invite members, change roles and remove members.
## Invite a member
1. In the dashboard, go to **Team**.
2. Select **Invite member**.
3. Type the person's **Email**.
4. Select a **Role**. The default is **Member**.
5. Select **Send invite**.
Spectate sends an email with the subject "You've been invited to join TEAM_NAME on Spectate". The invite shows under **Pending invites** until the person accepts it.
These rules apply to invites:
- An invite is valid for 7 days after Spectate sends it.
- You cannot invite someone who is already a member, or who has a pending invite.
- Spectate does not accept disposable email addresses.
- You cannot invite someone as owner. A team has one owner.
- Pending invites count towards the member limit of your plan. The Starter plan allows 3 members. The Team and Business plans have no member limit.
To send an expired invite again, invite the same address again. Spectate replaces the old invite.
To cancel an invite, select **Revoke** next to it under **Pending invites**.
## Accept an invite
1. Open the link in the invite email.
2. Sign in, or create an account, with the email address that received the invite.
3. Verify your email address, if you have not done that yet.
4. Select **Accept invite**.
You join the team with the role from the invite. The dashboard switches to the team.
An invite works only for the email address it was sent to. If the invite expired, ask the team to send a new one.
## Change a role
1. Go to **Team**.
2. In the list of members, select the new role next to the member.
The change applies at once. You cannot change the owner's role here. To make another member the owner, [transfer ownership](#transfer-ownership).
## Remove a member
1. Go to **Team**.
2. Select the remove button next to the member.
3. Select **Remove member** to confirm.
The person loses access to the team at once. Spectate also removes them from the team's on-call rotations. You cannot remove the owner. The dashboard does not let you remove yourself from a team.
## The owner
Every team has one owner. The owner is the only member who can delete the team or transfer ownership. The owner and billing members are the only roles that can manage billing. The person who creates a team is its owner.
You cannot change the owner's role or remove the owner. To give the team to another person, transfer ownership.
## Transfer ownership
Only the owner can transfer ownership. The new owner must already be a member of the team. If the person is not a member yet, [invite them](#invite-a-member) first.
1. Go to **Team → Settings**.
2. In the **Danger zone**, select **Transfer ownership**.
3. In **New owner**, select the member.
4. Type your password in **Your password**.
5. Select **Transfer ownership**.
The change applies at once:
- The member that you selected becomes the owner.
- You become a manager. You keep access to everything except billing and deleting the team.
- Spectate sends an email to you and to the new owner.
You cannot undo a transfer yourself. Only the new owner can transfer ownership back to you.
If the owner left your company and cannot sign in, send an email to [help@spectate.net](mailto:help@spectate.net). Spectate support can transfer ownership to another member of the team.
:::note
A transfer does not change the billing email at Vatly. Vatly sends invoices and receipts to the address it got at the team's first checkout. See [plans and billing](/account/plans-and-billing).
:::
## Use the API
The [public API](/api-reference/members) can list members, change their roles and remove them. It can also list, send and revoke [invites](/api-reference/invites). This needs a [team API token](/developers/api-tokens) with `members:read` or `members:write`. If you try to change or remove the owner, the API returns `403` with the code `TEAM_OWNER_PROTECTED`. The API cannot transfer ownership, because a transfer needs the owner's password. Use the dashboard.
---
## Document: Data and privacy
Where Spectate stores your data, how long it keeps each type of data, how to delete a team or your account, and who to contact about privacy and security.
URL: /account/data-and-privacy
# Data and privacy
Spectate stores your data in Germany, on servers of Hetzner. It keeps measurements for a fixed time, with less detail as they get older. When you delete a monitor, a host, a domain or a whole team, Spectate permanently deletes its data after 7 days.
## Where Spectate stores data
The API, the databases, the dashboard, the status pages, the file storage and the backups run in Germany.
The checkers that run your [uptime monitors](/monitors/introduction) are in Amsterdam, New York, Singapore and Sydney. A checker outside the EU only gets the monitors for which you selected its region. It sends the results back to Germany and keeps no copy.
Data leaves the EU only when you choose that, for example with a checker region outside the EU, or a channel such as Slack. The [subprocessors list](https://spectate.net/legal/subprocessors) names every company that processes customer data, what it gets and where.
## How long Spectate keeps data
| Data | Kept for |
|---|---|
| Uptime checks, every single check | 90 days |
| Uptime checks, hourly totals | 400 days (about 13 months) |
| Uptime checks, daily totals | 3 years |
| Recorded outages, for the downtime report | 3 years |
| Host metric samples, every 15 seconds | 30 days |
| Host metrics, hourly minimum, maximum, average and last value | 400 days (about 13 months) |
| Failure snapshots: the response and screenshot of a failed check | 90 days |
| Charts in alert notifications | 30 days |
| Status page views, per minute | 400 days |
| Raw events from alert sources | 7 days |
Spectate keeps everything else until you delete it, or until the team is deleted. This includes settings, alerts, incidents, postmortems, status pages and members.
## Deleted monitors, hosts and domains
When you delete a monitor, a host or a domain, it stops at once and no longer shows in the dashboard or the API. Spectate keeps its data for 7 more days. Then Spectate permanently deletes the resource with all its data:
- the check history, response times and outages of a monitor, and its failure snapshots (response bodies and screenshots)
- the metrics of a host
- the alerts of the resource, with their escalation history
Incidents stay, because they belong to the team. In the first 7 days, Spectate support can restore a deleted resource. Send an email to [help@spectate.net](mailto:help@spectate.net). After 7 days, Spectate cannot restore it.
## Delete a team
Only the owner can delete a team.
1. In the dashboard, go to **Team → Settings**.
2. Under **Danger zone**, select **Delete team**.
3. Type the team name to confirm.
4. Select **Delete team**.
What happens next:
1. Monitoring stops at once. Spectate revokes the pending invites.
2. The subscription does not renew. It ends with the current paid period.
3. For 7 days, the team stays visible to its members. The owner can select **Restore team** under **Team → Settings** to keep everything and resume monitoring.
4. After 7 days, Spectate permanently deletes all data of the team. This includes the history, status pages and their uploaded files. If the team installed the Slack app, Spectate also removes it from the Slack workspace.
:::caution
After the grace period, Spectate cannot restore a deleted team.
:::
A team without a paid plan for 90 days is also scheduled for deletion, with 14 days' notice. See [plans and billing](/account/plans-and-billing#without-a-plan).
## Delete your account
The dashboard has no option to delete your account. To delete it, send an email to [privacy@spectate.net](mailto:privacy@spectate.net) from the address of your account.
## Your privacy rights
The [privacy policy](https://spectate.net/legal/privacy) explains which personal data Spectate processes and why. To use your rights under the GDPR, such as access or deletion, send an email to [privacy@spectate.net](mailto:privacy@spectate.net). The [data processing agreement](https://spectate.net/legal/dpa) covers the personal data that you process with Spectate, for example status page subscribers.
## Report a security problem
Send security reports to [security@spectate.net](mailto:security@spectate.net). The [responsible disclosure policy](https://spectate.net/security/disclosure) explains what is in scope and what to include. The contact is also in [security.txt](https://spectate.net/.well-known/security.txt).
For other questions, send an email to [help@spectate.net](mailto:help@spectate.net).
# Spectate public API reference
Base URL: `https://api.spectate.net/v1`. Authentication: a team API token as `Authorization: Bearer spct_...`. The interactive reference is at https://docs.spectate.net/api-reference and the OpenAPI document at https://docs.spectate.net/api-reference/1.0.0/spectate-openapi-v1.json.
Manage your Spectate team from code: monitors, hosts, domains, projects, alerting, on-call, incidents and status pages. This API backs the official SDKs and the Terraform provider; everything they do, you can do with plain HTTP.
### Authentication
Every request sends a **team API token** as a bearer token:
```http
GET /v1/token HTTP/1.1
Host: api.spectate.net
Authorization: Bearer spct_…
```
Owners and managers create tokens in the dashboard under **Team → API tokens**. A token:
- belongs to the team, not to the member who created it, and keeps working when that member leaves;
- can only do what its **abilities** allow, for example `monitors:read` or `incidents:write`. Each endpoint lists the ability it requires. There is no wildcard: a token never gains an ability it wasn't created with;
- is shown once. Spectate stores only a hash of it; lost tokens can't be recovered, only regenerated or revoked;
- may expire. Revoked and expired tokens stop working immediately.
Tokens look like `spct_` followed by 46 letters and digits, the last 6 of which are a checksum, so secret scanners can recognise them. Call `GET /v1/token` to check a token and see its abilities.
### Requests and responses
- Send and expect JSON. Request bodies are `application/json`; responses are always JSON, also for errors.
- IDs are UUIDs. Timestamps are ISO 8601 in UTC, for example `2026-10-25T14:03:00+00:00`.
- `PATCH` changes only the fields you send. Fields you leave out keep their value; send `null` to clear a nullable field.
- Secrets you send (passwords, webhook secrets) are never returned.
### Pagination
List endpoints are paginated with `page` (from 1) and `per_page` (1–100, default 25). The response has the items in `data`, plus `current_page`, `last_page`, `per_page`, `total`, `from`, `to` and the URLs of the neighbouring pages. Filters use `filter[name]=value`; sorting uses `sort=field` (ascending) or `sort=-field` (descending).
### Errors
Every error has the same shape:
```json
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Monitor not found."
}
}
```
Branch on `error.code`, which is stable; `error.message` is for people and may change. Some codes add `error.details`. Validation errors (`422`, `VALIDATION_FAILED`) list the invalid fields in `error.details.errors`.
| Status | Meaning |
| --- | --- |
| `400` | The query is malformed (`INVALID_QUERY`), for example an unknown filter or sort. |
| `401` | No token, or the token is invalid, revoked or expired. |
| `403` | The token lacks an ability (`FORBIDDEN`), the plan doesn't allow it (`PLAN_LIMIT_REACHED`, `PLAN_FEATURE_UNAVAILABLE`), or the team is being deleted or suspended. |
| `404` | No such resource in this team (`RESOURCE_NOT_FOUND`) or no such endpoint (`NOT_FOUND`). |
| `409` | The request conflicts with the current state, for example enabling monitoring on a paused team. |
| `422` | The request body is invalid (`VALIDATION_FAILED`). |
| `429` | Rate limited (`RATE_LIMITED`); see below. |
| `5xx` | Something went wrong on our side (`INTERNAL_ERROR`). Retry with backoff. |
### Rate limits
Each token may make **300 requests a minute**, of which **60 may change something** (`POST`, `PUT`, `PATCH`, `DELETE`). Responses carry `X-RateLimit-Limit` and `X-RateLimit-Remaining`; when you're over, the API answers `429` with a `Retry-After` header in seconds.
### Versioning
This is version 1, under `/v1`. Within it, changes are additive only: new endpoints, new optional request fields, new response fields and new enum values. Treat unknown fields and enum values as possible. Anything that would break a client gets a new version, announced well before the old one is retired.
## API tokens
Check the token you authenticate with. Tokens themselves are created, regenerated and revoked in the dashboard (Team → API tokens) by owners and managers, never through the API.
### Get the current API token
`GET /token`
Operation ID: `getApiToken`
Returns the token that authenticated this request: its name, abilities, team and expiry.
Any valid token may call it, whatever its abilities, so SDKs and the Terraform provider use
it to check credentials before doing anything else. Revoked and expired tokens get `401`.
Responses: `200` The token that authenticated the request.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Monitors
Uptime monitors check a URL, host, port or DNS name from Spectate's regions every interval, and raise alerts when it goes down, gets slow or its certificate is about to expire. Monitors and hosts together count against the plan's resource limit.
### List monitors
`GET /monitors`
Operation ID: `listMonitors`
Returns the team's monitors, newest first unless you sort. Filters combine with AND.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Monitors per page, 1 to 100. |
| `filter[state]` | query | MonitorState | no | Only monitors in this state. |
| `filter[uptime_status]` | query | UptimeStatus | no | Only monitors with this uptime status, whether paused or not. |
| `filter[protocol]` | query | MonitorProtocol | no | Only monitors of this protocol. |
| `filter[enabled]` | query | boolean | no | Only running (`true`) or paused (`false`) monitors. |
| `filter[project_id]` | query | string, uuid | no | Only monitors of this project. |
| `filter[search]` | query | string | no | Case-insensitive text in the label, target, protocol or region. |
| `sort` | query | string | no | Sort by `label`, `created_at`, `last_checked_at` or `state` (down, pending, up, paused, then label). Prefix `-` for descending. Default `-created_at`. |
Responses: `200` Paginated set of `Monitor`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create a monitor
`POST /monitors`
Operation ID: `createMonitor`
The monitor starts checking at once unless `enabled` is `false`. Without `project_id` it
joins the team's default project. Monitors and hosts together are limited by the plan
(`403` `PLAN_LIMIT_REACHED`), and so is the shortest `interval` (`422`). Targets on private
or reserved addresses are refused (`422`).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `label` | string | yes | Name shown in the dashboard, alerts and status pages |
| `protocol` | MonitorProtocol | yes | What a monitor checks, and so the format of its `uri`. \| \| \|---\| \| `https`
An HTTPS request to the URL in `uri`, with a certificate check. \| \| `http`
An HTTP request to the URL in `uri`. \| \| `icmp`
A ping (ICMP echo) to the host in `uri`. \| \| `tcp`
A TCP connect to `host:port`, optionally with a TLS handshake and a banner keyword. \| \| `dns`
A DNS query for a record of the name in `uri`, optionally compared with expected values. \| \| `smtp`
An SMTP greeting from `host:port` (port optional), with STARTTLS by default. \| \| `imap`
An IMAP greeting from `host:port` (port optional), over TLS by default. \| \| `pop3`
A POP3 greeting from `host:port` (port optional), over TLS by default. \| |
| `uri` | string | yes | The target: a URL for `http` and `https`, a host for `icmp`, `host:port` for `tcp`, `host` or `host:port` for mail, a DNS name for `dns`. Private and reserved addresses are refused. For `http` and `https` the scheme is optional: `example.com/health` and `https://example.com/health` give the same monitor, stored without the scheme. A scheme that differs from `protocol` (`http://` for an `https` monitor) is refused with `422` |
| `interval` | MonitorInterval | yes | Seconds between checks. Plans set the shortest interval a team may use. |
| `enabled` | boolean | no | Whether the monitor starts running at once. Default `true` |
| `primary_location` | MonitorLocation | no | A region checks run from. A monitor's primary region decides its uptime and alerts (a failed check is repeated from the same region about 5 seconds later before it is marked down); on the Team plan and up the other regions can also measure its response time. \| \| \|---\| \| `eu`
Europe. \| \| `us`
North America. \| \| `as`
Asia. \| \| `oc`
Oceania. \| |
| `timeout` | integer | no | Seconds before a check times out, 1 to 60. Default 30 |
| `max_redirects` | integer | no | HTTP: redirects to follow, 0 to 10; `null` follows up to 10 |
| `headers` | array of MonitorHeader | no | HTTP: up to 25 headers to send |
| `advanced_settings` | MonitorAdvancedSettingsInput | no | Protocol-specific settings to set. On update, settings you leave out keep their value; send `null` to reset one to its default. |
| `allow_insecure_requests` | boolean | no | HTTPS: accept invalid certificates for the check itself. Default `false` |
| `expected_http_status_code` | string | no | HTTP: status codes that count as up, comma-separated, `*` as a wildcard digit; `null` accepts 2xx and 3xx |
| `certificate_check_enabled` | boolean | no | Check the TLS certificate for validity and expiry (HTTPS, and TCP or mail with TLS). Default `false` |
| `certificate_expiry_threshold_days` | integer | no | Days before the certificate expires that the "expires soon" alert fires, 1 to 90. Default 14 |
| `performance_check_enabled` | boolean | no | Raise alerts for slow responses. Default `false` |
| `performance_hard_threshold` | integer | no | Milliseconds, 1 to 30000: a response slower than this raises an alert |
| `performance_deviation_percentage` | integer | no | Percent, 1 to 500: alert when recent response times are this much above the earlier ones (see the two timeframes) |
| `performance_deviation_timeframe` | integer | no | Minutes of recent checks to compare: 15, 30, 45, 60, 75, 90, 105 or 120. Must be shorter than `performance_deviation_before_timeframe` |
| `performance_deviation_before_timeframe` | integer | no | Minutes before those to compare with, a whole number of hours from 60 to 1440 |
| `regional_performance_enabled` | boolean | no | Also measure response time from the regions other than `primary_location`, every minute (or at the interval, when longer). Shown with the monitor's performance; not used for uptime or alerts. Team plan and up. Default `false` |
| `project_id` | string | no | Project to add the monitor to; default the team's default project, `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the monitor's alerts. Leave out or send `[]` to follow the project's paths, else the team's default path |
Responses: `201` The new monitor.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a monitor
`GET /monitors/{monitor}`
Operation ID: `getMonitor`
Returns the monitor's settings and its latest results: uptime status, response time,
certificate and uptime percentages.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `monitor` | path | string, uuid | yes | Monitor ID. |
Responses: `200` The monitor.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a monitor
`PATCH /monitors/{monitor}`
Operation ID: `updateMonitor`
Changes only the fields you send; `advanced_settings` is merged into the current settings.
Changing `protocol` requires a `uri` in the new protocol's format. The next check uses the
new settings.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `monitor` | path | string, uuid | yes | Monitor ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `label` | string | no | Name shown in the dashboard, alerts and status pages |
| `protocol` | MonitorProtocol | no | What a monitor checks, and so the format of its `uri`. \| \| \|---\| \| `https`
An HTTPS request to the URL in `uri`, with a certificate check. \| \| `http`
An HTTP request to the URL in `uri`. \| \| `icmp`
A ping (ICMP echo) to the host in `uri`. \| \| `tcp`
A TCP connect to `host:port`, optionally with a TLS handshake and a banner keyword. \| \| `dns`
A DNS query for a record of the name in `uri`, optionally compared with expected values. \| \| `smtp`
An SMTP greeting from `host:port` (port optional), with STARTTLS by default. \| \| `imap`
An IMAP greeting from `host:port` (port optional), over TLS by default. \| \| `pop3`
A POP3 greeting from `host:port` (port optional), over TLS by default. \| |
| `uri` | string | no | The target, in the format of the (new) protocol; see `createMonitor`. For `http` and `https` the scheme is optional and must match the protocol; it is stored without the scheme |
| `interval` | MonitorInterval | no | Seconds between checks. Plans set the shortest interval a team may use. |
| `primary_location` | MonitorLocation | no | A region checks run from. A monitor's primary region decides its uptime and alerts (a failed check is repeated from the same region about 5 seconds later before it is marked down); on the Team plan and up the other regions can also measure its response time. \| \| \|---\| \| `eu`
Europe. \| \| `us`
North America. \| \| `as`
Asia. \| \| `oc`
Oceania. \| |
| `timeout` | integer | no | Seconds before a check times out, 1 to 60 |
| `max_redirects` | integer | no | HTTP: redirects to follow, 0 to 10; `null` follows up to 10 |
| `headers` | array of MonitorHeader | no | HTTP: up to 25 headers to send; replaces the current headers |
| `advanced_settings` | MonitorAdvancedSettingsInput | no | Protocol-specific settings to set. On update, settings you leave out keep their value; send `null` to reset one to its default. |
| `allow_insecure_requests` | boolean | no | HTTPS: accept invalid certificates for the check itself |
| `expected_http_status_code` | string | no | HTTP: status codes that count as up; `null` accepts 2xx and 3xx |
| `certificate_check_enabled` | boolean | no | Check the TLS certificate for validity and expiry |
| `certificate_expiry_threshold_days` | integer | no | Days before the certificate expires that the "expires soon" alert fires, 1 to 90 |
| `performance_check_enabled` | boolean | no | Raise alerts for slow responses |
| `performance_hard_threshold` | integer | no | Milliseconds, 1 to 30000: a response slower than this raises an alert |
| `performance_deviation_percentage` | integer | no | Percent, 1 to 500: alert when recent response times are this much above the earlier ones |
| `performance_deviation_timeframe` | integer | no | Minutes of recent checks to compare: 15 to 120 in steps of 15 |
| `performance_deviation_before_timeframe` | integer | no | Minutes before those to compare with: 60 to 1440 in whole hours |
| `regional_performance_enabled` | boolean | no | Also measure response time from the regions other than `primary_location`, every minute (or at the interval, when longer). Shown with the monitor's performance; not used for uptime or alerts. Team plan and up |
| `project_id` | string | no | Project of the monitor; `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the monitor's alerts; replaces the current ones. `[]` follows the project's paths, else the team's default path |
Responses: `200` The updated monitor.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a monitor
`DELETE /monitors/{monitor}`
Operation ID: `deleteMonitor`
Its checks stop at once and it no longer appears in the API or the dashboard. Seven days
later the monitor is deleted permanently with all its data: check history, alerts and
failure snapshots. Until then support can restore it on request. Incidents stay, and status
page components that showed the monitor keep their place without it. Deleting the same
monitor again returns `404`.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `monitor` | path | string, uuid | yes | Monitor ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Pause a monitor
`POST /monitors/{monitor}/pause`
Operation ID: `pauseMonitor`
Stops its checks; ongoing alerts stay as they are. Pausing a paused monitor changes
nothing.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `monitor` | path | string, uuid | yes | Monitor ID. |
Responses: `200` The paused monitor.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `409` `TEAM_MONITORING_PAUSED`: the team's monitoring is paused (no paid plan), so nothing can be resumed until it subscribes.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Resume a monitor
`POST /monitors/{monitor}/resume`
Operation ID: `resumeMonitor`
Starts its checks again, also when the system paused it for the plan limit, if the plan
has room now (`403` `PLAN_LIMIT_REACHED` otherwise). While the team's monitoring is paused
(no paid plan) nothing can be resumed (`409` `TEAM_MONITORING_PAUSED`). Resuming a running
monitor changes nothing.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `monitor` | path | string, uuid | yes | Monitor ID. |
Responses: `200` The running monitor.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `409` `TEAM_MONITORING_PAUSED`: the team's monitoring is paused (no paid plan), so nothing can be resumed until it subscribes.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Hosts
Servers with the Spectate agent, which reports CPU, memory, disk and network metrics every minute. Hosts register themselves when the agent is installed with an install token; the API reads, renames, assigns and deletes them. Hosts and monitors together count against the plan's resource limit.
### List hosts
`GET /hosts`
Operation ID: `listHosts`
Returns the team's hosts, newest first unless you sort.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Hosts per page, 1 to 100. |
| `filter[state]` | query | HostState | no | Only hosts in this state. |
| `filter[project_id]` | query | string, uuid | no | Only hosts of this project. |
| `filter[search]` | query | string | no | Case-insensitive text in the label, host info (hostname, platform, architecture) or agent version. |
| `sort` | query | string | no | Sort by `label`, `last_seen_at` or `created_at`. Prefix `-` for descending. Default `-created_at`. |
Responses: `200` Paginated set of `Host`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a host
`GET /hosts/{host}`
Operation ID: `getHost`
Returns the host with what its agent reports about the system. Metrics themselves are in the
dashboard.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `host` | path | string, uuid | yes | Host ID. |
Responses: `200` The host.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a host
`PATCH /hosts/{host}`
Operation ID: `updateHost`
Changes only the fields you send. The agent stops renaming a host once you set its label.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `host` | path | string, uuid | yes | Host ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `label` | string | no | Name shown in the dashboard and alerts |
| `no_data_alert_minutes` | integer | no | Minutes without data, 2 to 1440, before the "no data received" alert fires; `null` turns it off. A firing alert ends at once when the host is within the new window |
| `project_id` | string | no | Project of the host; `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the host's alerts; replaces the current ones. `[]` follows the project's paths, else the team's default path |
Responses: `200` The updated host.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a host
`DELETE /hosts/{host}`
Operation ID: `deleteHost`
The host disappears from the API and the dashboard, and data its agent still sends is
refused (the agent stops itself). Uninstall the agent on the server too. Seven days later
the host is deleted permanently with all its data: metrics, alerts and metric condition
links. Until then support can restore it on request. Deleting the same host again returns
`404`.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `host` | path | string, uuid | yes | Host ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Host install tokens
Tokens the agent's installer uses to register servers as hosts of the team. One token can register a whole fleet until it expires after 7 days or is revoked; hosts that registered keep reporting either way.
### List install tokens
`GET /host-install-tokens`
Operation ID: `listHostInstallTokens`
Returns the tokens that can still register hosts, newest first. Expired tokens aren't listed.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Tokens per page, 1 to 100. |
Responses: `200` Paginated set of `HostInstallToken`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create an install token
`POST /host-install-tokens`
Operation ID: `createHostInstallToken`
The token is valid for 7 days. Give it to the agent's installer; Hosts → Add host in the
dashboard shows the full command for each platform.
Responses: `201` The new install token.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Revoke an install token
`DELETE /host-install-tokens/{token}`
Operation ID: `deleteHostInstallToken`
No new hosts can register with it. Hosts that registered with it keep reporting.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `token` | path | string, uuid | yes | Install token ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Metric conditions
Alert rules for host metrics, such as "disk usage above 90% for 10 minutes". A condition applies to the hosts it names and to every host of the projects it names; when it holds for its duration, it raises an alert with its severity on the host.
### List metric conditions
`GET /metric-conditions`
Operation ID: `listMetricConditions`
Returns the team's metric conditions, oldest first.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `filter[host_id]` | query | string, uuid | no | Only conditions attached to this host directly (not through its project). |
| `filter[project_id]` | query | string, uuid | no | Only conditions attached to this project. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Conditions per page, 1 to 100. |
Responses: `200` Paginated set of `MetricCondition`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create a metric condition
`POST /metric-conditions`
Operation ID: `createMetricCondition`
Hosts and projects must belong to the team (`422` otherwise). The condition is checked on
the next report of each host it applies to.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `metric` | MetricPoint | yes | A host metric the agent reports. `cpu_usage`, `memory_usage`, `disk_usage`, `load_average`, `network_in` and `network_out` are the summaries the dashboard charts; the `system.*` metrics are the agent's raw values. |
| `condition` | MetricCondition | yes | An alert rule for host metrics, for example "CPU usage above 90% for 5 minutes". It applies to its hosts and to every host of its projects. |
| `threshold` | number | yes | Compared with the metric's value as the agent reports it, in the unit the host's charts show |
| `severity` | Severity | yes | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `duration_minutes` | integer | no | Minutes, 0 to 60, the condition must hold before the alert fires. Default 0: on the first breach |
| `host_ids` | array of string, uuid | no | Hosts of the team it applies to |
| `project_ids` | array of string, uuid | no | Projects of the team whose hosts it applies to |
Responses: `201` The new metric condition.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a metric condition
`GET /metric-conditions/{condition}`
Operation ID: `getMetricCondition`
Returns the condition with the hosts and projects it applies to.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `condition` | path | string, uuid | yes | Metric condition ID. |
Responses: `200` The metric condition.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a metric condition
`DELETE /metric-conditions/{condition}`
Operation ID: `deleteMetricCondition`
It's no longer checked from the hosts' next report.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `condition` | path | string, uuid | yes | Metric condition ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Domains
Domain registrations Spectate watches at their registry (RDAP or WHOIS): it alerts before a domain expires and, optionally, when its registrar, nameservers or DNSSEC keys change. The plan limits the number of domains.
### List domains
`GET /domains`
Operation ID: `listDomains`
Returns the team's monitored domains, newest first unless you sort.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Domains per page, 1 to 100. |
| `filter[view]` | query | DomainView | no | Only domains in this view. |
| `filter[project_id]` | query | string, uuid | no | Only domains of this project. |
| `filter[search]` | query | string | no | Case-insensitive text in the name, registrar or nameservers. |
| `sort` | query | string | no | Sort by `name`, `expires_at` (unknown expiry last) or `created_at`. Prefix `-` for descending. Default `-created_at`. |
Responses: `200` Paginated set of `Domain`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Add a domain
`POST /domains`
Operation ID: `createDomain`
Starts monitoring it and looks it up at its registry right away; the registry fields fill
in within a minute. Without `project_id` it joins the team's default project. The plan
limits the number of domains (`403` `PLAN_LIMIT_REACHED`).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | The registered domain, without `www.` or a path; internationalised names may be in Unicode or punycode |
| `enabled` | boolean | no | Whether to start monitoring at once. Default `true` |
| `expiry_threshold_days` | integer | no | Days before expiry, 1 to 365, that the "expires soon" alert fires. Default 30 |
| `alert_on_registry_changes` | boolean | no | Raise an alert when the registrar, nameservers or DNSSEC keys change. Default `true` |
| `project_id` | string | no | Project to add the domain to; default the team's default project, `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the domain's alerts. Leave out or send `[]` to follow the project's paths, else the team's default path |
Responses: `201` The new domain.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a domain
`GET /domains/{domain}`
Operation ID: `getDomain`
Returns the domain with what its registry reported at the last check.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string, uuid | yes | Domain ID. |
Responses: `200` The domain.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a domain
`PATCH /domains/{domain}`
Operation ID: `updateDomain`
Changes only the fields you send. A new `name` forgets the old registration data and is
looked up at once. Resuming (`enabled: true`) goes through the plan's domain limit.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string, uuid | yes | Domain ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Another domain to monitor instead; its registry data is looked up again |
| `enabled` | boolean | no | Pause (`false`) or resume (`true`) monitoring. Resuming goes through the plan's domain limit |
| `expiry_threshold_days` | integer | no | Days before expiry, 1 to 365, that the "expires soon" alert fires |
| `alert_on_registry_changes` | boolean | no | Raise an alert when the registrar, nameservers or DNSSEC keys change |
| `project_id` | string | no | Project of the domain; `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the domain's alerts; replaces the current ones |
Responses: `200` The updated domain.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `409` `TEAM_MONITORING_PAUSED`: the team's monitoring is paused (no paid plan), so nothing can be resumed until it subscribes.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a domain
`DELETE /domains/{domain}`
Operation ID: `deleteDomain`
Monitoring stops and the domain no longer appears in the API or the dashboard. Seven days
later the domain is deleted permanently with all its data, alerts included. Until then
support can restore it on request. Nothing changes at the registrar. Deleting the same
domain again returns `404`.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `domain` | path | string, uuid | yes | Domain ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Projects
Projects group monitors and hosts, for example per product or environment, and give them shared escalation paths. Every team has a default project that new monitors and hosts join when no project is given.
### List projects
`GET /projects`
Operation ID: `listProjects`
Returns the team's projects, the default project first, then by name.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Projects per page, 1 to 100. |
Responses: `200` Paginated set of `Project`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create a project
`POST /projects`
Operation ID: `createProject`
Plans limit the number of projects: over the limit the request fails with `403`
`PLAN_LIMIT_REACHED`. Escalation paths must belong to the team (`422` otherwise).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Project name |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for alerts of the project's monitors and hosts. Leave out for none |
Responses: `201` The new project.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a project
`GET /projects/{project}`
Operation ID: `getProject`
Returns the project with the escalation paths its monitors and hosts use by default.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `project` | path | string, uuid | yes | Project ID. |
Responses: `200` The project.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a project
`PATCH /projects/{project}`
Operation ID: `updateProject`
Changes only the fields you send. `escalation_path_ids` replaces the project's paths;
send `[]` to remove them all.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `project` | path | string, uuid | yes | Project ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Project name |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for alerts of the project's monitors and hosts; replaces the current list. Send `[]` for none |
Responses: `200` The updated project.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a project
`DELETE /projects/{project}`
Operation ID: `deleteProject`
Its monitors and hosts are kept, without a project; they follow the team's default
escalation path until you give them another. The default project can't be deleted
(`409` `DEFAULT_PROJECT`).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `project` | path | string, uuid | yes | Project ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `409` `DEFAULT_PROJECT`: the team's default project can't be deleted.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Channels
Where alerts are delivered: email, Slack, Discord, Microsoft Teams, Telegram, webhooks, Pushover, SMS and voice calls. Escalation paths send to channels. A channel that keeps failing is turned off automatically; a successful test turns it back on.
### List channels
`GET /channels`
Operation ID: `listChannels`
Returns the team's channels, by name.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `filter[type]` | query | ChannelType | no | Only channels of this type. |
| `filter[enabled]` | query | boolean | no | Only enabled (`true`) or disabled (`false`) channels. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Channels per page, 1 to 100. |
Responses: `200` Paginated set of `Channel`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create a channel
`POST /channels`
Operation ID: `createChannel`
Send `type` and the settings object of that type, for example `type: "email"` with
`email: {address}`. Webhook URLs must be public addresses. Slack channels post through a
Slack workspace connected under Integrations in the dashboard, Telegram channels are
connected there too. Create channels before the escalation paths that use them.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name shown in escalation paths |
| `type` | ChannelType | yes | Where the channel delivers; `telegram` can't be created through the API |
| `enabled` | boolean | no | Whether it delivers from the start. Default `true` |
| `email` | ChannelEmail | no | Where an `email` channel sends. |
| `slack` | ChannelSlackInput | no | Where a `slack` channel posts. Connect the Slack workspace under Integrations in the dashboard first; the installation's ID is in the Slack integration. |
| `discord` | ChannelWebhookUrlInput | no | The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned. |
| `microsoft_teams` | ChannelWebhookUrlInput | no | The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned. |
| `webhook` | ChannelWebhookInput | no | Where a `webhook` channel posts its JSON. The URL and header values are write-only. |
| `pushover` | ChannelPushoverInput | no | Who a `pushover` channel notifies, and with which Pushover application. |
| `sms` | ChannelPhone | no | The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits. |
| `voice` | ChannelPhone | no | The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits. |
Responses: `201` The new channel.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a channel
`GET /channels/{channel}`
Operation ID: `getChannel`
Returns the channel with its delivery health. Secrets in its settings are never returned.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `channel` | path | string, uuid | yes | Channel ID. |
Responses: `200` The channel.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a channel
`PATCH /channels/{channel}`
Operation ID: `updateChannel`
Changes only the fields you send. The settings object of the channel's type replaces the
current settings, including secrets: send them again. Other types' objects are refused
(`422`); create a new channel to change the type. Enabling clears an automatic disable.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `channel` | path | string, uuid | yes | Channel ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name shown in escalation paths |
| `enabled` | boolean | no | Turn delivery on or off. Turning it on clears an automatic disable and its failure count |
| `email` | ChannelEmail | no | Where an `email` channel sends. |
| `slack` | ChannelSlackInput | no | Where a `slack` channel posts. Connect the Slack workspace under Integrations in the dashboard first; the installation's ID is in the Slack integration. |
| `discord` | ChannelWebhookUrlInput | no | The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned. |
| `microsoft_teams` | ChannelWebhookUrlInput | no | The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned. |
| `webhook` | ChannelWebhookInput | no | Where a `webhook` channel posts its JSON. The URL and header values are write-only. |
| `pushover` | ChannelPushoverInput | no | Who a `pushover` channel notifies, and with which Pushover application. |
| `sms` | ChannelPhone | no | The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits. |
| `voice` | ChannelPhone | no | The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits. |
Responses: `200` The updated channel.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a channel
`DELETE /channels/{channel}`
Operation ID: `deleteChannel`
Escalation steps that sent to it stay, and are skipped until you point them at another
channel. Notifications already sent aren't affected.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `channel` | path | string, uuid | yes | Channel ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Send a test notification
`POST /channels/{channel}/test`
Operation ID: `testChannel`
Delivers a test through the channel right away and returns when it was accepted. A
successful test clears the failure count and, with `enable`, turns a disabled channel back
on. A failed test (`422` `CHANNEL_TEST_FAILED`) doesn't count towards turning it off. SMS
and voice tests use the team's notification credits (`422` `NOTIFICATION_CREDITS_EXHAUSTED`
without them). Limited to 10 tests a minute per token.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `channel` | path | string, uuid | yes | Channel ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `enable` | boolean | no | Enable the channel again when the test succeeds, also after Spectate turned it off. Default `false` |
Responses: `200` The test was delivered.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `CHANNEL_TEST_FAILED`: the test couldn't be delivered; the message has the delivery error, `details.permanent` whether the settings are wrong. `NOTIFICATION_CREDITS_EXHAUSTED`: the team has no SMS and voice credits left; buy more under Billing.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Escalation paths
What happens when an alert fires: notify channels, page whoever is on call, declare an incident, wait, or branch on severity, source, labels or working hours, step by step until someone acknowledges the alert. Paths are trees: a `branch` step ends its list of steps and continues in its `then` and `else` steps. The dashboard shows the same paths in its flow editor.
### List escalation paths
`GET /escalation-paths`
Operation ID: `listEscalationPaths`
Returns the team's paths with their steps, the default path first, then by name.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Paths per page, 1 to 100. |
Responses: `200` Paginated set of `EscalationPath`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create an escalation path
`POST /escalation-paths`
Operation ID: `createEscalationPath`
Channels and schedules must belong to the team; a `branch` ends its list of steps (`422`
with the step's position, for example `steps.1.then.0.channel_id`). Paging the person on
call is part of the Team plan and up, and so are paths besides the default one (`403`
`PLAN_LIMIT_REACHED`).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name, up to 255 characters |
| `description` | string | no | What the path is for, up to 1000 characters |
| `enabled` | boolean | no | Whether alerts follow the path. Default `true` |
| `is_default` | boolean | no | Make it the team's default path; the current default stops being one. Default `false` |
| `working_hours` | WorkingHoursInput | no | |
| `steps` | array of EscalationStepInput | no | The steps, in order, up to 99 in total. Leave out or `[]` for a path that does nothing yet |
Responses: `201` The new escalation path.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get an escalation path
`GET /escalation-paths/{path}`
Operation ID: `getEscalationPath`
Returns the path with its steps as a tree and the problems that keep it from delivering.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `path` | path | string, uuid | yes | Escalation path ID. |
Responses: `200` The escalation path.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update an escalation path
`PATCH /escalation-paths/{path}`
Operation ID: `updateEscalationPath`
Changes only the fields you send; `steps` replaces all steps. Alerts that are already
escalating keep the steps they started with. Making a path the default takes that from the
current default path.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `path` | path | string, uuid | yes | Escalation path ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name, up to 255 characters |
| `description` | string | no | What the path is for, up to 1000 characters |
| `enabled` | boolean | no | Whether alerts follow the path |
| `is_default` | boolean | no | Make it the team's default path (the current default stops being one), or not |
| `working_hours` | WorkingHoursInput | no | |
| `steps` | array of EscalationStepInput | no | All steps, in order, up to 99 in total; replaces the current steps |
Responses: `200` The updated escalation path.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an escalation path
`DELETE /escalation-paths/{path}`
Operation ID: `deleteEscalationPath`
Monitors, hosts, domains, projects and alert sources that used it fall back to their
project's paths or the team's default path. Alerts that are escalating on it stop.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `path` | path | string, uuid | yes | Escalation path ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Alert sources
External tools that fire and resolve alerts in Spectate: Prometheus Alertmanager, Grafana, Sentry, email, or your own scripts through a webhook. Each source has its own secret URL (and email address); its alerts follow its escalation paths.
### List alert sources
`GET /alert-sources`
Operation ID: `listAlertSources`
Returns the team's alert sources, by name.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `filter[type]` | query | AlertSourceProvider | no | Only sources of this tool. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Sources per page, 1 to 100. |
Responses: `200` Paginated set of `AlertSource`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create an alert source
`POST /alert-sources`
Operation ID: `createAlertSource`
Returns the source with its `webhook_url` (and `email_address` for `email`) to set up in the
tool. Email sources resolve alerts after an hour without a repeat unless
`auto_resolve_minutes` says otherwise: mail has no "resolved".
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name shown on its alerts, up to 255 characters |
| `type` | AlertSourceProvider | yes | The external tool behind an alert source; decides how its requests are read. \| \| \|---\| \| `webhook`
Spectate's own JSON format, for scripts, CI and anything that can call a URL. \| \| `email`
Emails to the source's own address (subject becomes the alert). \| \| `alertmanager`
Prometheus Alertmanager `webhook_configs`. \| \| `grafana`
Grafana Alerting webhook contact point (Alertmanager format plus Grafana links). \| \| `sentry`
Sentry internal integration webhooks (SaaS and self-hosted), or the legacy WebHooks plugin. \| |
| `default_severity` | Severity | no | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `auto_resolve_minutes` | integer | no | Minutes, 5 to 10080, after which an alert the tool stopped repeating resolves; `null` keeps it until resolved. Default `null`, or 60 for `email` sources |
| `secret` | string | no | Signing secret the tool uses: Sentry client secret, Grafana HMAC secret or Alertmanager bearer token. Write-only |
| `settings` | AlertSourceSettingsInput | no | Settings to set; settings you leave out keep their value. |
| `project_id` | string | no | Project whose escalation paths apply when the source has none of its own |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the source's alerts |
Responses: `201` The new alert source.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get an alert source
`GET /alert-sources/{source}`
Operation ID: `getAlertSource`
Returns the source with its URL and how many of its alerts are firing.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `source` | path | string, uuid | yes | Alert source ID. |
Responses: `200` The alert source.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update an alert source
`PATCH /alert-sources/{source}`
Operation ID: `updateAlertSource`
Changes only the fields you send; `settings` merge into the current settings.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `source` | path | string, uuid | yes | Alert source ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name shown on its alerts |
| `enabled` | boolean | no | Whether requests fire alerts |
| `default_severity` | Severity | no | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `auto_resolve_minutes` | integer | no | Minutes, 5 to 10080, after which an alert the tool stopped repeating resolves; `null` keeps it until resolved |
| `secret` | string | no | Signing secret; an empty string or `null` removes it. Write-only |
| `settings` | AlertSourceSettingsInput | no | Settings to set; settings you leave out keep their value. |
| `project_id` | string | no | Project whose escalation paths apply; `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the source's alerts; replaces the current ones |
Responses: `200` The updated alert source.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an alert source
`DELETE /alert-sources/{source}`
Operation ID: `deleteAlertSource`
Its firing alerts are resolved first; its URL and address stop working at once.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `source` | path | string, uuid | yes | Alert source ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Rotate the source's URL
`POST /alert-sources/{source}/rotate-token`
Operation ID: `rotateAlertSourceToken`
Gives the source a new secret `webhook_url` (and `email_address`); the old ones stop working
at once, so update the tool right after.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `source` | path | string, uuid | yes | Alert source ID. |
Responses: `200` The source with its new URL.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Fire a test alert
`POST /alert-sources/{source}/test`
Operation ID: `testAlertSource`
Fires an alert on the source that escalates like a real one (it notifies people) and
resolves itself after a few minutes. Returns the event it made.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `source` | path | string, uuid | yes | Alert source ID. |
Responses: `200` The test event.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### List a source's events
`GET /alert-sources/{source}/events`
Operation ID: `listAlertSourceEvents`
Returns the requests the source received in the last 7 days, newest first, with what each
did. Use it to check that a tool reaches Spectate.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `source` | path | string, uuid | yes | Alert source ID. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Events per page, 1 to 100. |
Responses: `200` Paginated set of `AlertSourceEvent`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Alerts
Problems Spectate or an alert source detected. An alert escalates along its escalation path until someone acknowledges it, and resolves on its own when the problem is over, or when someone resolves it by hand. Resolved alerts can be deleted. Alerts can lead to incidents.
### List alerts
`GET /alerts`
Operation ID: `listAlerts`
Returns the team's alerts, most recently fired first unless you sort.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Alerts per page, 1 to 100. |
| `filter[status]` | query | AlertStatus | no | Only firing or resolved alerts. |
| `filter[severity]` | query | Severity | no | Only alerts of this severity. |
| `filter[source_type]` | query | AlertSourceType | no | Only alerts raised by this kind of check or integration. |
| `filter[resource_id]` | query | string, uuid | no | Only alerts about this resource (a monitor, host, domain, status page or alert source ID). |
| `filter[acknowledged]` | query | boolean | no | Only acknowledged (`true`) or unacknowledged (`false`) alerts. |
| `sort` | query | string | no | Sort by `fired_at`, `resolved_at`, `severity` or `status`. Prefix `-` for descending. Default `-fired_at`. |
Responses: `200` Paginated set of `Alert`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get an alert
`GET /alerts/{alert}`
Operation ID: `getAlert`
Returns the alert with the resource it's about and who acknowledged it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `alert` | path | string, uuid | yes | Alert ID. |
Responses: `200` The alert.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an alert
`DELETE /alerts/{alert}`
Operation ID: `deleteAlert`
Deletes a resolved alert for good, with its escalation history. Incidents and status page
incidents it led to stay, without the link to it; messages already posted in Slack or Telegram
stay in their channels. A firing alert can't be deleted: resolve it first.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `alert` | path | string, uuid | yes | Alert ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `409` `ALERT_FIRING`: the alert is still firing; resolve it before deleting it.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Acknowledge an alert
`POST /alerts/{alert}/acknowledge`
Operation ID: `acknowledgeAlert`
Stops its escalation: nobody else is notified. The alert keeps firing until the problem is
over. The dashboard, Slack and Telegram show it as acknowledged by the API token.
Acknowledging an acknowledged or resolved alert changes nothing.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `alert` | path | string, uuid | yes | Alert ID. |
Responses: `200` The acknowledged alert.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Resolve an alert
`POST /alerts/{alert}/resolve`
Operation ID: `resolveAlert`
Ends the alert by hand, as if its problem were over: its escalation stops, the channels and
on-call members it notified hear that it resolved, Slack and Telegram show it as resolved by the
API token, and status pages automated from an uptime alert show the monitor as recovered. Use
it for false alarms, or for alerts whose source can't tell they're over.
If the problem is still there, the source fires a new alert at its next check (a monitor that
is still down, a host metric still over its limit). Resolving a resolved alert changes nothing.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `alert` | path | string, uuid | yes | Alert ID. |
Responses: `200` The resolved alert.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## On-call
Who gets paged when an escalation path's `notify_on_call` step runs. A schedule has rotation layers, where members take turns, and overrides, where someone covers for a while. Overrides win over every layer; where layers overlap, the top one wins. On-call is part of the Team plan and up.
### List on-call schedules
`GET /on-call-schedules`
Operation ID: `listOnCallSchedules`
Returns the team's schedules, by name, each with who is on call now and the next handoff.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Schedules per page, 1 to 100. |
Responses: `200` Paginated set of `OnCallSchedule`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create an on-call schedule
`POST /on-call-schedules`
Operation ID: `createOnCallSchedule`
The schedule starts empty: nobody is on call until you add a rotation layer. Needs a plan
with on-call (`403` `PLAN_FEATURE_UNAVAILABLE`).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name, up to 255 characters |
| `description` | string | no | What the schedule covers, up to 1000 characters |
| `timezone` | string | yes | IANA time zone the rotations' dates, handoffs and restrictions are in |
Responses: `201` The new schedule.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_FEATURE_UNAVAILABLE`: the plan doesn't include this feature; `details.feature` names it. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get an on-call schedule
`GET /on-call-schedules/{schedule}`
Operation ID: `getOnCallSchedule`
Returns the schedule with its rotation layers, upcoming overrides, who is on call now and
the escalation paths that page it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
Responses: `200` The schedule.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update an on-call schedule
`PATCH /on-call-schedules/{schedule}`
Operation ID: `updateOnCallSchedule`
Changes only the fields you send.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name |
| `description` | string | no | What the schedule covers |
| `timezone` | string | no | IANA time zone. Rotations keep their dates and wall-clock handoff times in the new zone |
Responses: `200` The updated schedule.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an on-call schedule
`DELETE /on-call-schedules/{schedule}`
Operation ID: `deleteOnCallSchedule`
Deletes its rotations and overrides. Escalation steps that paged it stay, and are skipped
until you point them at another schedule.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a schedule's timeline
`GET /on-call-schedules/{schedule}/timeline`
Operation ID: `getOnCallTimeline`
Who is on call between `from` and `to` (default: now and 14 days later; at most 62 days):
each layer's shifts, the overrides, and the result, which is who actually gets paged.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
| `from` | query | string, date-time | no | Start of the window, ISO 8601. Default now. |
| `to` | query | string, date-time | no | End of the window, ISO 8601, at most 62 days after `from`. Default 14 days after `from`. |
Responses: `200` The timeline of the window.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get who is on call
`GET /on-call-schedules/{schedule}/now`
Operation ID: `getOnCallNow`
Who is on call at `at` (default now). `shift` is `null` during a gap.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
| `at` | query | string, date-time | no | The moment, ISO 8601. Default now. |
Responses: `200` Who is on call at that moment.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Add a rotation layer
`POST /on-call-schedules/{schedule}/rotations`
Operation ID: `createOnCallRotation`
New layers go below the existing ones unless `position` is given. Participants must be
members of the team (`422`).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name, up to 255 characters |
| `position` | integer | no | Layer order, 0 for the top. Default: below the existing layers |
| `shift_unit` | OnCallShiftUnit | yes | The unit of a rotation's shift length. \| \| \|---\| \| `hours`
Absolute hours: shifts keep their length across DST changes. \| \| `days`
Calendar days in the schedule's time zone: the handoff stays at the same wall-clock time. \| \| `weeks`
Calendar weeks in the schedule's time zone. \| |
| `shift_length` | integer | yes | Shift length in `shift_unit`s: up to 720 hours, 90 days or 12 weeks |
| `start_date` | string, date | yes | The first handoff's date in the schedule's time zone; turns are counted from it |
| `handoff_time` | string | yes | Handoff time as `HH:MM` in the schedule's time zone |
| `restrictions` | OnCallRestrictionsInput | no | |
| `participant_ids` | array of string, uuid | no | 1 to 50 team members taking turns, in order |
Responses: `201` The new rotation layer.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a rotation layer
`PATCH /on-call-schedules/{schedule}/rotations/{rotation}`
Operation ID: `updateOnCallRotation`
Changes only the fields you send; `participant_ids` replaces the members taking turns.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
| `rotation` | path | string, uuid | yes | Rotation ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name |
| `position` | integer | no | Move the layer to this position, 0 for the top; the others shift |
| `shift_unit` | OnCallShiftUnit | no | The unit of a rotation's shift length. \| \| \|---\| \| `hours`
Absolute hours: shifts keep their length across DST changes. \| \| `days`
Calendar days in the schedule's time zone: the handoff stays at the same wall-clock time. \| \| `weeks`
Calendar weeks in the schedule's time zone. \| |
| `shift_length` | integer | no | Shift length in `shift_unit`s |
| `start_date` | string, date | no | The first handoff's date |
| `handoff_time` | string | no | Handoff time as `HH:MM` |
| `restrictions` | OnCallRestrictionsInput | no | |
| `participant_ids` | array of string, uuid | no | Members taking turns, in order; replaces the current ones |
Responses: `200` The updated rotation layer.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a rotation layer
`DELETE /on-call-schedules/{schedule}/rotations/{rotation}`
Operation ID: `deleteOnCallRotation`
The layers below move up.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
| `rotation` | path | string, uuid | yes | Rotation ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Add an override
`POST /on-call-schedules/{schedule}/overrides`
Operation ID: `createOnCallOverride`
Has a team member cover the schedule from `starts_at` to `ends_at`, at most 90 days.
Overrides win over every layer; where overrides overlap, the newest wins.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `member_id` | string, uuid | yes | The member who covers |
| `starts_at` | string, date-time | yes | From when, as an ISO 8601 date and time |
| `ends_at` | string, date-time | yes | Until when; after `starts_at` |
| `note` | string | no | Why, for the team; up to 500 characters |
Responses: `201` The new override.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an override
`DELETE /on-call-schedules/{schedule}/overrides/{override}`
Operation ID: `deleteOnCallOverride`
The rotations decide again for its time.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `schedule` | path | string, uuid | yes | Schedule ID. |
| `override` | path | string, uuid | yes | Override ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Incidents
Problems that affect customers, worked on by the team: declare one, post updates as you learn more, assign a commander and a communications lead, resolve it and write the postmortem. Changes show in the incident's Slack channel and timeline, named after the API token that made them. Publish to status pages with `publishIncidentStatusPageUpdate`.
### List incidents
`GET /incidents`
Operation ID: `listIncidents`
Returns the team's incidents, most recently started first unless you sort.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Incidents per page, 1 to 100. |
| `filter[status]` | query | IncidentStatus | no | Only incidents with this status. |
| `filter[severity]` | query | Severity | no | Only incidents of this severity. |
| `filter[title]` | query | string | no | Case-insensitive text in the title. |
| `sort` | query | string | no | Sort by `started_at`, `created_at`, `severity`, `status` or `title`. Prefix `-` for descending. Default `-started_at`. |
Responses: `200` Paginated set of `Incident`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Declare an incident
`POST /incidents`
Operation ID: `createIncident`
It starts `investigating`. With Slack connected it's announced there like an incident
declared in the dashboard, with its own channel when the Slack settings say so.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | What's going on, up to 255 characters |
| `severity` | Severity | yes | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `summary` | string | no | More about it, in Markdown |
Responses: `201` The new incident.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get an incident
`GET /incidents/{incident}`
Operation ID: `getIncident`
Returns the incident with its roles and the alert that opened it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Responses: `200` The incident.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update an incident
`PATCH /incidents/{incident}`
Operation ID: `updateIncident`
Changes only the fields you send. Status and severity changes are announced like in the
dashboard. To share what's known, post an update instead.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | no | What's going on |
| `summary` | string | no | More about it, in Markdown |
| `severity` | Severity | no | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `status` | IncidentStatus | no | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
Responses: `200` The updated incident.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an incident
`DELETE /incidents/{incident}`
Operation ID: `deleteIncident`
Deletes it for good, open or resolved, with its updates, role assignments and postmortem.
Nothing else goes with it: the alert that opened it keeps firing or stays resolved, status
page incidents published from it stay on their pages, and its Slack channel isn't archived.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Acknowledge an incident
`POST /incidents/{incident}/acknowledge`
Operation ID: `acknowledgeIncident`
Moves it to `identified` and stops the escalation of the alert that opened it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Responses: `200` The acknowledged incident.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Resolve an incident
`POST /incidents/{incident}/resolve`
Operation ID: `resolveIncident`
Ends it, with an optional closing update. Its status page incidents stay as they are:
resolve those with a status page update.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | no | A closing update, in Markdown; leave out for none |
Responses: `200` The resolved incident.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### List an incident's updates
`GET /incidents/{incident}/updates`
Operation ID: `listIncidentUpdates`
Returns the updates, newest first.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Updates per page, 1 to 100. |
Responses: `200` Paginated set of `IncidentUpdate`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Post an incident update
`POST /incidents/{incident}/updates`
Operation ID: `createIncidentUpdate`
Adds what's known now to the timeline, optionally with a new status, and shares it like an
update from the dashboard.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `body` | string | yes | What's known now, in Markdown |
| `status` | IncidentStatus | no | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
Responses: `201` The posted update.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get an incident's timeline
`GET /incidents/{incident}/timeline`
Operation ID: `listIncidentTimeline`
Everything that happened, newest first: declaring, updates, status and severity changes,
roles, acknowledging and resolving, with who did it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Entries per page, 1 to 100. |
Responses: `200` Paginated set of `IncidentTimelineEntry`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Assign an incident role
`PUT /incidents/{incident}/roles/{role}`
Operation ID: `assignIncidentRole`
Gives the role to a member of the team, replacing whoever had it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
| `role` | path | IncidentRole | yes | The role. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `member_id` | string, uuid | yes | The member who takes the role; they replace whoever had it |
Responses: `200` The incident with its roles.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Remove an incident role
`DELETE /incidents/{incident}/roles/{role}`
Operation ID: `removeIncidentRole`
Nobody has the role afterwards. Removing a role nobody has changes nothing.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
| `role` | path | IncidentRole | yes | The role. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get an incident's postmortem
`GET /incidents/{incident}/postmortem`
Operation ID: `getIncidentPostmortem`
`postmortem` is `null` until one is written.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Responses: `200` The postmortem, if any.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Write an incident's postmortem
`PUT /incidents/{incident}/postmortem`
Operation ID: `saveIncidentPostmortem`
Creates the postmortem, or replaces its content.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string | yes | The whole postmortem, in Markdown; replaces the current one |
| `published` | boolean | no | Mark it as published (final), or as a draft again. Leave out to keep its state |
Responses: `200` The saved postmortem.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Publish to a status page
`POST /incidents/{incident}/status-page-updates`
Operation ID: `publishIncidentStatusPageUpdate`
Posts an update of this incident on one of the team's status pages, creating the public
incident there the first time (`201`; later updates answer `200`). The public incident
takes the incident's title. `affected_components` are the impacts as of `published_at`
(default now); leave the field out to keep them. Confirmed subscribers are emailed
unless `notify_subscribers` is `false`. Needs both `incidents:write` and
`status-pages:write`.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `incident` | path | string, uuid | yes | Incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `status_page_id` | string, uuid | yes | The status page to publish on |
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | yes | The message visitors read, in Markdown |
| `impact` | ImpactLevel | no | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `published_at` | string | no | When it happened, now or in the past (default now) |
| `affected_components` | array of StatusPageAffectedComponentInput | no | The components it affects as of `published_at`, with their impact; components left out are no longer affected. Leave out to keep the impacts as they are; send `[]` for none. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers about the update (default `true`). `false` changes the page without emails |
Responses: `200` The public incident, updated.; `201` The public incident, created by this update.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Status pages
Public pages that show the status of your components, your incidents and scheduled maintenance, on `.spectate.page` or your own domain. Visitors can subscribe to updates by email and report problems. The plan limits the number of pages; private pages, password protection and custom domains depend on the plan too. Logos and the favicon are uploaded in the dashboard.
### List status pages
`GET /status-pages`
Operation ID: `listStatusPages`
Returns the team's status pages, by name unless you sort.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Status pages per page, 1 to 100. |
| `filter[visibility]` | query | StatusPageVisibility | no | Only pages with this visibility. |
| `filter[search]` | query | string | no | Case-insensitive text in the name, slug or custom domain. |
| `sort` | query | string | no | Sort by `name` or `created_at`. Prefix `-` for descending. Default `name`. |
Responses: `200` Paginated set of `StatusPage`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create a status page
`POST /status-pages`
Operation ID: `createStatusPage`
Creates the page on `.spectate.page`; without a `slug` it is derived from the name.
Add components next (`createStatusPageComponent`). The plan limits the number of pages
(`403` `PLAN_LIMIT_REACHED`); private pages, password protection and custom domains need a
plan that includes them (`403` `PLAN_FEATURE_UNAVAILABLE`). Escalation paths must belong to
the team.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name, shown as the page title |
| `slug` | string | no | The page's subdomain under spectate.page: lowercase letters, digits and dashes. Leave out to derive it from the name |
| `visibility` | StatusPageVisibility | no | Who can open a status page. \| \| \|---\| \| `public`
Anyone. \| \| `private`
Visitors with the access link, or the password when the page has one. Part of the Team plan and up. \| |
| `custom_domain` | string | no | Your own domain for the page, such as `status.acme.com`; `null` for none. Part of paid plans (`403` `PLAN_FEATURE_UNAVAILABLE` otherwise). A new domain needs to be verified again: see `custom_domain_verification` and `verifyStatusPageCustomDomain` |
| `password_protected` | boolean | no | Let visitors of a private page also get in with a password. Part of paid plans (`403` `PLAN_FEATURE_UNAVAILABLE` otherwise); turning it on needs a `password` unless the page has one |
| `password` | string | no | The password, 8 to 255 characters. Write-only; leave out or send `null` to keep the current one |
| `language` | StatusPageLanguage | no | Languages of the public status page chrome and the subscriber emails. Customer-written content (names, incident titles and updates) is never translated. \| \| \|---\| \| `en`
English. \| \| `nl`
Dutch. \| \| `de`
German. \| \| `fr`
French. \| \| `es`
Spanish. \| \| `it`
Italian. \| |
| `match_browser_language` | boolean | no | Give visitors their browser's language when it is supported |
| `theme` | StatusPageThemeInput | no | Changes to how a status page looks. Settings left out keep their value, also inside `light`, `dark` and `display`; `null` goes back to the default. Logos and the favicon are uploaded in the dashboard. |
| `collapsed_groups` | array of string | no | Component groups that start collapsed; replaces the current list |
| `automation_enabled` | boolean | no | Monitor automation: when a monitor linked to a component goes down, open an incident "{component} is down" (major outage), and resolve it when the monitor recovers |
| `automation_down_message` | string | no | Posted when a linked monitor goes down, up to 5000 characters; `{component}` and `{status_page}` are filled in. `null` for a default message |
| `automation_recovered_message` | string | no | Posted when the monitor recovers, up to 5000 characters; `null` for a default message |
| `issue_reports_enabled` | boolean | no | Let visitors report problems from the page |
| `issue_reports_show_on_page` | boolean | no | While reports are above the threshold, say on the page that users are reporting issues |
| `issue_reports_alerts_enabled` | boolean | no | Fire an alert when reports reach the threshold |
| `issue_reports_threshold` | integer | no | Reports within `issue_reports_window_minutes` that count as above the threshold, 1 to 1000 |
| `issue_reports_window_minutes` | integer | no | The window for the threshold, in minutes, 1 to 1440 |
| `traffic_alerts_enabled` | boolean | no | Alert when views reach `traffic_alert_multiplier` times the usual views for the time of day |
| `traffic_alert_multiplier` | integer | no | How many times the usual views alert, 2 to 100 |
| `traffic_alert_min_views` | integer | no | Fewer views than this in 15 minutes never alert, 10 to 1000000 |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the page's alerts (issue reports and traffic spikes); replaces the current ones. Empty for the team's default path |
Responses: `201` The new status page.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `PLAN_FEATURE_UNAVAILABLE`: the plan doesn't include this feature; `details.feature` names it. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a status page
`GET /status-pages/{statusPage}`
Operation ID: `getStatusPage`
Returns the page with its settings and headline status. Its components, incidents and
maintenance have their own lists.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
Responses: `200` The status page.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a status page
`PATCH /status-pages/{statusPage}`
Operation ID: `updateStatusPage`
Changes only the settings you send; inside `theme`, also only the keys you send. A new
`slug` moves the page: the old address stops working. A new `custom_domain` needs to be
verified again before visitors use it. Turning off issue reports or traffic alerts ends the
alerts they fired. Private pages, password protection and custom domains need a plan that
includes them (`403` `PLAN_FEATURE_UNAVAILABLE`); a page that is private already stays so.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name, shown as the page title |
| `slug` | string | no | The page's subdomain under spectate.page: lowercase letters, digits and dashes. The old address stops working |
| `visibility` | StatusPageVisibility | no | Who can open a status page. \| \| \|---\| \| `public`
Anyone. \| \| `private`
Visitors with the access link, or the password when the page has one. Part of the Team plan and up. \| |
| `custom_domain` | string | no | Your own domain for the page, such as `status.acme.com`; `null` for none. Part of paid plans (`403` `PLAN_FEATURE_UNAVAILABLE` otherwise). A new domain needs to be verified again: see `custom_domain_verification` and `verifyStatusPageCustomDomain` |
| `password_protected` | boolean | no | Let visitors of a private page also get in with a password. Part of paid plans (`403` `PLAN_FEATURE_UNAVAILABLE` otherwise); turning it on needs a `password` unless the page has one |
| `password` | string | no | The password, 8 to 255 characters. Write-only; leave out or send `null` to keep the current one |
| `language` | StatusPageLanguage | no | Languages of the public status page chrome and the subscriber emails. Customer-written content (names, incident titles and updates) is never translated. \| \| \|---\| \| `en`
English. \| \| `nl`
Dutch. \| \| `de`
German. \| \| `fr`
French. \| \| `es`
Spanish. \| \| `it`
Italian. \| |
| `match_browser_language` | boolean | no | Give visitors their browser's language when it is supported |
| `theme` | StatusPageThemeInput | no | Changes to how a status page looks. Settings left out keep their value, also inside `light`, `dark` and `display`; `null` goes back to the default. Logos and the favicon are uploaded in the dashboard. |
| `collapsed_groups` | array of string | no | Component groups that start collapsed; replaces the current list |
| `automation_enabled` | boolean | no | Monitor automation: when a monitor linked to a component goes down, open an incident "{component} is down" (major outage), and resolve it when the monitor recovers |
| `automation_down_message` | string | no | Posted when a linked monitor goes down, up to 5000 characters; `{component}` and `{status_page}` are filled in. `null` for a default message |
| `automation_recovered_message` | string | no | Posted when the monitor recovers, up to 5000 characters; `null` for a default message |
| `issue_reports_enabled` | boolean | no | Let visitors report problems from the page |
| `issue_reports_show_on_page` | boolean | no | While reports are above the threshold, say on the page that users are reporting issues |
| `issue_reports_alerts_enabled` | boolean | no | Fire an alert when reports reach the threshold |
| `issue_reports_threshold` | integer | no | Reports within `issue_reports_window_minutes` that count as above the threshold, 1 to 1000 |
| `issue_reports_window_minutes` | integer | no | The window for the threshold, in minutes, 1 to 1440 |
| `traffic_alerts_enabled` | boolean | no | Alert when views reach `traffic_alert_multiplier` times the usual views for the time of day |
| `traffic_alert_multiplier` | integer | no | How many times the usual views alert, 2 to 100 |
| `traffic_alert_min_views` | integer | no | Fewer views than this in 15 minutes never alert, 10 to 1000000 |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the page's alerts (issue reports and traffic spikes); replaces the current ones. Empty for the team's default path |
Responses: `200` The updated status page.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_FEATURE_UNAVAILABLE`: the plan doesn't include this feature; `details.feature` names it. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a status page
`DELETE /status-pages/{statusPage}`
Operation ID: `deleteStatusPage`
The page goes offline at once, with its components, incidents, maintenance, subscribers
and uploaded logos. Subscribers aren't emailed. Its firing alerts resolve. The team's own
incidents are kept.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Verify the custom domain
`POST /status-pages/{statusPage}/custom-domain/verify`
Operation ID: `verifyStatusPageCustomDomain`
Looks up the page's custom domain in DNS. One passing record verifies it: a CNAME to the
page's `cname_target`, or the TXT record from `custom_domain_verification`. A verified
domain stays verified when a later check fails. `routed` tells whether visitors reach the
page; its certificate is issued on the first visit. The page needs a custom domain (`422`
otherwise). Safe to repeat while DNS changes propagate.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
Responses: `200` What DNS returned, and whether the domain is verified.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Rotate the access key
`POST /status-pages/{statusPage}/access-key/rotate`
Operation ID: `rotateStatusPageAccessKey`
Replaces the key in the page's `access_url`: the old link stops working, and every visitor
of the private page is signed out, including those who entered the password.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
Responses: `200` The status page with its new access URL.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Status page components
The parts of your service a status page shows, such as "API" or "Dashboard", optionally in groups. A component's status is derived: the worst ongoing impact of an unresolved incident, then maintenance, else operational. A component can follow a monitor for its uptime history, and with monitor automation the monitor's downtime opens an incident on the page.
### List components
`GET /status-pages/{statusPage}/components`
Operation ID: `listStatusPageComponents`
Returns the page's components in the order the page shows them: by group, then position,
then name.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Components per page, 1 to 100. |
Responses: `200` Paginated set of `StatusPageComponent`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Add a component
`POST /status-pages/{statusPage}/components`
Operation ID: `createStatusPageComponent`
The component starts operational and goes last in its group unless you give a
`position`. `monitor_id` must be a monitor of the team (`422` otherwise).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name shown on the page |
| `description` | string | no | Text shown with the name; `null` for none |
| `group` | string | no | Group to show the component in; `null` for the page's default group |
| `position` | integer | no | Order within the group, lowest first, from 0. New components go last when left out |
| `monitor_id` | string | no | A monitor of the team whose uptime history and response times the component shows, and whose downtime opens an incident when monitor automation is on; `null` for none |
| `show_latency_chart` | boolean | no | Show the monitor's response time chart under the component |
Responses: `201` The new component.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a component
`GET /status-pages/{statusPage}/components/{component}`
Operation ID: `getStatusPageComponent`
Returns the component with its current status.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `component` | path | string, uuid | yes | Component ID. |
Responses: `200` The component.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a component
`PATCH /status-pages/{statusPage}/components/{component}`
Operation ID: `updateStatusPageComponent`
Changes only the fields you send. Its status can't be set: post an incident or schedule
maintenance instead. `monitor_id: null` unlinks the monitor.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `component` | path | string, uuid | yes | Component ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name shown on the page |
| `description` | string | no | Text shown with the name; `null` for none |
| `group` | string | no | Group to show the component in; `null` for the page's default group |
| `position` | integer | no | Order within the group, lowest first, from 0. New components go last when left out |
| `monitor_id` | string | no | A monitor of the team whose uptime history and response times the component shows, and whose downtime opens an incident when monitor automation is on; `null` for none |
| `show_latency_chart` | boolean | no | Show the monitor's response time chart under the component |
Responses: `200` The updated component.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a component
`DELETE /status-pages/{statusPage}/components/{component}`
Operation ID: `deleteStatusPageComponent`
It disappears from the page, with its impact periods; incidents and maintenance that
affected it stay.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `component` | path | string, uuid | yes | Component ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Scheduled maintenance
Planned maintenance announced on a status page. While it is in progress, its components show as under maintenance. An automatic maintenance starts and completes on schedule by itself; a manual one changes when you set its status. Subscribers are emailed when it is scheduled, starts and completes.
### List scheduled maintenance
`GET /status-pages/{statusPage}/maintenances`
Operation ID: `listScheduledMaintenances`
Returns the page's maintenance, the latest planned start first.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Maintenances per page, 1 to 100. |
| `filter[status]` | query | ScheduledMaintenanceStatus | no | Only maintenance with this status. |
Responses: `200` Paginated set of `ScheduledMaintenance`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Schedule maintenance
`POST /status-pages/{statusPage}/maintenances`
Operation ID: `createScheduledMaintenance`
Announces it on the page and emails confirmed subscribers unless `notify_subscribers` is
`false`. `scheduled_at` must be in the future.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | Title shown on the page, up to 255 characters |
| `description` | string | no | What happens and what visitors notice, in Markdown; `null` for none |
| `scheduled_at` | string, date-time | yes | Planned start, in the future |
| `scheduled_until` | string | no | Planned end, after `scheduled_at`; `null` for none |
| `automatic` | boolean | no | `true` (default): starts at `scheduled_at` and completes at `scheduled_until` by itself (without a planned end, complete it by setting `status`). `false`: only changes when you set `status` |
| `affected_components` | array of StatusPageAffectedComponentInput | no | Components it affects; components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers about it (default `true`) |
Responses: `201` The new maintenance.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get scheduled maintenance
`GET /status-pages/{statusPage}/maintenances/{maintenance}`
Operation ID: `getScheduledMaintenance`
Returns the maintenance with the components it affects.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `maintenance` | path | string, uuid | yes | Maintenance ID. |
Responses: `200` The maintenance.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update scheduled maintenance
`PATCH /status-pages/{statusPage}/maintenances/{maintenance}`
Operation ID: `updateScheduledMaintenance`
Changes only the fields you send; `affected_components` replaces the list. Setting
`status` to `in_progress` or `completed` (or setting `completed_at`) emails confirmed
subscribers unless `notify_subscribers` is `false`; other changes are silent.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `maintenance` | path | string, uuid | yes | Maintenance ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | no | Title shown on the page, up to 255 characters |
| `description` | string | no | What happens and what visitors notice, in Markdown; `null` for none |
| `status` | ScheduledMaintenanceStatus | no | Where a scheduled maintenance stands. \| \| \|---\| \| `scheduled`
Announced, not started yet. \| \| `in_progress`
Going on: its components show as under maintenance. \| \| `completed`
Over. \| |
| `automatic` | boolean | no | `true`: starts and completes on schedule. `false`: only changes when you set `status` |
| `scheduled_at` | string, date-time | no | Planned start |
| `scheduled_until` | string | no | Planned end; `null` for none |
| `completed_at` | string | no | When it completed. Setting it completes the maintenance |
| `affected_components` | array of StatusPageAffectedComponentInput | no | Components it affects; replaces the current list. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers when this starts or completes the maintenance (default `true`) |
Responses: `200` The updated maintenance.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete scheduled maintenance
`DELETE /status-pages/{statusPage}/maintenances/{maintenance}`
Operation ID: `deleteScheduledMaintenance`
It disappears from the page and its components go back to their other status. Silent:
subscribers aren't emailed.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `maintenance` | path | string, uuid | yes | Maintenance ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Status page incidents
Incidents as visitors of a status page read them, with their updates. How an incident affects components is a timeline of impact periods, which drives each component's status and uptime history. Publishing an update sets the impacts as of then; you can also edit the periods directly. Monitor automation opens and resolves incidents for components that follow a monitor, until someone takes over by posting an update. The team's own incidents publish here with `publishIncidentStatusPageUpdate`.
### List status page incidents
`GET /status-pages/{statusPage}/incidents`
Operation ID: `listStatusPageIncidents`
Returns the page's incidents, newest first, with their updates, affected components and
impact periods.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Incidents per page, 1 to 100. |
| `filter[status]` | query | IncidentStatus | no | Only incidents with this status. |
| `filter[title]` | query | string | no | Case-insensitive text in the title. |
Responses: `200` Paginated set of `StatusPageIncident`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Create a status page incident
`POST /status-pages/{statusPage}/incidents`
Operation ID: `createStatusPageIncident`
Opens a public incident. With a `body` it starts with a first update published at
`published_at` (default now), and `affected_components` open impact periods from then on.
Confirmed subscribers are emailed unless `notify_subscribers` is `false`. `incident_id`
links the team's incident, so publishing from it posts here.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | Title shown on the page |
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | no | The first update, in Markdown. Leave out to create the incident without one |
| `published_at` | string | no | When it happened, now or in the past (default now) |
| `impact` | ImpactLevel | no | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `incident_id` | string | no | The team's incident this one is for; `null` for none. Publishing from that incident (`publishIncidentStatusPageUpdate`) then posts here |
| `affected_components` | array of StatusPageAffectedComponentInput | no | The components it affects as of `published_at`, with their impact; components left out are no longer affected. Leave out to keep the impacts as they are; send `[]` for none. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers about the new incident (default `true`). `false` changes the page without emails |
Responses: `201` The new status page incident.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a status page incident
`GET /status-pages/{statusPage}/incidents/{incident}`
Operation ID: `getStatusPageIncident`
Returns the incident with its updates, affected components and impact periods.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
Responses: `200` The status page incident.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update a status page incident
`PATCH /status-pages/{statusPage}/incidents/{incident}`
Operation ID: `updateStatusPageIncident`
Edits the incident without posting an update; fields left out keep their value.
`affected_components` set the impacts as of now. Setting `status` to `resolved` closes
every open impact period now and emails confirmed subscribers unless
`notify_subscribers` is `false`; other edits are silent. Changing the status or the
components takes the incident over from monitor automation.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | no | Title shown on the page |
| `status` | IncidentStatus | no | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `impact` | ImpactLevel | no | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `affected_components` | array of StatusPageAffectedComponentInput | no | The components it affects as of now, with their impact; components left out are no longer affected. Leave out to keep the impacts as they are; send `[]` for none. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers when this resolves the incident (default `true`). `false` changes the page without emails |
Responses: `200` The updated status page incident.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete a status page incident
`DELETE /status-pages/{statusPage}/incidents/{incident}`
Operation ID: `deleteStatusPageIncident`
Removes it from the page with its updates and impact periods; component status and
uptime history follow. Silent: subscribers aren't emailed. The team's incident it was
published from is kept.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Save the write-up
`PUT /status-pages/{statusPage}/incidents/{incident}/writeup`
Operation ID: `saveStatusPageIncidentWriteup`
Writes the incident's public write-up, in Markdown: what happened, why, and what changes.
With `published: true` it shows on the public incident page; with `false` it's a draft only
the team sees, and a published write-up is taken down. Publishing needs `content` (`422`).
Confirmed subscribers are emailed the write-up when this publishes it for the first time and
`notify_subscribers` is `true`; saving a published write-up again never emails. A write-up
keeps the time it was first published while you edit it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string | no | The write-up, in Markdown, at most 50,000 characters. Required to publish |
| `published` | boolean | yes | `true` shows it on the public incident page; `false` keeps it as a draft, or takes a published write-up down |
| `notify_subscribers` | boolean | no | Email confirmed subscribers when this publishes the write-up for the first time (default `false`). Edits to a published write-up are never emailed |
Responses: `200` The incident with its write-up.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete the write-up
`DELETE /status-pages/{statusPage}/incidents/{incident}/writeup`
Operation ID: `deleteStatusPageIncidentWriteup`
Removes the incident's write-up, published or a draft. Silent: subscribers aren't emailed.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
Responses: `200` The incident without a write-up.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Publish an update
`POST /status-pages/{statusPage}/incidents/{incident}/updates`
Operation ID: `createStatusPageIncidentUpdate`
Posts an update at `published_at` (default now) and moves the incident to its `status`.
`affected_components` are the impacts as of then: changed impacts close and reopen,
components left out are no longer affected; leave the field out to keep the impacts.
`resolved` closes every open period. An update published before the incident's latest
one doesn't change the impacts. Confirmed subscribers are emailed unless
`notify_subscribers` is `false`. Takes the incident over from monitor automation.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | yes | The message, in Markdown |
| `published_at` | string | no | When it happened, now or in the past (default now) |
| `affected_components` | array of StatusPageAffectedComponentInput | no | The components it affects as of `published_at`, with their impact; components left out are no longer affected. Leave out to keep the impacts as they are; send `[]` for none. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers about the update (default `true`). `false` changes the page without emails |
Responses: `201` The incident with the new update.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Edit an update
`PATCH /status-pages/{statusPage}/incidents/{incident}/updates/{update}`
Operation ID: `updateStatusPageIncidentUpdate`
Changes an update's message, status or time; fields left out keep their value. Moving
`published_at` moves the impact changes made at the old time with it. The incident's
status follows its latest update. Silent, and takes the incident over from monitor
automation.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
| `update` | path | string, uuid | yes | Update ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `status` | IncidentStatus | no | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | no | The message, in Markdown |
| `published_at` | string, date-time | no | When it happened, now or in the past. Impact periods that started or ended at the old time move with it |
Responses: `200` The incident with the edited update.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an update
`DELETE /status-pages/{statusPage}/incidents/{incident}/updates/{update}`
Operation ID: `deleteStatusPageIncidentUpdate`
Removes the update; the incident's status follows its latest remaining update. The
impact periods stay as they are. Silent, and takes the incident over from monitor
automation.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
| `update` | path | string, uuid | yes | Update ID. |
Responses: `200` The incident without the update.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Add an impact period
`POST /status-pages/{statusPage}/incidents/{incident}/impacts`
Operation ID: `createStatusPageImpactPeriod`
Records that the incident affected a component from `started_at` to `ended_at` (`null`
while it goes on). Periods of one component may not overlap within the incident (`422`).
Component status and uptime history follow. Silent, and takes the incident over from
monitor automation.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `component_id` | string, uuid | yes | A component of the status page |
| `impact` | ComponentImpact | yes | How badly an incident affects a component. A component's status is the worst impact it has at the moment. \| \| \|---\| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `started_at` | string, date-time | yes | When it started, now or in the past |
| `ended_at` | string | no | When it ended, after `started_at` and not in the future; `null` or left out while it goes on |
Responses: `201` The incident with the new period.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update an impact period
`PATCH /status-pages/{statusPage}/incidents/{incident}/impacts/{impact}`
Operation ID: `updateStatusPageImpactPeriod`
Changes only the fields you send; `ended_at: null` reopens the period. The same rules as
adding one apply. Silent, and takes the incident over from monitor automation.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
| `impact` | path | string, uuid | yes | Impact period ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `component_id` | string, uuid | no | A component of the status page |
| `impact` | ComponentImpact | no | How badly an incident affects a component. A component's status is the worst impact it has at the moment. \| \| \|---\| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `started_at` | string, date-time | no | When it started, now or in the past |
| `ended_at` | string | no | When it ended, after `started_at` and not in the future; `null` reopens the period |
Responses: `200` The incident with the changed period.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an impact period
`DELETE /status-pages/{statusPage}/incidents/{incident}/impacts/{impact}`
Operation ID: `deleteStatusPageImpactPeriod`
Component status and uptime history follow. Silent, and takes the incident over from
monitor automation.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `incident` | path | string, uuid | yes | Status page incident ID. |
| `impact` | path | string, uuid | yes | Impact period ID. |
Responses: `200` The incident without the period.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Status page subscribers
People who subscribed to a status page's updates by email, from the page itself. A subscription is confirmed by double opt-in; only confirmed subscribers are emailed. Subscribers can't be added through the API.
### List subscribers
`GET /status-pages/{statusPage}/subscribers`
Operation ID: `listStatusPageSubscribers`
Returns the page's subscribers, newest first.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Subscribers per page, 1 to 100. |
| `filter[confirmed]` | query | boolean | no | `true` for confirmed subscribers only, `false` for those awaiting confirmation. |
| `filter[search]` | query | string | no | Case-insensitive text in the email address. |
Responses: `200` Paginated set of `StatusPageSubscriber`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Remove a subscriber
`DELETE /status-pages/{statusPage}/subscribers/{subscriber}`
Operation ID: `deleteStatusPageSubscriber`
They get no more emails from the page and aren't told. They can subscribe again on the
page.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `subscriber` | path | string, uuid | yes | Subscriber ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Status page issue reports
Problems visitors reported from a status page, when the page has issue reports on. Reports above the page's threshold can show a notice on the page and fire an alert.
### List issue reports
`GET /status-pages/{statusPage}/issue-reports`
Operation ID: `listStatusPageIssueReports`
Returns the problems visitors reported, newest first. The visitor's email address is only
returned to tokens with `status-pages:write`. Whether the page is above its threshold is
on the status page (`issue_reports_triggered_at`).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Reports per page, 1 to 100. |
Responses: `200` Paginated set of `StatusPageIssueReport`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Delete an issue report
`DELETE /status-pages/{statusPage}/issue-reports/{report}`
Operation ID: `deleteStatusPageIssueReport`
For example to remove a visitor's email address.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `statusPage` | path | string, uuid | yes | Status page ID. |
| `report` | path | string, uuid | yes | Issue report ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Team
The team the API token belongs to: its name, time zone, plan and whether monitoring runs. Deleting the team and changing billing happen in the dashboard.
### Get the team
`GET /team`
Operation ID: `getTeam`
Returns the token's team. Works with any token.
Responses: `200` The team.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Update the team
`PATCH /team`
Operation ID: `updateTeam`
Changes only the fields you send.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name, up to 255 characters |
| `email` | string | no | The team's billing email: Spectate gives it to Vatly, which sends the invoices and receipts, at the team's first checkout (a plan or credits). `null` to use the address of the member who starts that checkout |
| `timezone` | string | no | The team's time zone, as an IANA name; escalation path working hours without a time zone of their own use it |
Responses: `200` The updated team.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Members
The people in the team and their roles. Members join by accepting an invite. Use member IDs in on-call rotations and incident roles.
### List members
`GET /members`
Operation ID: `listMembers`
Returns the team's members, by name.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `filter[role]` | query | TeamRole | no | Only members with this role. |
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Members per page, 1 to 100. |
Responses: `200` Paginated set of `Member`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get a member
`GET /members/{member}`
Operation ID: `getMember`
Returns a member of the team by their ID.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `member` | path | string, uuid | yes | Member (user) ID. |
Responses: `200` The member.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Change a member's role
`PATCH /members/{member}`
Operation ID: `updateMember`
The owner's role can't change, and nobody becomes owner this way (`403` `TEAM_OWNER_PROTECTED`).
The API can't transfer ownership: only the owner can, in the dashboard (Team → Settings),
after confirming their password.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `member` | path | string, uuid | yes | Member (user) ID. |
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `role` | TeamRole | yes | A member's role in the team: what they may do. \| \| \|---\| \| `owner`
Everything, including billing and deleting the team. One per team. \| \| `manager`
Everything but billing and deleting the team. \| \| `admin`
Configure monitoring, alerting, incidents and status pages; can't manage members or API tokens. \| \| `member`
Read everything; manage monitors and incidents, acknowledge alerts. \| \| `billing`
Billing and support only. \| |
Responses: `200` The member with the new role.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `TEAM_OWNER_PROTECTED`: the team owner's role can't be changed and the owner can't be removed. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Remove a member
`DELETE /members/{member}`
Operation ID: `removeMember`
They lose access to the team at once and leave its on-call rotations; what they did stays
in the history. API tokens they created keep working: revoke them in the dashboard if
needed. The owner can't be removed (`403` `TEAM_OWNER_PROTECTED`).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `member` | path | string, uuid | yes | Member (user) ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `TEAM_OWNER_PROTECTED`: the team owner's role can't be changed and the owner can't be removed. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Invites
Invites to join the team, sent by email. The invitee accepts in the dashboard, signed in with that address, and gets the invite's role. Invites expire after 7 days. Pending invites count towards the plan's member limit.
### List invites
`GET /invites`
Operation ID: `listInvites`
Returns the team's invites that weren't accepted or revoked, newest first, including
expired ones.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `page` | query | integer | no | Page number, from 1. |
| `per_page` | query | integer | no | Invites per page, 1 to 100. |
Responses: `200` Paginated set of `Invite`; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Invite someone
`POST /invites`
Operation ID: `createInvite`
Emails them a link to join the team. Someone who is a member already, or has a pending
invite, can't be invited again (`422`); an expired invite to the address is replaced. Over
the plan's member limit, counting pending invites, the request fails with `403`
`PLAN_LIMIT_REACHED`.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| `email` | string, email | yes | Their email address; disposable addresses aren't accepted |
| `role` | TeamRole | no | A member's role in the team: what they may do. \| \| \|---\| \| `owner`
Everything, including billing and deleting the team. One per team. \| \| `manager`
Everything but billing and deleting the team. \| \| `admin`
Configure monitoring, alerting, incidents and status pages; can't manage members or API tokens. \| \| `member`
Read everything; manage monitors and incidents, acknowledge alerts. \| \| `billing`
Billing and support only. \| |
Responses: `201` The invite.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `PLAN_LIMIT_REACHED`: the plan doesn't allow another one; `details.feature` names the limit. `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `422` `VALIDATION_FAILED`: the request is invalid; `details.errors` lists the fields.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get an invite
`GET /invites/{invite}`
Operation ID: `getInvite`
Returns the invite, also when it has expired.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `invite` | path | string, uuid | yes | Invite ID. |
Responses: `200` The invite.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Revoke an invite
`DELETE /invites/{invite}`
Operation ID: `revokeInvite`
The link in the email stops working. The invitee isn't told.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| `invite` | path | string, uuid | yes | Invite ID. |
Responses: `204` No content; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `404` `RESOURCE_NOT_FOUND`: there is no such resource in this team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Billing
The team's plan, subscription, notification credits and how much of the plan's limits it uses. Read only: subscriptions and credit packs are bought and changed in the dashboard. Needs `billing:read`, which only owners and billing members can grant.
### Get billing
`GET /billing`
Operation ID: `getBilling`
Returns the plan, the subscription and the SMS and voice notification credits.
Responses: `200` The billing state.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
### Get plan usage
`GET /billing/usage`
Operation ID: `getUsage`
Returns, per plan limit, how much the team uses and the limit. Useful before creating
resources in bulk.
Responses: `200` Usage per plan limit.; `401` `UNAUTHENTICATED`: no token was sent. `INVALID_TOKEN`: the token is unknown or revoked. `TOKEN_EXPIRED`: the token has expired.; `403` `FORBIDDEN`: the token lacks an ability this endpoint requires (listed in `details.required_abilities`). `TEAM_PENDING_DELETION`: the team is scheduled for deletion. `TEAM_SUSPENDED`: Spectate suspended the team.; `429` `RATE_LIMITED`: too many requests for this token. Wait for the number of seconds in `Retry-After`..
## Schemas
### Alert
An alert: a problem a monitor, host, domain, status page or alert source detected. It escalates along its escalation path until someone acknowledges it, and resolves when the problem is over.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Alert ID |
| `title` | string | yes | What's wrong |
| `description` | string | yes | More about it, as the source described it |
| `status` | AlertStatus | yes | Whether an alert's problem is ongoing. \| \| \|---\| \| `firing`
The problem is ongoing; it escalates until acknowledged. \| \| `resolved`
The problem is over. \| |
| `severity` | Severity | yes | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `source_type` | AlertSourceType | yes | What raised an alert. \| \| \|---\| \| `uptime`
A monitor went down. \| \| `certificate`
A monitor's certificate is invalid or expires soon. \| \| `performance`
A monitor got slow. \| \| `dns`
The answer of a DNS monitor changed (when it alerts on changes). \| \| `host_metric`
A host's metric condition held, or it stopped sending data. \| \| `domain`
A domain expires soon, expired or its registration changed. \| \| `external`
An alert source (external tool) fired it. \| \| `status_page`
Visitor issue reports over the threshold or a traffic spike (`metadata.type`: `issue_reports`, `traffic_spike`). \| |
| `resource` | AlertResource | yes | |
| `fired_at` | string, date-time | yes | When it fired |
| `acknowledged_at` | string | yes | When it was acknowledged, which stopped its escalation; `null` while unacknowledged |
| `acknowledged_by` | string | yes | Who acknowledged it: a member's name, an API token, or how (for example a phone call) |
| `resolved_at` | string | yes | When it resolved; `null` while firing |
| `resolved_by` | string | yes | Who resolved it by hand: a member's name or an API token. `null` while firing, and when it resolved on its own because the problem was over |
| `labels` | object | yes | Labels the source sent (Prometheus, Grafana); `null` when it sent none |
| `links` | array of AlertLink | yes | Links the source sent along |
### AlertLink
A link the alert source sent along.
| Field | Type | Required | Description |
|---|---|---|---|
| `label` | string | yes | What it opens |
| `url` | string, uri | yes | Where it goes |
### AlertResource
The resource an alert is about.
| Field | Type | Required | Description |
|---|---|---|---|
| `type` | AlertResourceType | yes | What kind of resource an alert is about. |
| `id` | string, uuid | yes | The resource's ID, for example a monitor ID |
| `name` | string | yes | Its name or label |
### AlertSource
An alert source: an external tool (Prometheus Alertmanager, Grafana, Sentry, a script…) whose requests to `webhook_url`, or mails to `email_address`, fire and resolve alerts. The URL and address contain the source's secret token: whoever has them can fire alerts.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Alert source ID |
| `name` | string | yes | Name shown on its alerts |
| `type` | AlertSourceProvider | yes | The external tool behind an alert source; decides how its requests are read. \| \| \|---\| \| `webhook`
Spectate's own JSON format, for scripts, CI and anything that can call a URL. \| \| `email`
Emails to the source's own address (subject becomes the alert). \| \| `alertmanager`
Prometheus Alertmanager `webhook_configs`. \| \| `grafana`
Grafana Alerting webhook contact point (Alertmanager format plus Grafana links). \| \| `sentry`
Sentry internal integration webhooks (SaaS and self-hosted), or the legacy WebHooks plugin. \| |
| `enabled` | boolean | yes | Whether requests fire alerts; a disabled source rejects them |
| `webhook_url` | string, uri | yes | Where the tool sends its webhooks. Secret: rotate it with `rotateAlertSourceToken` if it leaks |
| `email_address` | string | yes | `email` sources: the address to send mails to. Secret like the URL |
| `has_secret` | boolean | yes | Whether a signing secret is set (Sentry client secret, Grafana HMAC secret, Alertmanager bearer token); it's never returned |
| `default_severity` | Severity | yes | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `auto_resolve_minutes` | integer | yes | Minutes after which an alert the tool stopped repeating resolves; `null` keeps it until the tool resolves it |
| `settings` | AlertSourceSettings | yes | Settings of some source types; the others ignore them. |
| `project_id` | string | yes | The project whose escalation paths apply when the source has none of its own; `null` for none |
| `escalation_paths` | array of EscalationPathReference | yes | Escalation paths the source's alerts follow. Empty: the project's paths, else the team's default path |
| `last_event_at` | string | yes | When the source last received a request |
| `events_count` | integer | yes | Requests the source has received in total |
| `firing_alerts_count` | integer | yes | Alerts of the source that are firing now |
| `created_at` | string, date-time | yes | When the source was created |
### AlertSourceEvent
A request an alert source received, kept for 7 days.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Event ID |
| `received_at` | string, date-time | yes | When the request arrived |
| `outcome` | AlertSourceEventOutcome | yes | What became of a request an alert source received. \| \| \|---\| \| `fired`
It fired at least one new alert. \| \| `resolved`
It resolved at least one alert. \| \| `updated`
It repeated alerts that were already firing. \| \| `test`
A test request from the tool's own "test" button; no alert. \| \| `ignored`
Valid, but nothing to do (for example a resolve of an alert that isn't firing). \| \| `rejected`
Refused: bad signature, unreadable payload or a disabled source; see `error`. \| |
| `summary` | string | yes | What happened, in words |
| `error` | string | yes | Why it was rejected, with `outcome` `rejected` |
| `alerts` | array of AlertSourceEventAlert | yes | What it did per alert |
| `payload` | object | yes | The request body as received: the tool's JSON, or `{body, truncated}` for mail and non-JSON bodies. Its shape is the tool's |
### AlertSourceEventAlert
What a request did to one alert.
| Field | Type | Required | Description |
|---|---|---|---|
| `action` | AlertSourceEventAction | yes | What a request did to one alert. \| \| \|---\| \| `fired`
A new alert fired. \| \| `updated`
The alert was already firing; it was updated. \| \| `resolved`
The alert resolved. \| \| `ignored`
A resolve for an alert that wasn't firing. \| |
| `title` | string | yes | The alert's title |
| `dedupe_key` | string | yes | The key the tool groups repeats by; requests with the same key update one alert |
| `alert_id` | string | yes | The alert; `null` when none was touched |
### AlertSourceSettings
Settings of some source types; the others ignore them.
| Field | Type | Required | Description |
|---|---|---|---|
| `alert_on_new_issues` | boolean | yes | Sentry: also alert on every new issue (issue `created` webhooks), not only on alert rules |
| `signature_header` | string | yes | Grafana: the header carrying the HMAC signature; `null` means `X-Grafana-Alerting-Signature` |
| `timestamp_header` | string | yes | Grafana: the timestamp header, when the contact point signs `{timestamp}:{body}` |
### AlertSourceSettingsInput
Settings to set; settings you leave out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `alert_on_new_issues` | boolean | no | Sentry: also alert on every new issue |
| `signature_header` | string | no | Grafana: the header carrying the HMAC signature, up to 100 characters; `null` for the default |
| `timestamp_header` | string | no | Grafana: the timestamp header, when the contact point signs `{timestamp}:{body}`; `null` for none |
### ApiError
An error. The HTTP status tells the class of problem, `error.code` the exact one.
| Field | Type | Required | Description |
|---|---|---|---|
| `error` | object | yes | What went wrong. |
### ApiToken
The API token that made the request.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Token ID |
| `name` | string | yes | Name given to the token when it was created |
| `last_four` | string | yes | Last four characters of the token, to tell tokens apart |
| `abilities` | array of ApiTokenAbility | yes | What the token may do. Each endpoint lists the ability it requires |
| `team` | ApiTokenTeam | yes | The team an API token acts for. |
| `expires_at` | string | yes | When the token stops working; `null` if it never expires |
| `created_at` | string, date-time | yes | When the token was created |
### ApiTokenTeam
The team an API token acts for.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Team ID |
| `name` | string | yes | Team name |
### AssignIncidentRole
Who gets an incident role.
| Field | Type | Required | Description |
|---|---|---|---|
| `member_id` | string, uuid | yes | The member who takes the role; they replace whoever had it |
### Billing
The team's billing state. Subscriptions are changed in the dashboard.
| Field | Type | Required | Description |
|---|---|---|---|
| `plan` | Plan | yes | Billing plans (docs/billing.md). The plan sets the features; the number of monitors + hosts is the subscription's quantity, priced per monitor (`config/billing.php`). `None` is a team without a paid plan: on the trial (which uses the trial plan's limits) or unpaid (paused). \| \| \|---\| \| `none`
No paid plan and no trial: monitoring is paused until the team subscribes. \| \| `starter`
Starter: up to 3 members and 1 status page, the team default escalation path only. \| \| `team`
Team: unlimited members, 5 status pages, on-call, more escalation paths and private status pages. \| \| `business`
Business: everything in Team, with unlimited status pages and more subscribers and notification credits. \| |
| `subscribed` | boolean | yes | Whether the team has a paid subscription |
| `on_trial` | boolean | yes | Whether the team is on its trial |
| `trial_ends_at` | string | yes | When the trial ends; `null` without one |
| `plan_ends_at` | string | yes | End of a plan Spectate granted without a subscription; `null` without one |
| `subscription` | Subscription | yes | |
| `notification_credits` | NotificationCredits | yes | Credits for SMS and voice notifications. The monthly allowance is spent first; bought credits never expire. |
### Channel
A notification channel: where escalation paths send alerts. The settings of its type are in the object of that name (`email`, `slack`…); the others are `null`. Secrets (webhook URLs, tokens, header values) are never returned.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Channel ID |
| `name` | string | yes | Name shown in escalation paths |
| `type` | ChannelType | yes | Where the channel delivers |
| `enabled` | boolean | yes | Whether the channel delivers. `false` when a member turned it off or Spectate did after repeated failures (`auto_disabled`) |
| `auto_disabled` | boolean | yes | Whether Spectate turned the channel off because deliveries kept failing. Fix the cause, then enable it or send a test with `enable` |
| `disabled_at` | string | yes | When the channel was turned off automatically |
| `disabled_reason` | string | yes | Why it was turned off automatically |
| `consecutive_failures` | integer | yes | Failed deliveries since the last successful one |
| `failing_since` | string | yes | Since when deliveries fail |
| `last_failure_at` | string | yes | When a delivery last failed |
| `last_failure_reason` | string | yes | Why the last delivery failed |
| `last_delivered_at` | string | yes | When a delivery last succeeded |
| `email` | ChannelEmail | yes | |
| `slack` | ChannelSlack | yes | |
| `telegram` | ChannelTelegram | yes | |
| `webhook` | ChannelWebhook | yes | |
| `pushover` | ChannelPushover | yes | |
| `sms` | ChannelPhone | yes | |
| `voice` | ChannelPhone | yes | |
| `created_at` | string, date-time | yes | When the channel was created |
### ChannelEmail
Where an `email` channel sends.
| Field | Type | Required | Description |
|---|---|---|---|
| `address` | string, email | yes | The address alerts go to |
### ChannelPhone
The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits.
| Field | Type | Required | Description |
|---|---|---|---|
| `phone_number` | string | yes | The phone number in international format |
### ChannelPushover
Who a `pushover` channel notifies. The application token is write-only.
| Field | Type | Required | Description |
|---|---|---|---|
| `user_key` | string | yes | The Pushover user or group key |
| `priority` | integer | yes | Pushover priority, -2 (lowest) to 2 (emergency); `null` for normal (0) |
### ChannelPushoverInput
Who a `pushover` channel notifies, and with which Pushover application.
| Field | Type | Required | Description |
|---|---|---|---|
| `user_key` | string | yes | The Pushover user or group key |
| `api_token` | string | yes | Your Pushover application's API token. Write-only: never returned |
| `priority` | integer | no | Pushover priority, -2 (lowest) to 2 (emergency). Default 0 |
### ChannelReference
A channel something sends to.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Channel ID |
| `name` | string | yes | Channel name |
| `type` | ChannelType | yes | Where it delivers |
| `enabled` | boolean | yes | Whether it delivers; disabled channels are skipped |
### ChannelSlack
Where a `slack` channel posts: a channel of a Slack workspace connected under Integrations.
| Field | Type | Required | Description |
|---|---|---|---|
| `installation_id` | string | yes | The team's Slack installation (workspace) that posts. `null` for older channels with their own bot token |
| `channel` | string | yes | The Slack channel ID |
| `channel_name` | string | yes | The channel's name, for display |
### ChannelSlackInput
Where a `slack` channel posts. Connect the Slack workspace under Integrations in the dashboard first; the installation's ID is in the Slack integration.
| Field | Type | Required | Description |
|---|---|---|---|
| `installation_id` | string, uuid | yes | The team's Slack installation (workspace) that posts |
| `channel` | string | yes | The Slack channel ID (not its name); invite the Spectate app to private channels |
| `channel_name` | string | no | The channel's name, for display |
### ChannelTelegram
The chat a `telegram` channel sends to. Telegram channels are connected from the dashboard (Alerting → Channels), not through the API.
| Field | Type | Required | Description |
|---|---|---|---|
| `chat_id` | string | yes | The Telegram chat ID |
| `chat_title` | string | yes | The chat's title, for display |
### ChannelTestResult
A test notification that was delivered.
| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | yes | What was sent |
| `channel` | Channel | yes | A notification channel: where escalation paths send alerts. The settings of its type are in the object of that name (`email`, `slack`…); the others are `null`. Secrets (webhook URLs, tokens, header values) are never returned. |
### ChannelWebhook
What a `webhook` channel sends. The URL and header values can hold credentials, so only the host and the header names are returned.
| Field | Type | Required | Description |
|---|---|---|---|
| `host` | string | yes | The host of the URL the channel posts to |
| `header_names` | array of string | yes | Names of the headers it sends |
### ChannelWebhookHeader
A header a `webhook` channel sends with every request.
| Field | Type | Required | Description |
|---|---|---|---|
| `key` | string | yes | Header name. Hop-by-hop and connection headers are refused |
| `value` | string | yes | Header value; write-only, never returned |
### ChannelWebhookInput
Where a `webhook` channel posts its JSON. The URL and header values are write-only.
| Field | Type | Required | Description |
|---|---|---|---|
| `url` | string, uri | yes | The URL to `POST` to; must be a public HTTP or HTTPS address |
| `headers` | array of ChannelWebhookHeader | no | Headers to send with every request, for example for authentication |
### ChannelWebhookUrlInput
The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned.
| Field | Type | Required | Description |
|---|---|---|---|
| `webhook_url` | string, uri | yes | The incoming webhook URL from Discord (Server settings → Integrations → Webhooks) or a Teams workflow. Must be a public HTTPS address |
### CreateAlertSource
A new alert source. The response has the `webhook_url` (and `email_address`) to configure in the tool.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name shown on its alerts, up to 255 characters |
| `type` | AlertSourceProvider | yes | The external tool behind an alert source; decides how its requests are read. \| \| \|---\| \| `webhook`
Spectate's own JSON format, for scripts, CI and anything that can call a URL. \| \| `email`
Emails to the source's own address (subject becomes the alert). \| \| `alertmanager`
Prometheus Alertmanager `webhook_configs`. \| \| `grafana`
Grafana Alerting webhook contact point (Alertmanager format plus Grafana links). \| \| `sentry`
Sentry internal integration webhooks (SaaS and self-hosted), or the legacy WebHooks plugin. \| |
| `default_severity` | Severity | no | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `auto_resolve_minutes` | integer | no | Minutes, 5 to 10080, after which an alert the tool stopped repeating resolves; `null` keeps it until resolved. Default `null`, or 60 for `email` sources |
| `secret` | string | no | Signing secret the tool uses: Sentry client secret, Grafana HMAC secret or Alertmanager bearer token. Write-only |
| `settings` | AlertSourceSettingsInput | no | Settings to set; settings you leave out keep their value. |
| `project_id` | string | no | Project whose escalation paths apply when the source has none of its own |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the source's alerts |
### CreateChannel
A new notification channel: a name, a type, and the settings object of that type (`email` for `email`, `slack` for `slack`…). Send only that one object. Telegram channels are connected from the dashboard.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name shown in escalation paths |
| `type` | ChannelType | yes | Where the channel delivers; `telegram` can't be created through the API |
| `enabled` | boolean | no | Whether it delivers from the start. Default `true` |
| `email` | ChannelEmail | no | Where an `email` channel sends. |
| `slack` | ChannelSlackInput | no | Where a `slack` channel posts. Connect the Slack workspace under Integrations in the dashboard first; the installation's ID is in the Slack integration. |
| `discord` | ChannelWebhookUrlInput | no | The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned. |
| `microsoft_teams` | ChannelWebhookUrlInput | no | The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned. |
| `webhook` | ChannelWebhookInput | no | Where a `webhook` channel posts its JSON. The URL and header values are write-only. |
| `pushover` | ChannelPushoverInput | no | Who a `pushover` channel notifies, and with which Pushover application. |
| `sms` | ChannelPhone | no | The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits. |
| `voice` | ChannelPhone | no | The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits. |
### CreateDomain
A domain to monitor.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | The registered domain, without `www.` or a path; internationalised names may be in Unicode or punycode |
| `enabled` | boolean | no | Whether to start monitoring at once. Default `true` |
| `expiry_threshold_days` | integer | no | Days before expiry, 1 to 365, that the "expires soon" alert fires. Default 30 |
| `alert_on_registry_changes` | boolean | no | Raise an alert when the registrar, nameservers or DNSSEC keys change. Default `true` |
| `project_id` | string | no | Project to add the domain to; default the team's default project, `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the domain's alerts. Leave out or send `[]` to follow the project's paths, else the team's default path |
### CreateEscalationPath
A new escalation path.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name, up to 255 characters |
| `description` | string | no | What the path is for, up to 1000 characters |
| `enabled` | boolean | no | Whether alerts follow the path. Default `true` |
| `is_default` | boolean | no | Make it the team's default path; the current default stops being one. Default `false` |
| `working_hours` | WorkingHoursInput | no | |
| `steps` | array of EscalationStepInput | no | The steps, in order, up to 99 in total. Leave out or `[]` for a path that does nothing yet |
### CreateIncident
A new incident.
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | What's going on, up to 255 characters |
| `severity` | Severity | yes | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `summary` | string | no | More about it, in Markdown |
### CreateIncidentUpdate
An update to post to an incident.
| Field | Type | Required | Description |
|---|---|---|---|
| `body` | string | yes | What's known now, in Markdown |
| `status` | IncidentStatus | no | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
### CreateInvite
Someone to invite to the team.
| Field | Type | Required | Description |
|---|---|---|---|
| `email` | string, email | yes | Their email address; disposable addresses aren't accepted |
| `role` | TeamRole | no | A member's role in the team: what they may do. \| \| \|---\| \| `owner`
Everything, including billing and deleting the team. One per team. \| \| `manager`
Everything but billing and deleting the team. \| \| `admin`
Configure monitoring, alerting, incidents and status pages; can't manage members or API tokens. \| \| `member`
Read everything; manage monitors and incidents, acknowledge alerts. \| \| `billing`
Billing and support only. \| |
### CreateMetricCondition
A new metric condition. Attach it to hosts, to projects (all their hosts), or both.
| Field | Type | Required | Description |
|---|---|---|---|
| `metric` | MetricPoint | yes | A host metric the agent reports. `cpu_usage`, `memory_usage`, `disk_usage`, `load_average`, `network_in` and `network_out` are the summaries the dashboard charts; the `system.*` metrics are the agent's raw values. |
| `condition` | MetricCondition | yes | An alert rule for host metrics, for example "CPU usage above 90% for 5 minutes". It applies to its hosts and to every host of its projects. |
| `threshold` | number | yes | Compared with the metric's value as the agent reports it, in the unit the host's charts show |
| `severity` | Severity | yes | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `duration_minutes` | integer | no | Minutes, 0 to 60, the condition must hold before the alert fires. Default 0: on the first breach |
| `host_ids` | array of string, uuid | no | Hosts of the team it applies to |
| `project_ids` | array of string, uuid | no | Projects of the team whose hosts it applies to |
### CreateMonitor
A new monitor. Only `label`, `protocol`, `uri` and `interval` are required; everything else has a sensible default.
| Field | Type | Required | Description |
|---|---|---|---|
| `label` | string | yes | Name shown in the dashboard, alerts and status pages |
| `protocol` | MonitorProtocol | yes | What a monitor checks, and so the format of its `uri`. \| \| \|---\| \| `https`
An HTTPS request to the URL in `uri`, with a certificate check. \| \| `http`
An HTTP request to the URL in `uri`. \| \| `icmp`
A ping (ICMP echo) to the host in `uri`. \| \| `tcp`
A TCP connect to `host:port`, optionally with a TLS handshake and a banner keyword. \| \| `dns`
A DNS query for a record of the name in `uri`, optionally compared with expected values. \| \| `smtp`
An SMTP greeting from `host:port` (port optional), with STARTTLS by default. \| \| `imap`
An IMAP greeting from `host:port` (port optional), over TLS by default. \| \| `pop3`
A POP3 greeting from `host:port` (port optional), over TLS by default. \| |
| `uri` | string | yes | The target: a URL for `http` and `https`, a host for `icmp`, `host:port` for `tcp`, `host` or `host:port` for mail, a DNS name for `dns`. Private and reserved addresses are refused. For `http` and `https` the scheme is optional: `example.com/health` and `https://example.com/health` give the same monitor, stored without the scheme. A scheme that differs from `protocol` (`http://` for an `https` monitor) is refused with `422` |
| `interval` | MonitorInterval | yes | Seconds between checks. Plans set the shortest interval a team may use. |
| `enabled` | boolean | no | Whether the monitor starts running at once. Default `true` |
| `primary_location` | MonitorLocation | no | A region checks run from. A monitor's primary region decides its uptime and alerts (a failed check is repeated from the same region about 5 seconds later before it is marked down); on the Team plan and up the other regions can also measure its response time. \| \| \|---\| \| `eu`
Europe. \| \| `us`
North America. \| \| `as`
Asia. \| \| `oc`
Oceania. \| |
| `timeout` | integer | no | Seconds before a check times out, 1 to 60. Default 30 |
| `max_redirects` | integer | no | HTTP: redirects to follow, 0 to 10; `null` follows up to 10 |
| `headers` | array of MonitorHeader | no | HTTP: up to 25 headers to send |
| `advanced_settings` | MonitorAdvancedSettingsInput | no | Protocol-specific settings to set. On update, settings you leave out keep their value; send `null` to reset one to its default. |
| `allow_insecure_requests` | boolean | no | HTTPS: accept invalid certificates for the check itself. Default `false` |
| `expected_http_status_code` | string | no | HTTP: status codes that count as up, comma-separated, `*` as a wildcard digit; `null` accepts 2xx and 3xx |
| `certificate_check_enabled` | boolean | no | Check the TLS certificate for validity and expiry (HTTPS, and TCP or mail with TLS). Default `false` |
| `certificate_expiry_threshold_days` | integer | no | Days before the certificate expires that the "expires soon" alert fires, 1 to 90. Default 14 |
| `performance_check_enabled` | boolean | no | Raise alerts for slow responses. Default `false` |
| `performance_hard_threshold` | integer | no | Milliseconds, 1 to 30000: a response slower than this raises an alert |
| `performance_deviation_percentage` | integer | no | Percent, 1 to 500: alert when recent response times are this much above the earlier ones (see the two timeframes) |
| `performance_deviation_timeframe` | integer | no | Minutes of recent checks to compare: 15, 30, 45, 60, 75, 90, 105 or 120. Must be shorter than `performance_deviation_before_timeframe` |
| `performance_deviation_before_timeframe` | integer | no | Minutes before those to compare with, a whole number of hours from 60 to 1440 |
| `regional_performance_enabled` | boolean | no | Also measure response time from the regions other than `primary_location`, every minute (or at the interval, when longer). Shown with the monitor's performance; not used for uptime or alerts. Team plan and up. Default `false` |
| `project_id` | string | no | Project to add the monitor to; default the team's default project, `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the monitor's alerts. Leave out or send `[]` to follow the project's paths, else the team's default path |
### CreateOnCallOverride
Someone to cover a schedule for a while, at most 90 days.
| Field | Type | Required | Description |
|---|---|---|---|
| `member_id` | string, uuid | yes | The member who covers |
| `starts_at` | string, date-time | yes | From when, as an ISO 8601 date and time |
| `ends_at` | string, date-time | yes | Until when; after `starts_at` |
| `note` | string | no | Why, for the team; up to 500 characters |
### CreateOnCallRotation
A new rotation layer of a schedule.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name, up to 255 characters |
| `position` | integer | no | Layer order, 0 for the top. Default: below the existing layers |
| `shift_unit` | OnCallShiftUnit | yes | The unit of a rotation's shift length. \| \| \|---\| \| `hours`
Absolute hours: shifts keep their length across DST changes. \| \| `days`
Calendar days in the schedule's time zone: the handoff stays at the same wall-clock time. \| \| `weeks`
Calendar weeks in the schedule's time zone. \| |
| `shift_length` | integer | yes | Shift length in `shift_unit`s: up to 720 hours, 90 days or 12 weeks |
| `start_date` | string, date | yes | The first handoff's date in the schedule's time zone; turns are counted from it |
| `handoff_time` | string | yes | Handoff time as `HH:MM` in the schedule's time zone |
| `restrictions` | OnCallRestrictionsInput | no | |
| `participant_ids` | array of string, uuid | no | 1 to 50 team members taking turns, in order |
### CreateOnCallSchedule
A new on-call schedule. Add rotation layers to it afterwards.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name, up to 255 characters |
| `description` | string | no | What the schedule covers, up to 1000 characters |
| `timezone` | string | yes | IANA time zone the rotations' dates, handoffs and restrictions are in |
### CreateProject
A new project.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Project name |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for alerts of the project's monitors and hosts. Leave out for none |
### CreateScheduledMaintenance
Maintenance to announce on a status page.
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | Title shown on the page, up to 255 characters |
| `description` | string | no | What happens and what visitors notice, in Markdown; `null` for none |
| `scheduled_at` | string, date-time | yes | Planned start, in the future |
| `scheduled_until` | string | no | Planned end, after `scheduled_at`; `null` for none |
| `automatic` | boolean | no | `true` (default): starts at `scheduled_at` and completes at `scheduled_until` by itself (without a planned end, complete it by setting `status`). `false`: only changes when you set `status` |
| `affected_components` | array of StatusPageAffectedComponentInput | no | Components it affects; components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers about it (default `true`) |
### CreateStatusPage
A new status page. Settings left out get their defaults.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name, shown as the page title |
| `slug` | string | no | The page's subdomain under spectate.page: lowercase letters, digits and dashes. Leave out to derive it from the name |
| `visibility` | StatusPageVisibility | no | Who can open a status page. \| \| \|---\| \| `public`
Anyone. \| \| `private`
Visitors with the access link, or the password when the page has one. Part of the Team plan and up. \| |
| `custom_domain` | string | no | Your own domain for the page, such as `status.acme.com`; `null` for none. Part of paid plans (`403` `PLAN_FEATURE_UNAVAILABLE` otherwise). A new domain needs to be verified again: see `custom_domain_verification` and `verifyStatusPageCustomDomain` |
| `password_protected` | boolean | no | Let visitors of a private page also get in with a password. Part of paid plans (`403` `PLAN_FEATURE_UNAVAILABLE` otherwise); turning it on needs a `password` unless the page has one |
| `password` | string | no | The password, 8 to 255 characters. Write-only; leave out or send `null` to keep the current one |
| `language` | StatusPageLanguage | no | Languages of the public status page chrome and the subscriber emails. Customer-written content (names, incident titles and updates) is never translated. \| \| \|---\| \| `en`
English. \| \| `nl`
Dutch. \| \| `de`
German. \| \| `fr`
French. \| \| `es`
Spanish. \| \| `it`
Italian. \| |
| `match_browser_language` | boolean | no | Give visitors their browser's language when it is supported |
| `theme` | StatusPageThemeInput | no | Changes to how a status page looks. Settings left out keep their value, also inside `light`, `dark` and `display`; `null` goes back to the default. Logos and the favicon are uploaded in the dashboard. |
| `collapsed_groups` | array of string | no | Component groups that start collapsed; replaces the current list |
| `automation_enabled` | boolean | no | Monitor automation: when a monitor linked to a component goes down, open an incident "{component} is down" (major outage), and resolve it when the monitor recovers |
| `automation_down_message` | string | no | Posted when a linked monitor goes down, up to 5000 characters; `{component}` and `{status_page}` are filled in. `null` for a default message |
| `automation_recovered_message` | string | no | Posted when the monitor recovers, up to 5000 characters; `null` for a default message |
| `issue_reports_enabled` | boolean | no | Let visitors report problems from the page |
| `issue_reports_show_on_page` | boolean | no | While reports are above the threshold, say on the page that users are reporting issues |
| `issue_reports_alerts_enabled` | boolean | no | Fire an alert when reports reach the threshold |
| `issue_reports_threshold` | integer | no | Reports within `issue_reports_window_minutes` that count as above the threshold, 1 to 1000 |
| `issue_reports_window_minutes` | integer | no | The window for the threshold, in minutes, 1 to 1440 |
| `traffic_alerts_enabled` | boolean | no | Alert when views reach `traffic_alert_multiplier` times the usual views for the time of day |
| `traffic_alert_multiplier` | integer | no | How many times the usual views alert, 2 to 100 |
| `traffic_alert_min_views` | integer | no | Fewer views than this in 15 minutes never alert, 10 to 1000000 |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the page's alerts (issue reports and traffic spikes); replaces the current ones. Empty for the team's default path |
### CreateStatusPageComponent
A new component of a status page. Its status follows incidents and maintenance.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Name shown on the page |
| `description` | string | no | Text shown with the name; `null` for none |
| `group` | string | no | Group to show the component in; `null` for the page's default group |
| `position` | integer | no | Order within the group, lowest first, from 0. New components go last when left out |
| `monitor_id` | string | no | A monitor of the team whose uptime history and response times the component shows, and whose downtime opens an incident when monitor automation is on; `null` for none |
| `show_latency_chart` | boolean | no | Show the monitor's response time chart under the component |
### CreateStatusPageImpactPeriod
A period during which a public incident affected a component. Periods of one component may not overlap within the incident.
| Field | Type | Required | Description |
|---|---|---|---|
| `component_id` | string, uuid | yes | A component of the status page |
| `impact` | ComponentImpact | yes | How badly an incident affects a component. A component's status is the worst impact it has at the moment. \| \| \|---\| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `started_at` | string, date-time | yes | When it started, now or in the past |
| `ended_at` | string | no | When it ended, after `started_at` and not in the future; `null` or left out while it goes on |
### CreateStatusPageIncident
A new public incident on a status page.
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | Title shown on the page |
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | no | The first update, in Markdown. Leave out to create the incident without one |
| `published_at` | string | no | When it happened, now or in the past (default now) |
| `impact` | ImpactLevel | no | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `incident_id` | string | no | The team's incident this one is for; `null` for none. Publishing from that incident (`publishIncidentStatusPageUpdate`) then posts here |
| `affected_components` | array of StatusPageAffectedComponentInput | no | The components it affects as of `published_at`, with their impact; components left out are no longer affected. Leave out to keep the impacts as they are; send `[]` for none. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers about the new incident (default `true`). `false` changes the page without emails |
### CreateStatusPageIncidentUpdate
An update to publish on a public incident.
| Field | Type | Required | Description |
|---|---|---|---|
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | yes | The message, in Markdown |
| `published_at` | string | no | When it happened, now or in the past (default now) |
| `affected_components` | array of StatusPageAffectedComponentInput | no | The components it affects as of `published_at`, with their impact; components left out are no longer affected. Leave out to keep the impacts as they are; send `[]` for none. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers about the update (default `true`). `false` changes the page without emails |
### Domain
A monitored domain registration: Spectate looks it up at its registry (RDAP or WHOIS) every few hours and alerts before it expires and, optionally, when its registrar, nameservers or DNSSEC change.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Domain ID |
| `name` | string | yes | The registered domain, lowercase, internationalised names in punycode |
| `enabled` | boolean | yes | Whether the domain is monitored. `false` when paused by a member or by the system (see `paused_reason`) |
| `paused_reason` | ResourcePauseReason | yes | |
| `registrar` | string | yes | The registrar, as the registry reports it |
| `registered_at` | string | yes | When the domain was registered |
| `expires_at` | string | yes | When the registration expires |
| `registry_changed_at` | string | yes | When the registration last changed at the registry |
| `days_until_expiration` | integer | yes | Days until the registration expires; negative once expired |
| `is_expired` | boolean | yes | Whether the registration has expired |
| `is_expiring_soon` | boolean | yes | Whether it expires within `expiry_threshold_days` |
| `nameservers` | array | yes | The domain's nameservers |
| `dnssec` | boolean | yes | Whether the registry publishes DNSSEC keys for the domain |
| `dnssec_keys` | array | yes | The DNSSEC delegation signer records |
| `statuses` | array | yes | EPP status codes, for example `client transfer prohibited` |
| `registry_source` | DomainRegistrySource | yes | |
| `registry_error` | DomainLookupError | yes | |
| `last_checked_at` | string | yes | When the registry was last checked |
| `expiry_threshold_days` | integer | yes | Days before expiry that the "expires soon" alert fires |
| `alert_on_registry_changes` | boolean | yes | Whether changes of the registrar, nameservers or DNSSEC keys raise an alert |
| `project_id` | string | yes | The project the domain belongs to; `null` for none |
| `escalation_paths` | array of EscalationPathReference | yes | Escalation paths the domain's alerts follow. Empty: the project's paths, else the team's default path |
| `created_at` | string, date-time | yes | When monitoring of the domain started |
### DomainDnssecKey
A DNSSEC delegation signer (DS) record the registry publishes for the domain.
| Field | Type | Required | Description |
|---|---|---|---|
| `key_tag` | integer | yes | Key tag of the DNSKEY the record points at |
| `algorithm` | integer | yes | DNSSEC algorithm number, for example 13 (ECDSA P-256 with SHA-256) |
| `digest_type` | integer | yes | Digest type number, for example 2 (SHA-256) |
| `digest` | string | yes | The digest, in hexadecimal |
### EscalationCondition
A condition of a branch. The branch continues on its `then` side when every condition holds, else on its `else` side.
| Field | Type | Required | Description |
|---|---|---|---|
| `field` | EscalationConditionField | yes | What an escalation branch can test about an alert (incident.io-style "if/else" branches). \| \| \|---\| \| `severity`
\| \| `working_hours`
Whether the branch is reached inside the path's working hours. \| \| `source`
The kind of check or integration that raised the alert (uptime, certificate, external…). \| \| `label`
A label sent along by an alert source (`metadata.labels`), e.g. `env=production`. \| |
| `operator` | EscalationConditionOperator | yes | How an escalation branch condition tests its field. `severity` and `source` take `is_one_of` and `is_not_one_of`; `working_hours` takes `within` and `outside`; `label` takes all four list and presence operators. \| \| \|---\| \| `is_one_of`
The value is one of `values`. \| \| `is_not_one_of`
The value is none of `values`. \| \| `within`
Reached inside the path's working hours. \| \| `outside`
Reached outside the path's working hours. \| \| `exists`
The label is set. \| \| `not_exists`
The label isn't set. \| |
| `key` | string | yes | `label` conditions: the label name sent by the alert source |
| `values` | array of string | yes | Values to match, for `is_one_of` and `is_not_one_of`: severities (`critical`, `high`, `medium`, `low`), sources (`uptime`, `performance`, `certificate`, `dns`, `domain`, `host_metric`, `status_page`, `external`, or `external:` such as `external:grafana`) or label values |
| `description` | string | yes | The condition in words |
### EscalationConditionInput
A condition of a branch. `severity` and `source` take `is_one_of` and `is_not_one_of` with `values`; `working_hours` takes `within` and `outside`; `label` takes a `key` and any of the four list and presence operators.
| Field | Type | Required | Description |
|---|---|---|---|
| `field` | EscalationConditionField | yes | What an escalation branch can test about an alert (incident.io-style "if/else" branches). \| \| \|---\| \| `severity`
\| \| `working_hours`
Whether the branch is reached inside the path's working hours. \| \| `source`
The kind of check or integration that raised the alert (uptime, certificate, external…). \| \| `label`
A label sent along by an alert source (`metadata.labels`), e.g. `env=production`. \| |
| `operator` | EscalationConditionOperator | yes | How an escalation branch condition tests its field. `severity` and `source` take `is_one_of` and `is_not_one_of`; `working_hours` takes `within` and `outside`; `label` takes all four list and presence operators. \| \| \|---\| \| `is_one_of`
The value is one of `values`. \| \| `is_not_one_of`
The value is none of `values`. \| \| `within`
Reached inside the path's working hours. \| \| `outside`
Reached outside the path's working hours. \| \| `exists`
The label is set. \| \| `not_exists`
The label isn't set. \| |
| `key` | string | no | `label` conditions: the label name sent by the alert source, up to 100 characters |
| `values` | array of string | no | Up to 20 values to match, for `is_one_of` and `is_not_one_of`: severities, sources (`uptime`, `external:grafana`…) or label values |
### EscalationConditionInputRequest
A condition of a branch. `severity` and `source` take `is_one_of` and `is_not_one_of` with `values`; `working_hours` takes `within` and `outside`; `label` takes a `key` and any of the four list and presence operators.
| Field | Type | Required | Description |
|---|---|---|---|
| `field` | EscalationConditionField | yes | What an escalation branch can test about an alert (incident.io-style "if/else" branches). \| \| \|---\| \| `severity`
\| \| `working_hours`
Whether the branch is reached inside the path's working hours. \| \| `source`
The kind of check or integration that raised the alert (uptime, certificate, external…). \| \| `label`
A label sent along by an alert source (`metadata.labels`), e.g. `env=production`. \| |
| `operator` | EscalationConditionOperator | yes | How an escalation branch condition tests its field. `severity` and `source` take `is_one_of` and `is_not_one_of`; `working_hours` takes `within` and `outside`; `label` takes all four list and presence operators. \| \| \|---\| \| `is_one_of`
The value is one of `values`. \| \| `is_not_one_of`
The value is none of `values`. \| \| `within`
Reached inside the path's working hours. \| \| `outside`
Reached outside the path's working hours. \| \| `exists`
The label is set. \| \| `not_exists`
The label isn't set. \| |
| `key` | string | no | `label` conditions: the label name sent by the alert source, up to 100 characters |
| `values` | array of string | no | Up to 20 values to match, for `is_one_of` and `is_not_one_of`: severities, sources (`uptime`, `external:grafana`…) or label values |
### EscalationPath
An escalation path: what happens when an alert fires, step by step, until someone acknowledges it. Monitors, hosts, domains and alert sources use their own paths, their project's, or the team's default path.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Escalation path ID |
| `name` | string | yes | Name |
| `description` | string | yes | What the path is for |
| `enabled` | boolean | yes | Whether alerts follow the path. Alerts of a disabled path don't escalate |
| `is_default` | boolean | yes | Whether this is the team's default path, for resources without paths of their own or of their project. One per team |
| `working_hours` | WorkingHours | yes | Weekly working hours, for branch conditions and "until working hours" waits. |
| `steps` | array of EscalationStep | yes | The steps, in order; a `branch` continues in its `then` and `else` steps |
| `warnings` | array of EscalationPathWarning | yes | Problems that keep the path from reaching someone; empty when it can deliver |
| `created_at` | string, date-time | yes | When the path was created |
### EscalationPathReference
An escalation path a resource's alerts follow.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Escalation path ID |
| `name` | string | yes | Escalation path name |
### EscalationPathWarning
A delivery problem of an escalation path.
| Field | Type | Required | Description |
|---|---|---|---|
| `code` | EscalationPathWarningCode | yes | A problem that keeps an escalation path from reaching someone. \| \| \|---\| \| `no_deliverable_steps`
Every notify step targets a disabled channel or a deleted schedule: alerts reach nobody. \| \| `disabled_channels`
Some channels are disabled; their steps are skipped. \| \| `missing_schedules`
An on-call step's schedule was deleted; the step is skipped. \| |
| `message` | string | yes | The problem in words |
### EscalationStep
A step of an escalation path. Steps run in order, each after its wait. A `branch` is always the last step of its list: alerts go on with its `then` steps when its conditions hold, else with its `else` steps.
| Field | Type | Required | Description |
|---|---|---|---|
| `type` | EscalationStepAction | yes | What an escalation step does. \| \| \|---\| \| `notify_channel`
Send the alert to a channel. \| \| `create_incident`
Declare an incident for the alert. \| \| `notify_on_call`
Page whoever is on call in a schedule, by email and their own phone. \| \| `branch`
If/else: alerts meeting every condition continue on its `then` side, the rest on its `else` side. \| |
| `delay_minutes` | integer | yes | Minutes to wait before the step runs; `null` for a branch (decided at once) or when `delay_until` applies |
| `delay_until` | EscalationDelayUntil | yes | |
| `channel` | ChannelReference | yes | |
| `schedule` | OnCallScheduleReference | yes | |
| `conditions` | array | yes | `branch` steps: the conditions; all must hold for `then` |
| `then` | array | yes | `branch` steps: what happens when the conditions hold |
| `else` | array | yes | `branch` steps: what happens otherwise |
### EscalationStepInput
A step to run. `notify_channel` needs `channel_id`, `notify_on_call` needs `schedule_id`, `branch` needs `conditions` and ends its list: what follows goes in its `then` and `else`.
| Field | Type | Required | Description |
|---|---|---|---|
| `type` | EscalationStepAction | yes | What an escalation step does. \| \| \|---\| \| `notify_channel`
Send the alert to a channel. \| \| `create_incident`
Declare an incident for the alert. \| \| `notify_on_call`
Page whoever is on call in a schedule, by email and their own phone. \| \| `branch`
If/else: alerts meeting every condition continue on its `then` side, the rest on its `else` side. \| |
| `delay_minutes` | integer | no | Minutes, 0 to 1440, to wait before the step runs. Default 0. Not for branches |
| `delay_until` | EscalationDelayUntil | no | |
| `channel_id` | string, uuid | no | `notify_channel`: the channel to send to |
| `schedule_id` | string, uuid | no | `notify_on_call`: the schedule whose person on call is paged (on-call is part of the Team plan and up) |
| `conditions` | array of EscalationConditionInput | no | `branch`: 1 to 10 conditions; all must hold for `then` |
| `then` | array of EscalationStepInput | no | `branch`: the steps when the conditions hold; empty ends the escalation there |
| `else` | array of EscalationStepInput | no | `branch`: the steps otherwise; empty ends the escalation there |
### EscalationStepInputRequest
A step to run. `notify_channel` needs `channel_id`, `notify_on_call` needs `schedule_id`, `branch` needs `conditions` and ends its list: what follows goes in its `then` and `else`.
| Field | Type | Required | Description |
|---|---|---|---|
| `type` | EscalationStepAction | yes | What an escalation step does. \| \| \|---\| \| `notify_channel`
Send the alert to a channel. \| \| `create_incident`
Declare an incident for the alert. \| \| `notify_on_call`
Page whoever is on call in a schedule, by email and their own phone. \| \| `branch`
If/else: alerts meeting every condition continue on its `then` side, the rest on its `else` side. \| |
| `delay_minutes` | integer | no | Minutes, 0 to 1440, to wait before the step runs. Default 0. Not for branches |
| `delay_until` | EscalationDelayUntil | no | |
| `channel_id` | string, uuid | no | `notify_channel`: the channel to send to |
| `schedule_id` | string, uuid | no | `notify_on_call`: the schedule whose person on call is paged (on-call is part of the Team plan and up) |
| `conditions` | array of EscalationConditionInput | no | `branch`: 1 to 10 conditions; all must hold for `then` |
| `then` | array of EscalationStepInput | no | `branch`: the steps when the conditions hold; empty ends the escalation there |
| `else` | array of EscalationStepInput | no | `branch`: the steps otherwise; empty ends the escalation there |
### Host
A server with the Spectate agent, which reports CPU, memory, disk and network metrics. Hosts are added by installing the agent with an install token, not through the API.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Host ID |
| `label` | string | yes | Name shown in the dashboard and alerts; the agent sets the hostname until you change it |
| `state` | HostState | yes | Whether a host's agent reports. \| \| \|---\| \| `up`
Reported in the last 15 minutes. \| \| `stale`
Reported before, but not in the last 15 minutes. \| \| `pending`
The agent never reported. \| |
| `host_info` | object | yes | What the agent reports about the system, as key-value pairs (for example `hostname`, `os`, `platform`, `kernel_version`); the keys depend on the agent version and platform |
| `cpu_info` | array | yes | The CPUs, each as key-value pairs (for example `model_name`, `cores`, `mhz`) |
| `agent_version` | string | yes | Version of the agent |
| `agent_update_version` | string | yes | A newer agent release, when the host runs an older one (`sudo spectate-agent update`) |
| `clock_offset_ms` | integer | yes | Server time minus the host's clock, in milliseconds, as last measured by a v2 agent; `null` when unknown |
| `last_seen_at` | string | yes | When the agent last reported |
| `no_data_alert_minutes` | integer | yes | Minutes without data before the "no data received" alert fires; `null` when that alert is off |
| `paused_reason` | ResourcePauseReason | yes | |
| `project_id` | string | yes | The project the host belongs to; `null` for none |
| `escalation_paths` | array of EscalationPathReference | yes | Escalation paths the host's alerts follow. Empty: the project's paths, else the team's default path |
| `created_at` | string, date-time | yes | When the host registered |
| `health` | array of HostHealthCheckResult | yes | Health checks (agent 2.1 or later): failed services, out of memory, reboot, updates, clock, file handles and pressure. Checks of collectors that are switched off, and Linux-only checks on other systems, are left out |
| `health_issues` | integer | yes | Number of health checks that need attention (`warning` or `critical`) |
### HostHealthCheckResult
One health check of a host, computed from what agent 2.1 or later reports.
| Field | Type | Required | Description |
|---|---|---|---|
| `check` | HostHealthCheck | yes | A host health check, computed from what agent 2.1+ reports. \| \| \|---\| \| `services`
Failed systemd services. \| \| `oom`
Processes killed for lack of memory (OOM kills) in the last 24 hours. \| \| `reboot`
The system needs a reboot (after kernel or library updates). \| \| `updates`
Pending package updates, security updates in particular. \| \| `clock`
Whether the clock is synchronised (NTP) and close to the server's. \| \| `files`
Open file handles against the system's maximum. \| \| `pressure`
Tasks stalled waiting for memory or I/O (pressure stall information). \| |
| `status` | HealthStatus | yes | Verdict of a host health check. \| \| \|---\| \| `ok`
Nothing to do. \| \| `warning`
Needs attention soon: a reboot or security updates pending, the clock not synchronised. \| \| `critical`
Needs attention now: a service failed, processes were killed for lack of memory. \| \| `unknown`
The agent does not report it (yet): an older agent, or nothing to report on this host. \| |
| `detail` | string | yes | What was found, in one line |
| `since` | string | yes | Since when the problem has lasted (for out of memory: the last kill); `null` when there is none |
### HostInstallToken
An install token: agents use it to register hosts with the team. Any number of hosts can use one token until it expires or is revoked.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Install token ID |
| `token` | string | yes | The token to give the agent's installer (`--token`) |
| `expires_at` | string | yes | When the token stops registering new hosts. Hosts that registered keep reporting |
| `created_at` | string, date-time | yes | When the token was created |
### HostReference
A host something applies to.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Host ID |
| `label` | string | yes | Host name shown in the dashboard; `null` until set or reported |
### Incident
An incident: a problem that affects customers, worked on by the team, with updates, roles and eventually a postmortem. Incidents are declared by hand, through the API, from Slack, or by an escalation path's `create_incident` step.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Incident ID |
| `number` | integer | yes | The team's sequence number: `INC-42` is 42. `null` for some older incidents |
| `reference` | string | yes | The human reference |
| `title` | string | yes | What's going on |
| `summary` | string | yes | More about it, in Markdown |
| `severity` | Severity | yes | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `started_at` | string, date-time | yes | When it started |
| `acknowledged_at` | string | yes | When someone acknowledged it |
| `resolved_at` | string | yes | When it was resolved |
| `alert_id` | string | yes | The alert that opened it, for incidents declared by an escalation path |
| `roles` | array of IncidentRoleAssignment | yes | Who has which role |
| `created_at` | string, date-time | yes | When it was declared |
### IncidentPostmortem
An incident's postmortem: what happened, why, and what changes.
| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string | yes | The postmortem, in Markdown |
| `published` | boolean | yes | Whether it is marked as published (final). It is not shown on status pages |
| `updated_at` | string, date-time | yes | When it last changed |
### IncidentPostmortemResult
An incident's postmortem, if it has one.
| Field | Type | Required | Description |
|---|---|---|---|
| `postmortem` | IncidentPostmortem | yes | |
### IncidentRoleAssignment
Who has a role in an incident.
| Field | Type | Required | Description |
|---|---|---|---|
| `role` | IncidentRole | yes | A role in handling an incident; one member each. \| \| \|---\| \| `commander`
Leads the response and makes the calls. \| \| `communications_lead`
Keeps customers and the company informed, for example through the status page. \| |
| `member` | MemberReference | yes | A member of the team. |
### IncidentTimelineEntry
Something that happened in an incident.
| Field | Type | Required | Description |
|---|---|---|---|
| `description` | string | yes | What happened |
| `actor` | string | yes | Who did it: a member's name, `API token "…"`, or Spectate staff; `null` for Spectate itself |
| `actor_type` | ActivityCauserType | yes | |
| `created_at` | string, date-time | yes | When it happened |
### IncidentUpdate
An update posted to an incident: what's known now, and its status at that moment.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Update ID |
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | yes | The update, in Markdown |
| `created_at` | string, date-time | yes | When it was posted |
### Invite
An invite to join the team, sent by email. The invitee accepts it in the dashboard with an account for that address.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Invite ID |
| `email` | string, email | yes | The invitee's email address |
| `role` | TeamRole | yes | A member's role in the team: what they may do. \| \| \|---\| \| `owner`
Everything, including billing and deleting the team. One per team. \| \| `manager`
Everything but billing and deleting the team. \| \| `admin`
Configure monitoring, alerting, incidents and status pages; can't manage members or API tokens. \| \| `member`
Read everything; manage monitors and incidents, acknowledge alerts. \| \| `billing`
Billing and support only. \| |
| `expired` | boolean | yes | Whether it expired without being accepted. Expired invites don't count towards the member limit and can be sent again |
| `expires_at` | string, date-time | yes | When it expires, 7 days after it was sent |
| `created_at` | string, date-time | yes | When it was sent |
### Member
A member of the team. Use member IDs for on-call rotations and incident roles.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Member (user) ID |
| `name` | string | yes | Name |
| `email` | string, email | yes | Email address |
| `role` | TeamRole | yes | A member's role in the team: what they may do. \| \| \|---\| \| `owner`
Everything, including billing and deleting the team. One per team. \| \| `manager`
Everything but billing and deleting the team. \| \| `admin`
Configure monitoring, alerting, incidents and status pages; can't manage members or API tokens. \| \| `member`
Read everything; manage monitors and incidents, acknowledge alerts. \| \| `billing`
Billing and support only. \| |
| `joined_at` | string | yes | When they joined the team |
### MemberReference
A member of the team.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Member (user) ID |
| `name` | string | yes | Name |
| `email` | string, email | yes | Email address |
### MetricCondition
An alert rule for host metrics, for example "CPU usage above 90% for 5 minutes". It applies to its hosts and to every host of its projects.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Metric condition ID |
| `metric` | MetricPoint | yes | A host metric the agent reports. `cpu_usage`, `memory_usage`, `disk_usage`, `load_average`, `network_in` and `network_out` are the summaries the dashboard charts; the `system.*` metrics are the agent's raw values. |
| `condition` | MetricCondition | yes | An alert rule for host metrics, for example "CPU usage above 90% for 5 minutes". It applies to its hosts and to every host of its projects. |
| `threshold` | number | yes | Compared with the metric's value as the agent reports it, in the unit the host's charts show (percent for `cpu_usage`, `memory_usage` and `disk_usage`) |
| `duration_minutes` | integer | yes | Minutes the condition must hold before the alert fires; 0 fires on the first breach |
| `severity` | Severity | yes | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `hosts` | array of HostReference | yes | Hosts it applies to |
| `projects` | array of ProjectReference | yes | Projects whose hosts it applies to |
### Monitor
A monitor: a check of a URL, host or DNS name from Spectate's regions, with its settings and latest results.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Monitor ID |
| `label` | string | yes | Name shown in the dashboard, alerts and status pages |
| `protocol` | MonitorProtocol | yes | What a monitor checks, and so the format of its `uri`. \| \| \|---\| \| `https`
An HTTPS request to the URL in `uri`, with a certificate check. \| \| `http`
An HTTP request to the URL in `uri`. \| \| `icmp`
A ping (ICMP echo) to the host in `uri`. \| \| `tcp`
A TCP connect to `host:port`, optionally with a TLS handshake and a banner keyword. \| \| `dns`
A DNS query for a record of the name in `uri`, optionally compared with expected values. \| \| `smtp`
An SMTP greeting from `host:port` (port optional), with STARTTLS by default. \| \| `imap`
An IMAP greeting from `host:port` (port optional), over TLS by default. \| \| `pop3`
A POP3 greeting from `host:port` (port optional), over TLS by default. \| |
| `uri` | string | yes | The target as stored: a URL without the scheme for `http` and `https` (the protocol is the scheme), a host for `icmp`, `host:port` for `tcp` and mail, a DNS name for `dns`. `url` has the full URL |
| `url` | string | yes | The target as the dashboard shows it, for example `smtp://mail.example.com:587` for SMTP |
| `interval` | MonitorInterval | yes | Seconds between checks. Plans set the shortest interval a team may use. |
| `primary_location` | MonitorLocation | yes | A region checks run from. A monitor's primary region decides its uptime and alerts (a failed check is repeated from the same region about 5 seconds later before it is marked down); on the Team plan and up the other regions can also measure its response time. \| \| \|---\| \| `eu`
Europe. \| \| `us`
North America. \| \| `as`
Asia. \| \| `oc`
Oceania. \| |
| `timeout` | integer | yes | Seconds before a check times out |
| `max_redirects` | integer | yes | HTTP: redirects followed before the check fails; `null` follows up to 10 |
| `headers` | array of MonitorHeader | yes | HTTP: headers sent with every check |
| `advanced_settings` | MonitorAdvancedSettings | yes | Protocol-specific settings of a monitor. Settings that don't apply to its protocol are `null`. The password is never returned; `has_auth_password` says whether one is set. |
| `enabled` | boolean | yes | Whether the monitor runs. `false` when paused by a member or by the system (see `paused_reason`) |
| `paused_reason` | ResourcePauseReason | yes | |
| `allow_insecure_requests` | boolean | yes | HTTPS: whether invalid certificates are accepted for the check itself (the certificate check still reports them) |
| `expected_http_status_code` | string | yes | HTTP: status codes that count as up, comma-separated, `*` as a wildcard digit (`2**,301`); `null` accepts 2xx and 3xx |
| `certificate_check_enabled` | boolean | yes | Whether the TLS certificate is checked for validity and expiry |
| `certificate_expiry_threshold_days` | integer | yes | Days before the certificate expires that the "expires soon" alert fires |
| `uses_tls` | boolean | yes | Whether a check reports a certificate: HTTPS, and TCP or mail with TLS |
| `certificate_status` | CertificateStatus | yes | |
| `certificate_expires_at` | string | yes | When the certificate expires |
| `certificate_valid_from` | string | yes | When the certificate became valid |
| `certificate_issuer` | string | yes | Who issued the certificate |
| `certificate_error` | string | yes | Why the certificate isn't valid, with `certificate_status` `invalid` or `expired` |
| `certificate_checked_at` | string | yes | When the certificate was last checked |
| `performance_check_enabled` | boolean | yes | Whether slow responses raise alerts (`performance_hard_threshold`, `performance_deviation_percentage`) |
| `performance_hard_threshold` | integer | yes | Milliseconds: a response slower than this raises an alert |
| `performance_deviation_percentage` | integer | yes | Percent: an alert fires when the average response time of the last `performance_deviation_timeframe` minutes is this much above the average of the `performance_deviation_before_timeframe` minutes before |
| `performance_deviation_timeframe` | integer | yes | Minutes of recent checks compared (15 to 120, in steps of 15) |
| `performance_deviation_before_timeframe` | integer | yes | Minutes before those that they're compared with (60 to 1440, in whole hours) |
| `regional_performance_enabled` | boolean | yes | Also measure response time from the regions other than `primary_location`, every minute (or at the interval, when longer). Shown with the monitor's performance; not used for uptime or alerts. Team plan and up |
| `uptime_status` | UptimeStatus | yes | Whether a monitor's target answers, from its latest checks. \| \| \|---\| \| `pending`
Not checked yet. \| \| `up`
The latest check succeeded. \| \| `down`
Checks fail: a failed check, repeated from the same region about 5 seconds later, failed again. \| |
| `uptime_status_changed_at` | string | yes | When `uptime_status` last changed |
| `last_checked_at` | string | yes | When the monitor was last checked |
| `response_time` | integer | yes | Milliseconds the latest check took |
| `check_details` | MonitorCheckDetails | yes | |
| `uptime` | MonitorUptime | yes | Share of successful checks, in percent, over rolling windows; `null` until there is data. |
| `project_id` | string | yes | The project the monitor belongs to; `null` for none |
| `escalation_paths` | array of EscalationPathReference | yes | Escalation paths the monitor's alerts follow. Empty: the project's paths, else the team's default path |
| `created_at` | string, date-time | yes | When the monitor was created |
| `updated_at` | string, date-time | yes | When the monitor's settings last changed |
### MonitorAdvancedSettings
Protocol-specific settings of a monitor. Settings that don't apply to its protocol are `null`. The password is never returned; `has_auth_password` says whether one is set.
| Field | Type | Required | Description |
|---|---|---|---|
| `connection_timeout` | integer | yes | Seconds to wait for the connection; `null` uses the monitor's `timeout` |
| `auth_method` | MonitorAuthMethod | yes | |
| `auth_user` | string | yes | HTTP: user name for `basic` and `digest` |
| `has_auth_password` | boolean | yes | HTTP: whether a password or bearer token is stored |
| `keyword` | string | yes | HTTP: text the response body must contain (or must not, with `keyword_inverted`). TCP: the same for the server's banner |
| `keyword_inverted` | boolean | yes | Whether the check fails when `keyword` is found, instead of when it's missing |
| `useragent` | string | yes | HTTP: the `User-Agent` header; `null` sends Spectate's |
| `method` | MonitorHttpMethod | yes | |
| `tls_mode` | TlsMode | yes | |
| `dns_record_type` | DnsRecordType | yes | |
| `dns_resolver` | string | yes | DNS: the resolver to query, as `ip` or `ip:port`; `null` uses the checker's resolver |
| `dns_authoritative` | boolean | yes | DNS: whether to ask the zone's authoritative nameservers directly |
| `dns_expected_values` | array | yes | DNS: values the answer must contain or equal (see `dns_match`); `null` or empty accepts any answer |
| `dns_match` | DnsMatch | yes | |
| `dns_alert_on_change` | boolean | yes | DNS: whether a changed answer raises an alert |
### MonitorAdvancedSettingsInput
Protocol-specific settings to set. On update, settings you leave out keep their value; send `null` to reset one to its default.
| Field | Type | Required | Description |
|---|---|---|---|
| `connection_timeout` | integer | no | Seconds to wait for the connection, 1 to 60; `null` uses the monitor's `timeout` |
| `auth_method` | MonitorAuthMethod | no | |
| `auth_user` | string | no | HTTP: user name for `basic` and `digest` |
| `auth_password` | string | no | HTTP: password, or the token for `bearer`. Write-only: never returned. Leave out or send an empty string to keep the stored one |
| `keyword` | string | no | HTTP: text the response body must contain (or must not, with `keyword_inverted`). TCP: the same for the server's banner |
| `keyword_inverted` | boolean | no | Fail the check when `keyword` is found, instead of when it's missing |
| `useragent` | string | no | HTTP: the `User-Agent` header; `null` sends Spectate's |
| `method` | MonitorHttpMethod | no | |
| `tls_mode` | TlsMode | no | |
| `dns_record_type` | DnsRecordType | no | |
| `dns_resolver` | string | no | DNS: the resolver to query, as a public `ip` or `ip:port`; `null` uses the checker's resolver |
| `dns_authoritative` | boolean | no | DNS: ask the zone's authoritative nameservers directly |
| `dns_expected_values` | array | no | DNS: up to 20 values the answer must contain or equal (see `dns_match`) |
| `dns_match` | DnsMatch | no | |
| `dns_alert_on_change` | boolean | no | DNS: raise an alert when the answer changes |
### MonitorCheckDetails
Protocol details of the latest check, as the checker reported them. Fields that don't apply to the protocol are `null`.
| Field | Type | Required | Description |
|---|---|---|---|
| `banner` | string | yes | TCP and mail: the first line of the server's greeting or banner |
| `reply_code` | integer | yes | SMTP: the greeting's reply code |
| `starttls` | boolean | yes | Mail: whether the session was upgraded with STARTTLS (or STLS) |
| `tls_version` | string | yes | The negotiated TLS version |
| `cipher_suite` | string | yes | The negotiated cipher suite |
| `dns_answers` | array | yes | DNS: the answer's values of the queried record type, sorted |
| `dns_server` | string | yes | DNS: the server that answered, as `ip:port` |
| `dns_rcode` | string | yes | DNS: the response code |
### MonitorHeader
A request header an HTTP monitor sends.
| Field | Type | Required | Description |
|---|---|---|---|
| `key` | string | yes | Header name |
| `value` | string | yes | Header value |
### MonitorReference
A monitor something follows.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Monitor ID |
| `label` | string | yes | Monitor name |
### MonitorUptime
Share of successful checks, in percent, over rolling windows; `null` until there is data.
| Field | Type | Required | Description |
|---|---|---|---|
| `twenty_four_hours` | number | yes | Last 24 hours |
| `seven_days` | number | yes | Last 7 days |
| `thirty_days` | number | yes | Last 30 days |
| `ninety_days` | number | yes | Last 90 days |
### NotificationCredits
Credits for SMS and voice notifications. The monthly allowance is spent first; bought credits never expire.
| Field | Type | Required | Description |
|---|---|---|---|
| `balance` | integer | yes | Credits that can be spent now: what's left of this month's allowance plus bought credits |
| `allowance` | integer | yes | What's left of this month's allowance |
| `purchased` | integer | yes | Bought credits left |
| `monthly` | integer | yes | The plan's monthly allowance; 0 during the trial |
| `reset_at` | string | yes | When the allowance was last reset; `null` before the first reset |
### OnCallNow
Who is on call at a moment.
| Field | Type | Required | Description |
|---|---|---|---|
| `shift` | OnCallShift | yes | |
### OnCallOverride
Someone covering a schedule for a while, whatever the rotations say.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Override ID |
| `member` | MemberReference | yes | A member of the team. |
| `starts_at` | string, date-time | yes | From when |
| `ends_at` | string, date-time | yes | Until when |
| `note` | string | yes | Why, for the team |
| `created_by` | MemberReference | yes | |
| `created_at` | string, date-time | yes | When it was added |
### OnCallRestrictions
When a rotation layer covers, each week; outside it the layers below take over.
| Field | Type | Required | Description |
|---|---|---|---|
| `days` | array of integer | yes | ISO weekdays the layer covers, 1 (Monday) to 7 (Sunday) |
| `start_time` | string | yes | From when on those days, as `HH:MM` in the schedule's time zone; `null` with `end_time` `null` for the whole day |
| `end_time` | string | yes | Until when, as `HH:MM`; before `start_time` runs past midnight |
### OnCallRestrictionsInput
When a rotation layer covers, each week.
| Field | Type | Required | Description |
|---|---|---|---|
| `days` | array of integer | yes | ISO weekdays the layer covers, 1 (Monday) to 7 (Sunday), at least one |
| `start_time` | string | no | From when on those days, as `HH:MM` in the schedule's time zone; leave out with `end_time` for the whole day |
| `end_time` | string | no | Until when, as `HH:MM` |
### OnCallRotation
A rotation layer: its participants take turns of `shift_length` `shift_unit`s, from `start_date` at `handoff_time`. Where layers overlap, the top layer (`position` 0) wins.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Rotation ID |
| `name` | string | yes | Name |
| `position` | integer | yes | Layer order; 0 is the top layer and wins where layers overlap |
| `shift_unit` | OnCallShiftUnit | yes | The unit of a rotation's shift length. \| \| \|---\| \| `hours`
Absolute hours: shifts keep their length across DST changes. \| \| `days`
Calendar days in the schedule's time zone: the handoff stays at the same wall-clock time. \| \| `weeks`
Calendar weeks in the schedule's time zone. \| |
| `shift_length` | integer | yes | Shift length in `shift_unit`s |
| `start_date` | string, date | yes | The first handoff's date in the schedule's time zone |
| `handoff_time` | string | yes | Handoff time as `HH:MM` in the schedule's time zone |
| `restrictions` | OnCallRestrictions | yes | |
| `participants` | array of MemberReference | yes | The members taking turns, in order |
| `created_at` | string, date-time | yes | When the rotation was created |
### OnCallSchedule
An on-call schedule: rotation layers and overrides that decide who gets paged when an escalation path's `notify_on_call` step runs.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Schedule ID |
| `name` | string | yes | Name |
| `description` | string | yes | What the schedule covers |
| `timezone` | string | yes | IANA time zone the rotations' dates, handoffs and restrictions are in |
| `current` | OnCallShift | yes | |
| `next_handoff_at` | string | yes | When the person on call changes next, within 4 weeks |
| `next` | OnCallShift | yes | |
| `rotations` | array of OnCallRotation | yes | Rotation layers, top first |
| `overrides` | array of OnCallOverride | yes | Overrides that haven't ended |
| `used_by` | array of EscalationPathReference | yes | Escalation paths with a step that pages this schedule |
| `created_at` | string, date-time | yes | When the schedule was created |
### OnCallScheduleReference
An on-call schedule something pages.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | On-call schedule ID |
| `name` | string | yes | Schedule name |
### OnCallShift
A stretch of time someone is on call.
| Field | Type | Required | Description |
|---|---|---|---|
| `member` | MemberReference | yes | |
| `starts_at` | string, date-time | yes | When the shift starts |
| `ends_at` | string, date-time | yes | When it ends |
| `source` | OnCallShiftSource | yes | Where an on-call shift comes from. \| \| \|---\| \| `rotation`
A rotation layer's turn. \| \| `override`
An override someone added. \| |
| `rotation_id` | string | yes | The rotation layer, for rotation shifts |
| `override_id` | string | yes | The override, for override shifts |
### OnCallTimeline
Who is on call over a window: each layer's shifts, the overrides, and the result.
| Field | Type | Required | Description |
|---|---|---|---|
| `from` | string, date-time | yes | Start of the window |
| `to` | string, date-time | yes | End of the window |
| `timezone` | string | yes | The schedule's time zone |
| `layers` | array of OnCallTimelineLayer | yes | Each layer's shifts, top layer first |
| `overrides` | array of OnCallShift | yes | Override shifts |
| `final` | array of OnCallShift | yes | Who actually gets paged when: overrides first, then the highest layer. Gaps are absent |
### OnCallTimelineLayer
One rotation layer's shifts in a timeline.
| Field | Type | Required | Description |
|---|---|---|---|
| `rotation_id` | string, uuid | yes | Rotation ID |
| `name` | string | yes | Rotation name |
| `position` | integer | yes | Layer order; 0 is the top layer |
| `shifts` | array of OnCallShift | yes | The layer's own shifts, before overrides and higher layers |
### Project
A project: a group of monitors and hosts that share escalation paths. Every team has one default project, which can't be deleted.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Project ID |
| `name` | string | yes | Project name |
| `is_default` | boolean | yes | Whether this is the team's default project, which new monitors and hosts join when no project is given. It can't be deleted |
| `escalation_paths` | array of EscalationPathReference | yes | Escalation paths that alerts of this project's monitors and hosts follow, unless a monitor or host sets its own |
| `created_at` | string, date-time | yes | When the project was created |
### ProjectReference
A project a resource belongs to or applies to.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Project ID |
| `name` | string | yes | Project name |
### PublishStatusPageUpdate
An update of the team's incident to publish on a status page.
| Field | Type | Required | Description |
|---|---|---|---|
| `status_page_id` | string, uuid | yes | The status page to publish on |
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | yes | The message visitors read, in Markdown |
| `impact` | ImpactLevel | no | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `published_at` | string | no | When it happened, now or in the past (default now) |
| `affected_components` | array of StatusPageAffectedComponentInput | no | The components it affects as of `published_at`, with their impact; components left out are no longer affected. Leave out to keep the impacts as they are; send `[]` for none. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers about the update (default `true`). `false` changes the page without emails |
### ResolveIncident
How an incident ends.
| Field | Type | Required | Description |
|---|---|---|---|
| `message` | string | no | A closing update, in Markdown; leave out for none |
### SavePostmortem
An incident's postmortem.
| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string | yes | The whole postmortem, in Markdown; replaces the current one |
| `published` | boolean | no | Mark it as published (final), or as a draft again. Leave out to keep its state |
### SaveStatusPageIncidentWriteup
The public write-up to save on a status page incident.
| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string | no | The write-up, in Markdown, at most 50,000 characters. Required to publish |
| `published` | boolean | yes | `true` shows it on the public incident page; `false` keeps it as a draft, or takes a published write-up down |
| `notify_subscribers` | boolean | no | Email confirmed subscribers when this publishes the write-up for the first time (default `false`). Edits to a published write-up are never emailed |
### ScheduledMaintenance
Planned maintenance announced on a status page. While it is in progress its components show as under maintenance.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Maintenance ID |
| `title` | string | yes | Title shown on the page |
| `description` | string | yes | What happens and what visitors notice, in Markdown; `null` for none |
| `status` | ScheduledMaintenanceStatus | yes | Where a scheduled maintenance stands. \| \| \|---\| \| `scheduled`
Announced, not started yet. \| \| `in_progress`
Going on: its components show as under maintenance. \| \| `completed`
Over. \| |
| `automatic` | boolean | yes | `true`: starts at `scheduled_at` and completes at `scheduled_until` by itself (without a planned end it is completed by hand). `false`: only changes when you set `status` |
| `scheduled_at` | string, date-time | yes | Planned start |
| `scheduled_until` | string | yes | Planned end; `null` for none |
| `started_at` | string | yes | When it actually went in progress; `null` before |
| `completed_at` | string | yes | When it completed; `null` before |
| `affected_components` | array of StatusPageAffectedComponent | yes | Components it affects |
| `created_at` | string, date-time | yes | When it was created |
### StatusPage
A status page: the public page that shows your components' status, incidents and maintenance.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Status page ID |
| `name` | string | yes | Name, shown as the page title |
| `slug` | string | yes | The page's subdomain under spectate.page |
| `visibility` | StatusPageVisibility | yes | Who can open a status page. \| \| \|---\| \| `public`
Anyone. \| \| `private`
Visitors with the access link, or the password when the page has one. Part of the Team plan and up. \| |
| `status` | ComponentStatus | yes | A status page component's status, derived from incidents and maintenance. \| \| \|---\| \| `operational`
Working normally. \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| \| `under_maintenance`
In planned maintenance. \| |
| `public_url` | string, uri | yes | Where visitors open the page: the custom domain once it is verified, else the spectate.page address |
| `access_url` | string, uri | yes | Opens the page while it is private. Anyone with it gets in; `rotateStatusPageAccessKey` replaces it |
| `custom_domain` | string | yes | Your own domain for the page; `null` for none. Visitors use it once it is verified |
| `custom_domain_verification` | StatusPageCustomDomainVerification | yes | |
| `password_protected` | boolean | yes | Whether visitors of a private page can also get in with the password |
| `has_password` | boolean | yes | Whether the page has a password. The password itself is never returned |
| `language` | StatusPageLanguage | yes | Languages of the public status page chrome and the subscriber emails. Customer-written content (names, incident titles and updates) is never translated. \| \| \|---\| \| `en`
English. \| \| `nl`
Dutch. \| \| `de`
German. \| \| `fr`
French. \| \| `es`
Spanish. \| \| `it`
Italian. \| |
| `match_browser_language` | boolean | yes | Visitors get their browser's language when it is supported, and can switch languages in the footer |
| `theme` | StatusPageTheme | yes | How a status page looks. `null` values use the default. |
| `collapsed_groups` | array of string | yes | Component groups that start collapsed |
| `automation_enabled` | boolean | yes | Monitor automation: when a monitor linked to a component goes down, an incident "{component} is down" (major outage) opens with `automation_down_message`, and resolves with `automation_recovered_message` when the monitor recovers |
| `automation_down_message` | string | yes | Posted when a linked monitor goes down; `{component}` and `{status_page}` are filled in. `null` for a default message |
| `automation_recovered_message` | string | yes | Posted when the monitor recovers; `null` for a default message |
| `issue_reports_enabled` | boolean | yes | Visitors can report problems from the page |
| `issue_reports_show_on_page` | boolean | yes | While reports are above the threshold, the page says that users are reporting issues |
| `issue_reports_alerts_enabled` | boolean | yes | Reaching the threshold fires an alert |
| `issue_reports_threshold` | integer | yes | Reports within `issue_reports_window_minutes` that count as above the threshold, 1 to 1000 |
| `issue_reports_window_minutes` | integer | yes | The window for the threshold, in minutes, 1 to 1440 |
| `issue_reports_triggered_at` | string | yes | Since when reports are above the threshold; `null` when they aren't |
| `traffic_alerts_enabled` | boolean | yes | Alert when views reach `traffic_alert_multiplier` times the usual views for the time of day |
| `traffic_alert_multiplier` | integer | yes | How many times the usual views alert, 2 to 100 |
| `traffic_alert_min_views` | integer | yes | Fewer views than this in 15 minutes never alert, 10 to 1000000 |
| `escalation_paths` | array of EscalationPathReference | yes | Escalation paths the page's alerts (issue reports and traffic spikes) follow; empty for the team's default path |
| `paused_reason` | ResourcePauseReason | yes | |
| `created_at` | string, date-time | yes | When the page was created |
### StatusPageAffectedComponent
A component an incident or maintenance affects, and how badly.
| Field | Type | Required | Description |
|---|---|---|---|
| `component` | StatusPageComponentReference | yes | A component of the status page. |
| `impact` | ImpactLevel | yes | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
### StatusPageAffectedComponentInput
A component an incident or maintenance affects, and how badly.
| Field | Type | Required | Description |
|---|---|---|---|
| `component_id` | string, uuid | yes | A component of the status page |
| `impact` | ImpactLevel | yes | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
### StatusPageAffectedComponentInputRequest
A component an incident or maintenance affects, and how badly.
| Field | Type | Required | Description |
|---|---|---|---|
| `component_id` | string, uuid | yes | A component of the status page |
| `impact` | ImpactLevel | yes | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
### StatusPageComponent
A component of a status page: a part of your service visitors see the status of, optionally following a monitor.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Component ID |
| `name` | string | yes | Name shown on the page |
| `description` | string | yes | Text shown with the name; `null` for none |
| `group` | string | yes | Group the component is shown in; `null` for the page's default group |
| `position` | integer | yes | Order within the group, lowest first |
| `status` | ComponentStatus | yes | A status page component's status, derived from incidents and maintenance. \| \| \|---\| \| `operational`
Working normally. \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| \| `under_maintenance`
In planned maintenance. \| |
| `monitor` | MonitorReference | yes | |
| `show_latency_chart` | boolean | yes | Whether the page shows the monitor's response time chart under the component |
| `created_at` | string, date-time | yes | When the component was created |
### StatusPageComponentReference
A component of the status page.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Component ID |
| `name` | string | yes | Component name |
### StatusPageCustomDomainCheck
The result of looking up a custom domain's DNS records.
| Field | Type | Required | Description |
|---|---|---|---|
| `domain` | string | yes | The domain |
| `verified` | boolean | yes | Whether ownership is proven, now or earlier. A proven domain stays verified when a later check fails |
| `verified_at` | string | yes | When ownership was proven; `null` before |
| `records` | array of StatusPageDnsRecordCheck | yes | The records that can verify the domain; one passing record is enough |
| `routed` | boolean | yes | Whether visitors reach the page: the domain points at it by CNAME or resolves to the same addresses. The page and its certificate need this; the certificate is issued on the first visit |
| `addresses` | array of string | yes | Addresses the domain resolves to (A and AAAA records) |
| `checked_at` | string, date-time | yes | When DNS was checked |
### StatusPageCustomDomainVerification
How to prove you own a status page's custom domain: create the TXT record, or point the domain at the CNAME target (which also routes visitors to the page). Then call `verifyStatusPageCustomDomain`.
| Field | Type | Required | Description |
|---|---|---|---|
| `verified` | boolean | yes | Whether ownership is proven. A proven domain stays verified when a later check fails |
| `verified_at` | string | yes | When ownership was proven; `null` before |
| `txt_record_name` | string | yes | Name of the TXT record to create |
| `txt_record_value` | string | yes | Value of the TXT record |
| `cname_target` | string | yes | Host to point a CNAME at (subdomains), or an ALIAS (root domains); unique to the page |
### StatusPageDisplay
What a status page shows.
| Field | Type | Required | Description |
|---|---|---|---|
| `show_uptime_history` | boolean | yes | Show each component's uptime history |
| `show_latency_charts` | boolean | yes | Show response time charts under components that have them on |
| `show_incidents` | boolean | yes | Show incidents |
| `show_maintenances` | boolean | yes | Show scheduled maintenance |
| `show_subscriptions` | boolean | yes | Let visitors subscribe to updates by email (when the plan includes subscribers) |
| `history_layout` | StatusPageHistoryLayout | yes | How a status page shows the uptime history of its components. \| \| \|---\| \| `calendar`
A calendar of days (default). \| \| `timeline`
One row of bars per component. \| |
| `uptime_bars` | StatusPageUptimeBars | yes | How a day with problems is drawn in a status page's uptime history. \| \| \|---\| \| `fill`
Colour part of the bar, by how long the problem lasted (default). \| \| `solid`
Colour the whole bar. \| |
### StatusPageDisplayInput
What a status page shows; settings left out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `show_uptime_history` | boolean | no | Show each component's uptime history |
| `show_latency_charts` | boolean | no | Show response time charts under components that have them on |
| `show_incidents` | boolean | no | Show incidents |
| `show_maintenances` | boolean | no | Show scheduled maintenance |
| `show_subscriptions` | boolean | no | Let visitors subscribe to updates by email (when the plan includes subscribers) |
| `history_layout` | StatusPageHistoryLayout | no | How a status page shows the uptime history of its components. \| \| \|---\| \| `calendar`
A calendar of days (default). \| \| `timeline`
One row of bars per component. \| |
| `uptime_bars` | StatusPageUptimeBars | no | How a day with problems is drawn in a status page's uptime history. \| \| \|---\| \| `fill`
Colour part of the bar, by how long the problem lasted (default). \| \| `solid`
Colour the whole bar. \| |
### StatusPageDnsRecordCheck
One DNS record that can verify a custom domain, with what DNS returned for it.
| Field | Type | Required | Description |
|---|---|---|---|
| `type` | DnsRecordType | yes | The DNS record type a DNS monitor queries. |
| `name` | string | yes | Record name |
| `expected` | string | yes | The value it needs |
| `found` | array of string | yes | The values DNS returned; empty when there is no such record |
| `ok` | boolean | yes | Whether this record passes |
### StatusPageImpactPeriod
A period during which an incident affected a component. Periods drive the component's status and its uptime history.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Period ID |
| `component` | StatusPageComponentReference | yes | A component of the status page. |
| `impact` | ComponentImpact | yes | How badly an incident affects a component. A component's status is the worst impact it has at the moment. \| \| \|---\| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `started_at` | string, date-time | yes | When it started |
| `ended_at` | string | yes | When it ended; `null` while it goes on |
| `duration_seconds` | integer | yes | How long it lasted so far, in seconds |
### StatusPageIncident
A public incident on a status page: what visitors read, separate from the team's own incident (which can publish to it). Its impact on components is a timeline of periods.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Status page incident ID |
| `title` | string | yes | Title shown on the page |
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `impact` | ImpactLevel | yes | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `incident_id` | string | yes | The team's incident that publishes to it; `null` for none |
| `automated` | boolean | yes | Opened by monitor automation and still managed by it, until someone posts an update or edits its timeline |
| `updates` | array of StatusPageIncidentUpdate | yes | Updates, newest first |
| `affected_components` | array of StatusPageAffectedComponent | yes | Components it affects or affected |
| `impacts` | array of StatusPageImpactPeriod | yes | The impact timeline, oldest first |
| `resolved_at` | string | yes | When it was resolved; `null` while open |
| `created_at` | string, date-time | yes | When it was created |
| `writeup` | StatusPageIncidentWriteup | yes | |
### StatusPageIncidentUpdate
An update of a status page incident, as visitors read it.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Update ID |
| `status` | IncidentStatus | yes | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | yes | The message, in Markdown |
| `published_at` | string, date-time | yes | When it happened; updates are ordered by it |
| `created_at` | string, date-time | yes | When it was written |
### StatusPageIncidentWriteup
A public write-up of a status page incident: what happened and what changes, for visitors. Published, it shows on the public incident page; otherwise it's a draft only the team sees.
| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string | yes | The write-up, in Markdown |
| `published` | boolean | yes | Whether visitors see it on the public incident page |
| `published_at` | string | yes | When it was first published; `null` while it's a draft. Editing a published write-up keeps this time |
### StatusPageIssueReport
A problem a visitor reported from the public page.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Report ID |
| `message` | string | yes | What the visitor wrote; `null` for nothing |
| `email` | string | yes | The address the visitor left for a reply. Only returned to tokens with `status-pages:write`; `null` for others (see `has_email`) and when they left none |
| `has_email` | boolean | yes | Whether the visitor left an email address, also when it isn't returned |
| `components` | array of StatusPageComponentReference | yes | Components the visitor picked; deleted components are left out |
| `created_at` | string, date-time | yes | When it was reported |
### StatusPageSubscriber
Someone who subscribed to a status page's updates by email. Only confirmed subscribers (double opt-in) get emails.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Subscriber ID |
| `email` | string, email | yes | Email address |
| `confirmed_at` | string | yes | When they confirmed the subscription; `null` while it awaits confirmation |
| `language` | StatusPageLanguage | yes | Languages of the public status page chrome and the subscriber emails. Customer-written content (names, incident titles and updates) is never translated. \| \| \|---\| \| `en`
English. \| \| `nl`
Dutch. \| \| `de`
German. \| \| `fr`
French. \| \| `es`
Spanish. \| \| `it`
Italian. \| |
| `created_at` | string, date-time | yes | When they subscribed |
### StatusPageTheme
How a status page looks. `null` values use the default.
| Field | Type | Required | Description |
|---|---|---|---|
| `accent` | string | yes | Brand colour, as hex; `null` for Spectate's yellow (`#ffea00`) |
| `mode` | StatusPageThemeMode | yes | |
| `preset` | StatusPageThemePreset | yes | |
| `font` | StatusPageFont | yes | |
| `light` | StatusPageThemeColors | yes | Colours that override the preset in one colour scheme, as hex (`#0f766e`). `null` keeps the preset's colour. |
| `dark` | StatusPageThemeColors | yes | Colours that override the preset in one colour scheme, as hex (`#0f766e`). `null` keeps the preset's colour. |
| `display` | StatusPageDisplay | yes | What a status page shows. |
| `logo_url` | string | yes | The logo, uploaded in the dashboard; `null` for none (the page shows its name) |
| `logo_dark_url` | string | yes | The logo for dark mode; `null` shows `logo_url` in dark mode too |
| `favicon_url` | string | yes | The favicon, uploaded in the dashboard; `null` for Spectate's |
### StatusPageThemeColors
Colours that override the preset in one colour scheme, as hex (`#0f766e`). `null` keeps the preset's colour.
| Field | Type | Required | Description |
|---|---|---|---|
| `background` | string | yes | Page background |
| `surface` | string | yes | Background of cards and panels |
| `foreground` | string | yes | Text |
| `muted` | string | yes | Secondary text |
| `border` | string | yes | Lines and borders |
| `success` | string | yes | Operational |
| `warning` | string | yes | Degraded performance and maintenance |
| `partial` | string | yes | Partial outage |
| `danger` | string | yes | Major outage |
| `info` | string | yes | Information, such as scheduled maintenance |
### StatusPageThemeColorsInput
Colours that override the preset in one colour scheme, as hex (`#0f766e` or `#0f7`). Colours left out keep their value; `null` goes back to the preset's colour.
| Field | Type | Required | Description |
|---|---|---|---|
| `background` | string | no | Page background |
| `surface` | string | no | Background of cards and panels |
| `foreground` | string | no | Text |
| `muted` | string | no | Secondary text |
| `border` | string | no | Lines and borders |
| `success` | string | no | Operational |
| `warning` | string | no | Degraded performance and maintenance |
| `partial` | string | no | Partial outage |
| `danger` | string | no | Major outage |
| `info` | string | no | Information, such as scheduled maintenance |
### StatusPageThemeInput
Changes to how a status page looks. Settings left out keep their value, also inside `light`, `dark` and `display`; `null` goes back to the default. Logos and the favicon are uploaded in the dashboard.
| Field | Type | Required | Description |
|---|---|---|---|
| `accent` | string | no | Brand colour, as hex; `null` for Spectate's yellow |
| `mode` | StatusPageThemeMode | no | |
| `preset` | StatusPageThemePreset | no | |
| `font` | StatusPageFont | no | |
| `light` | StatusPageThemeColorsInput | no | |
| `dark` | StatusPageThemeColorsInput | no | |
| `display` | StatusPageDisplayInput | no | What a status page shows; settings left out keep their value. |
### Subscription
The team's paid subscription.
| Field | Type | Required | Description |
|---|---|---|---|
| `plan` | Plan | yes | Billing plans (docs/billing.md). The plan sets the features; the number of monitors + hosts is the subscription's quantity, priced per monitor (`config/billing.php`). `None` is a team without a paid plan: on the trial (which uses the trial plan's limits) or unpaid (paused). \| \| \|---\| \| `none`
No paid plan and no trial: monitoring is paused until the team subscribes. \| \| `starter`
Starter: up to 3 members and 1 status page, the team default escalation path only. \| \| `team`
Team: unlimited members, 5 status pages, on-call, more escalation paths and private status pages. \| \| `business`
Business: everything in Team, with unlimited status pages and more subscribers and notification credits. \| |
| `interval` | BillingInterval | yes | Billing interval of a subscription; the values are Vatly's `interval` values. \| \| \|---\| \| `month`
Billed every month. \| \| `year`
Billed every year, for the price of 10 months. \| |
| `quantity` | integer | yes | Monitors and hosts paid for: the team's limit of both together |
| `status` | SubscriptionStatus | yes | Where a subscription stands at the payment provider. \| \| \|---\| \| `created`
Created; the first payment hasn't gone through yet. \| \| `trial`
In a trial period. \| \| `active`
Paid and running. \| \| `on_grace_period`
Cancelled, running until the end of the paid period. \| \| `paused`
Paused. \| \| `canceled`
Ended. \| |
| `cancelled` | boolean | yes | Whether it's cancelled and runs until `current_period_ends_at`; it can be resumed in the dashboard until then |
| `renews_at` | string | yes | When it renews; `null` when it won't |
| `current_period_ends_at` | string | yes | End of the period paid for |
| `payment_method` | string | yes | How it's paid; `null` when unknown |
### Team
The team the API token belongs to.
| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string, uuid | yes | Team ID |
| `name` | string | yes | Name |
| `email` | string | yes | The team's billing email: Spectate gives it to Vatly, which sends the invoices and receipts, at the team's first checkout (a plan or credits). `null` to use the address of the member who starts that checkout |
| `timezone` | string | yes | The team's time zone; escalation path working hours without a time zone of their own use it |
| `plan` | Plan | yes | Billing plans (docs/billing.md). The plan sets the features; the number of monitors + hosts is the subscription's quantity, priced per monitor (`config/billing.php`). `None` is a team without a paid plan: on the trial (which uses the trial plan's limits) or unpaid (paused). \| \| \|---\| \| `none`
No paid plan and no trial: monitoring is paused until the team subscribes. \| \| `starter`
Starter: up to 3 members and 1 status page, the team default escalation path only. \| \| `team`
Team: unlimited members, 5 status pages, on-call, more escalation paths and private status pages. \| \| `business`
Business: everything in Team, with unlimited status pages and more subscribers and notification credits. \| |
| `on_trial` | boolean | yes | Whether the team is on its trial, without a paid plan yet |
| `trial_ends_at` | string | yes | When the trial ends; `null` without one |
| `monitoring_paused_at` | string | yes | Since when all monitoring is paused; `null` while it runs |
| `monitoring_paused_reason` | TeamPauseReason | yes | |
| `deletion_scheduled_at` | string | yes | When the team and all its data will be deleted; `null` when it isn't scheduled. An owner can cancel it in the dashboard |
| `deletion_reason` | TeamDeletionReason | yes | |
| `created_at` | string, date-time | yes | When the team was created |
### TestChannel
Options of a channel test.
| Field | Type | Required | Description |
|---|---|---|---|
| `enable` | boolean | no | Enable the channel again when the test succeeds, also after Spectate turned it off. Default `false` |
### UpdateAlertSource
Changes to an alert source; fields you leave out keep their value. Its type can't change.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name shown on its alerts |
| `enabled` | boolean | no | Whether requests fire alerts |
| `default_severity` | Severity | no | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `auto_resolve_minutes` | integer | no | Minutes, 5 to 10080, after which an alert the tool stopped repeating resolves; `null` keeps it until resolved |
| `secret` | string | no | Signing secret; an empty string or `null` removes it. Write-only |
| `settings` | AlertSourceSettingsInput | no | Settings to set; settings you leave out keep their value. |
| `project_id` | string | no | Project whose escalation paths apply; `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the source's alerts; replaces the current ones |
### UpdateChannel
Changes to a channel; fields you leave out keep their value. A channel's type can't change. Its settings object, when you send it, replaces the current settings, secrets included.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name shown in escalation paths |
| `enabled` | boolean | no | Turn delivery on or off. Turning it on clears an automatic disable and its failure count |
| `email` | ChannelEmail | no | Where an `email` channel sends. |
| `slack` | ChannelSlackInput | no | Where a `slack` channel posts. Connect the Slack workspace under Integrations in the dashboard first; the installation's ID is in the Slack integration. |
| `discord` | ChannelWebhookUrlInput | no | The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned. |
| `microsoft_teams` | ChannelWebhookUrlInput | no | The incoming webhook a `discord` or `microsoft_teams` channel posts to. It's a secret: it's never returned. |
| `webhook` | ChannelWebhookInput | no | Where a `webhook` channel posts its JSON. The URL and header values are write-only. |
| `pushover` | ChannelPushoverInput | no | Who a `pushover` channel notifies, and with which Pushover application. |
| `sms` | ChannelPhone | no | The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits. |
| `voice` | ChannelPhone | no | The phone an `sms` or `voice` channel reaches. Each message or call uses the team's notification credits. |
### UpdateDomain
Changes to a monitored domain; fields you leave out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Another domain to monitor instead; its registry data is looked up again |
| `enabled` | boolean | no | Pause (`false`) or resume (`true`) monitoring. Resuming goes through the plan's domain limit |
| `expiry_threshold_days` | integer | no | Days before expiry, 1 to 365, that the "expires soon" alert fires |
| `alert_on_registry_changes` | boolean | no | Raise an alert when the registrar, nameservers or DNSSEC keys change |
| `project_id` | string | no | Project of the domain; `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the domain's alerts; replaces the current ones |
### UpdateEscalationPath
Changes to an escalation path; fields you leave out keep their value. `steps` replaces all steps. Alerts already escalating keep the steps they started with.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name, up to 255 characters |
| `description` | string | no | What the path is for, up to 1000 characters |
| `enabled` | boolean | no | Whether alerts follow the path |
| `is_default` | boolean | no | Make it the team's default path (the current default stops being one), or not |
| `working_hours` | WorkingHoursInput | no | |
| `steps` | array of EscalationStepInput | no | All steps, in order, up to 99 in total; replaces the current steps |
### UpdateHost
Changes to a host; fields you leave out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `label` | string | no | Name shown in the dashboard and alerts |
| `no_data_alert_minutes` | integer | no | Minutes without data, 2 to 1440, before the "no data received" alert fires; `null` turns it off. A firing alert ends at once when the host is within the new window |
| `project_id` | string | no | Project of the host; `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the host's alerts; replaces the current ones. `[]` follows the project's paths, else the team's default path |
### UpdateIncident
Changes to an incident; fields you leave out keep their value. To post what's known, use `createIncidentUpdate`; to close it, `resolveIncident`.
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | no | What's going on |
| `summary` | string | no | More about it, in Markdown |
| `severity` | Severity | no | How urgent an alert or incident is. Escalation paths can branch on it. \| \| \|---\| \| `critical`
Customers are affected right now. \| \| `high`
Serious, needs attention soon. \| \| `medium`
Should be looked at. \| \| `low`
Informational. \| |
| `status` | IncidentStatus | no | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
### UpdateMember
A member's new role.
| Field | Type | Required | Description |
|---|---|---|---|
| `role` | TeamRole | yes | A member's role in the team: what they may do. \| \| \|---\| \| `owner`
Everything, including billing and deleting the team. One per team. \| \| `manager`
Everything but billing and deleting the team. \| \| `admin`
Configure monitoring, alerting, incidents and status pages; can't manage members or API tokens. \| \| `member`
Read everything; manage monitors and incidents, acknowledge alerts. \| \| `billing`
Billing and support only. \| |
### UpdateMonitor
Changes to a monitor; fields you leave out keep their value. To pause or resume it, use `pauseMonitor` and `resumeMonitor`.
| Field | Type | Required | Description |
|---|---|---|---|
| `label` | string | no | Name shown in the dashboard, alerts and status pages |
| `protocol` | MonitorProtocol | no | What a monitor checks, and so the format of its `uri`. \| \| \|---\| \| `https`
An HTTPS request to the URL in `uri`, with a certificate check. \| \| `http`
An HTTP request to the URL in `uri`. \| \| `icmp`
A ping (ICMP echo) to the host in `uri`. \| \| `tcp`
A TCP connect to `host:port`, optionally with a TLS handshake and a banner keyword. \| \| `dns`
A DNS query for a record of the name in `uri`, optionally compared with expected values. \| \| `smtp`
An SMTP greeting from `host:port` (port optional), with STARTTLS by default. \| \| `imap`
An IMAP greeting from `host:port` (port optional), over TLS by default. \| \| `pop3`
A POP3 greeting from `host:port` (port optional), over TLS by default. \| |
| `uri` | string | no | The target, in the format of the (new) protocol; see `createMonitor`. For `http` and `https` the scheme is optional and must match the protocol; it is stored without the scheme |
| `interval` | MonitorInterval | no | Seconds between checks. Plans set the shortest interval a team may use. |
| `primary_location` | MonitorLocation | no | A region checks run from. A monitor's primary region decides its uptime and alerts (a failed check is repeated from the same region about 5 seconds later before it is marked down); on the Team plan and up the other regions can also measure its response time. \| \| \|---\| \| `eu`
Europe. \| \| `us`
North America. \| \| `as`
Asia. \| \| `oc`
Oceania. \| |
| `timeout` | integer | no | Seconds before a check times out, 1 to 60 |
| `max_redirects` | integer | no | HTTP: redirects to follow, 0 to 10; `null` follows up to 10 |
| `headers` | array of MonitorHeader | no | HTTP: up to 25 headers to send; replaces the current headers |
| `advanced_settings` | MonitorAdvancedSettingsInput | no | Protocol-specific settings to set. On update, settings you leave out keep their value; send `null` to reset one to its default. |
| `allow_insecure_requests` | boolean | no | HTTPS: accept invalid certificates for the check itself |
| `expected_http_status_code` | string | no | HTTP: status codes that count as up; `null` accepts 2xx and 3xx |
| `certificate_check_enabled` | boolean | no | Check the TLS certificate for validity and expiry |
| `certificate_expiry_threshold_days` | integer | no | Days before the certificate expires that the "expires soon" alert fires, 1 to 90 |
| `performance_check_enabled` | boolean | no | Raise alerts for slow responses |
| `performance_hard_threshold` | integer | no | Milliseconds, 1 to 30000: a response slower than this raises an alert |
| `performance_deviation_percentage` | integer | no | Percent, 1 to 500: alert when recent response times are this much above the earlier ones |
| `performance_deviation_timeframe` | integer | no | Minutes of recent checks to compare: 15 to 120 in steps of 15 |
| `performance_deviation_before_timeframe` | integer | no | Minutes before those to compare with: 60 to 1440 in whole hours |
| `regional_performance_enabled` | boolean | no | Also measure response time from the regions other than `primary_location`, every minute (or at the interval, when longer). Shown with the monitor's performance; not used for uptime or alerts. Team plan and up |
| `project_id` | string | no | Project of the monitor; `null` for none |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the monitor's alerts; replaces the current ones. `[]` follows the project's paths, else the team's default path |
### UpdateOnCallRotation
Changes to a rotation layer; fields you leave out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name |
| `position` | integer | no | Move the layer to this position, 0 for the top; the others shift |
| `shift_unit` | OnCallShiftUnit | no | The unit of a rotation's shift length. \| \| \|---\| \| `hours`
Absolute hours: shifts keep their length across DST changes. \| \| `days`
Calendar days in the schedule's time zone: the handoff stays at the same wall-clock time. \| \| `weeks`
Calendar weeks in the schedule's time zone. \| |
| `shift_length` | integer | no | Shift length in `shift_unit`s |
| `start_date` | string, date | no | The first handoff's date |
| `handoff_time` | string | no | Handoff time as `HH:MM` |
| `restrictions` | OnCallRestrictionsInput | no | |
| `participant_ids` | array of string, uuid | no | Members taking turns, in order; replaces the current ones |
### UpdateOnCallSchedule
Changes to an on-call schedule; fields you leave out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name |
| `description` | string | no | What the schedule covers |
| `timezone` | string | no | IANA time zone. Rotations keep their dates and wall-clock handoff times in the new zone |
### UpdateProject
Changes to a project; fields left out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Project name |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for alerts of the project's monitors and hosts; replaces the current list. Send `[]` for none |
### UpdateScheduledMaintenance
Changes to a maintenance; fields left out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | no | Title shown on the page, up to 255 characters |
| `description` | string | no | What happens and what visitors notice, in Markdown; `null` for none |
| `status` | ScheduledMaintenanceStatus | no | Where a scheduled maintenance stands. \| \| \|---\| \| `scheduled`
Announced, not started yet. \| \| `in_progress`
Going on: its components show as under maintenance. \| \| `completed`
Over. \| |
| `automatic` | boolean | no | `true`: starts and completes on schedule. `false`: only changes when you set `status` |
| `scheduled_at` | string, date-time | no | Planned start |
| `scheduled_until` | string | no | Planned end; `null` for none |
| `completed_at` | string | no | When it completed. Setting it completes the maintenance |
| `affected_components` | array of StatusPageAffectedComponentInput | no | Components it affects; replaces the current list. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers when this starts or completes the maintenance (default `true`) |
### UpdateStatusPage
Changes to a status page; settings left out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name, shown as the page title |
| `slug` | string | no | The page's subdomain under spectate.page: lowercase letters, digits and dashes. The old address stops working |
| `visibility` | StatusPageVisibility | no | Who can open a status page. \| \| \|---\| \| `public`
Anyone. \| \| `private`
Visitors with the access link, or the password when the page has one. Part of the Team plan and up. \| |
| `custom_domain` | string | no | Your own domain for the page, such as `status.acme.com`; `null` for none. Part of paid plans (`403` `PLAN_FEATURE_UNAVAILABLE` otherwise). A new domain needs to be verified again: see `custom_domain_verification` and `verifyStatusPageCustomDomain` |
| `password_protected` | boolean | no | Let visitors of a private page also get in with a password. Part of paid plans (`403` `PLAN_FEATURE_UNAVAILABLE` otherwise); turning it on needs a `password` unless the page has one |
| `password` | string | no | The password, 8 to 255 characters. Write-only; leave out or send `null` to keep the current one |
| `language` | StatusPageLanguage | no | Languages of the public status page chrome and the subscriber emails. Customer-written content (names, incident titles and updates) is never translated. \| \| \|---\| \| `en`
English. \| \| `nl`
Dutch. \| \| `de`
German. \| \| `fr`
French. \| \| `es`
Spanish. \| \| `it`
Italian. \| |
| `match_browser_language` | boolean | no | Give visitors their browser's language when it is supported |
| `theme` | StatusPageThemeInput | no | Changes to how a status page looks. Settings left out keep their value, also inside `light`, `dark` and `display`; `null` goes back to the default. Logos and the favicon are uploaded in the dashboard. |
| `collapsed_groups` | array of string | no | Component groups that start collapsed; replaces the current list |
| `automation_enabled` | boolean | no | Monitor automation: when a monitor linked to a component goes down, open an incident "{component} is down" (major outage), and resolve it when the monitor recovers |
| `automation_down_message` | string | no | Posted when a linked monitor goes down, up to 5000 characters; `{component}` and `{status_page}` are filled in. `null` for a default message |
| `automation_recovered_message` | string | no | Posted when the monitor recovers, up to 5000 characters; `null` for a default message |
| `issue_reports_enabled` | boolean | no | Let visitors report problems from the page |
| `issue_reports_show_on_page` | boolean | no | While reports are above the threshold, say on the page that users are reporting issues |
| `issue_reports_alerts_enabled` | boolean | no | Fire an alert when reports reach the threshold |
| `issue_reports_threshold` | integer | no | Reports within `issue_reports_window_minutes` that count as above the threshold, 1 to 1000 |
| `issue_reports_window_minutes` | integer | no | The window for the threshold, in minutes, 1 to 1440 |
| `traffic_alerts_enabled` | boolean | no | Alert when views reach `traffic_alert_multiplier` times the usual views for the time of day |
| `traffic_alert_multiplier` | integer | no | How many times the usual views alert, 2 to 100 |
| `traffic_alert_min_views` | integer | no | Fewer views than this in 15 minutes never alert, 10 to 1000000 |
| `escalation_path_ids` | array of string, uuid | no | Escalation paths for the page's alerts (issue reports and traffic spikes); replaces the current ones. Empty for the team's default path |
### UpdateStatusPageComponent
Changes to a component; fields left out keep their value. Its status follows incidents and maintenance and can't be set.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name shown on the page |
| `description` | string | no | Text shown with the name; `null` for none |
| `group` | string | no | Group to show the component in; `null` for the page's default group |
| `position` | integer | no | Order within the group, lowest first, from 0. New components go last when left out |
| `monitor_id` | string | no | A monitor of the team whose uptime history and response times the component shows, and whose downtime opens an incident when monitor automation is on; `null` for none |
| `show_latency_chart` | boolean | no | Show the monitor's response time chart under the component |
### UpdateStatusPageImpactPeriod
Changes to an impact period; fields left out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `component_id` | string, uuid | no | A component of the status page |
| `impact` | ComponentImpact | no | How badly an incident affects a component. A component's status is the worst impact it has at the moment. \| \| \|---\| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `started_at` | string, date-time | no | When it started, now or in the past |
| `ended_at` | string | no | When it ended, after `started_at` and not in the future; `null` reopens the period |
### UpdateStatusPageIncident
Changes to a public incident without posting an update; fields left out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | no | Title shown on the page |
| `status` | IncidentStatus | no | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `impact` | ImpactLevel | no | An impact on a status page, including `none`: how an incident or maintenance affects a component, or an incident's overall impact. \| \| \|---\| \| `none`
No impact (for a component: not affected). \| \| `degraded_performance`
Slower or less reliable than usual. \| \| `partial_outage`
Down for some visitors or some functions. \| \| `major_outage`
Down. \| |
| `affected_components` | array of StatusPageAffectedComponentInput | no | The components it affects as of now, with their impact; components left out are no longer affected. Leave out to keep the impacts as they are; send `[]` for none. Components of the status page only |
| `notify_subscribers` | boolean | no | Email confirmed subscribers when this resolves the incident (default `true`). `false` changes the page without emails |
### UpdateStatusPageIncidentUpdate
Changes to an update of a public incident; fields left out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `status` | IncidentStatus | no | Where an incident stands. \| \| \|---\| \| `investigating`
Declared; the cause isn't known yet. \| \| `identified`
Acknowledged: the cause is known and someone works on it. \| \| `monitoring`
A fix is out; watching whether it holds. \| \| `resolved`
Over. \| |
| `body` | string | no | The message, in Markdown |
| `published_at` | string, date-time | no | When it happened, now or in the past. Impact periods that started or ended at the old time move with it |
### UpdateTeam
Changes to the team; fields left out keep their value.
| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Name, up to 255 characters |
| `email` | string | no | The team's billing email: Spectate gives it to Vatly, which sends the invoices and receipts, at the team's first checkout (a plan or credits). `null` to use the address of the member who starts that checkout |
| `timezone` | string | no | The team's time zone, as an IANA name; escalation path working hours without a time zone of their own use it |
### Usage
How much of the plan's limits the team uses.
| Field | Type | Required | Description |
|---|---|---|---|
| `monitors_and_hosts` | UsageLimit | yes | How much of a plan limit is used. |
| `domains` | UsageLimit | yes | How much of a plan limit is used. |
| `projects` | UsageLimit | yes | How much of a plan limit is used. |
| `status_pages` | UsageLimit | yes | How much of a plan limit is used. |
| `status_page_subscribers` | UsageLimit | yes | How much of a plan limit is used. |
| `escalation_paths` | UsageLimit | yes | How much of a plan limit is used. |
| `members` | UsageLimit | yes | How much of a plan limit is used. |
### UsageLimit
How much of a plan limit is used.
| Field | Type | Required | Description |
|---|---|---|---|
| `used` | integer | yes | In use now |
| `limit` | integer | yes | The limit; `null` for unlimited, `0` when the plan doesn't include it. At the limit, creating more through the API answers `403` `PLAN_LIMIT_REACHED` |
### ValidationError
The request body or query failed validation.
| Field | Type | Required | Description |
|---|---|---|---|
| `error` | object | yes | What went wrong. |
### WorkingHours
Weekly working hours, for branch conditions and "until working hours" waits.
| Field | Type | Required | Description |
|---|---|---|---|
| `timezone` | string | yes | IANA time zone the hours are in |
| `days` | array of integer | yes | ISO weekdays, 1 (Monday) to 7 (Sunday) |
| `start_time` | string | yes | When working hours begin, as `HH:MM` |
| `end_time` | string | yes | When they end, as `HH:MM`; before `start_time` runs past midnight |
| `description` | string | yes | The hours in words |
### WorkingHoursInput
Weekly working hours of a path.
| Field | Type | Required | Description |
|---|---|---|---|
| `timezone` | string | yes | IANA time zone the hours are in |
| `days` | array of integer | yes | ISO weekdays, 1 (Monday) to 7 (Sunday), at least one |
| `start_time` | string | yes | When working hours begin, as `HH:MM` |
| `end_time` | string | yes | When they end, as `HH:MM`; before `start_time` runs past midnight |