API
The admin panel is a client of the same REST API you can call from scripts, CI/CD pipelines and infrastructure tooling. Everything under /api/v1/admin accepts an API token in place of a signed-in session.
API tokens
Create tokens in Administration → API tokens (administrators only). Click New token, enter a Name, tick the Permissions and choose when it Expires, click Create, and copy the token.
| Field | Meaning |
|---|---|
| Name | A label to recognise the token by, for example GitHub Actions (up to 80 characters). |
| Permissions | What the token may do, part by part. At least one is required. The buttons Report incidents, Deploy monitoring and Read only fill in the usual sets. |
| Expires | After 90 days unless you choose otherwise: 30 days, 1 year, or Never expires, which has to be chosen on purpose. |
The full token is shown once, when you create it. Only a hash is stored, so a lost token cannot be recovered: revoke it and create a new one. The list shows the permissions of each token, the first characters of it, when it expires and when it was last used. The permissions of a token cannot be changed afterwards; create another token with the ones you want.
To revoke a token click the bin icon and confirm with Revoke. It stops working immediately, and so does any live event stream opened with it.
Permissions
A token has a list of permissions instead of a role. Each names a part of the application and whether the token may read it (read) or change it (write). Writing a part includes reading it. A request without the permission it needs is answered 403, and the message names the permission (This token does not have the "monitors:write" permission). GET needs read, every other method write.
| Part | What it covers | Levels |
|---|---|---|
monitors | Monitors, their tests, checks and dependencies | read, write |
channels | Notification channels, the SMTP settings and the delivery history | read, write |
actions | HTTP actions, their links to monitors, their run history, and Action documents of the configuration export and import | read, write |
incidents | Incidents, their updates, affected monitors and incident templates | read, write |
maintenance | Maintenance windows | read, write |
subscribers | Subscribers and subscription settings | read, write |
reports | Uptime reports | read |
appearance | The layout, branding and languages | read, write |
audit | The audit log | read |
system | System health | read |
metrics | Prometheus metrics (below) | read |
vault:use | Secrets of a vault in a monitor, channel or SMTP configuration | – |
The configuration documents follow the part of each kind: monitors for a Monitor, channels for a NotificationChannel and actions for an Action. The export needs read for each kind in it, an import write.
vault:use. A vault secret is sent wherever the configuration that uses it points, and what the target answers (a query result, an error message) comes back to whoever asked. Without this permission a token cannot list the vaults and secrets, cannot add a vault reference to a monitor, channel or the SMTP settings, and cannot change the configuration of one that already has a reference (a monitor’s name, schedule, tags and links stay editable, and removing the reference is allowed). With it, a token can point those at any vault secret by name; it still never reads a value. Give it only to a token that has to create things that use a vault. Vault and secret names still appear in exported documents to a token that may read the monitor or channel.
The three presets:
| Preset | Permissions |
|---|---|
| Report incidents | incidents:write, monitors:read |
| Deploy monitoring | monitors:write, channels:write |
| Read only | read on every part |
What a token cannot do
A token is meant for automation, so it never reaches account or credential management, whatever permissions it has:
- users, passwords and two-factor authentication,
- single sign-on settings,
- who may view a private status page (status page access),
- vault settings and secret values (a token with
vault:usecan list vault and secret names, which is what the monitor form needs to pick one), - backups,
- creating, listing or revoking API tokens,
- the sign-in endpoints under
/api/v1/auth, - viewing a private status page.
These endpoints answer 403 to a token and need a signed-in administrator.
A token belongs to no user: it keeps working when the administrator who created it is demoted or deleted, so revoke the tokens of someone who leaves. Each token is limited to 300 requests per minute; beyond that the API answers 429 with a Retry-After header.
A backup contains the tokens as they were when it was taken. After restoring one, review Administration → API tokens and revoke any token that should no longer exist.
Every change a token makes is recorded in the audit log (Administration → Audit Log) as token: <token name>. Creating and revoking a token is recorded under the administrator who did it. Reading is not recorded.
Handling tokens
- Keep a token in the secret store of your pipeline, never in the repository or in a log.
- Give it only the Permissions the job needs, and an expiry. A pipeline that only opens incidents needs
incidents:write, not write access to everything. - Send it over HTTPS only. A token sent to an
http://address crosses the network in clear. - A token is not tied to an address or to a pipeline: whoever has the text can use it.
- If a token may have leaked, revoke it at once in Administration → API tokens, then filter the Audit Log for
(token: <name>)to see what it did. - A token with
vault:use, like an operator in the panel, can point a monitor, a test or the SMTP settings at any vault secret and at any address, and whoever can apply a configuration document can do it by name. A token never reads a vault value, but a vault secret can be sent where the token’s holder chooses. Withoutvault:usea token cannot do this. Treat a token that has it like the people it stands for.
Calling the API
Send the token in the Authorization header. No CSRF token or cookie is needed.
export BSP_URL=https://status.example.com
export BSP_TOKEN=bsp_...
curl -fsS -H "Authorization: Bearer $BSP_TOKEN" "$BSP_URL/api/v1/admin/monitors"
-fsS makes curl fail on an error status instead of printing the error as if it were the answer.
Errors
Errors come back as JSON, { "error": "..." }:
| Status | Meaning |
|---|---|
400 | The request is not valid; error says what. For configuration documents the answer also lists every problems entry with its place. |
401 | The token is missing, unknown, expired or revoked. |
403 | The token does not have the permission the endpoint needs (the message names it), or the endpoint does not accept API tokens (API tokens cannot call this endpoint). |
404 | There is no such object. |
409 | The key is already used by another object, or an export cannot name a vault because another vault has the same name. |
413 | The body is too large; a configuration file may be up to 2 MB. Behind nginx, see client_max_body_size in Deployment. |
415 | The Content-Type is not supported: send application/json, or application/yaml for configuration documents (the only type an import reads). |
422 | A notification channel could not deliver its test message. |
429 | The token sent more than 300 requests in a minute; wait for Retry-After seconds. |
500 | The server failed. Nothing is half-applied: a configuration file is applied completely or not at all. |
Reference
The operations meant for automation are described in an OpenAPI 3.1 file: openapi.yaml. It covers monitors, incidents, maintenance windows, notification channels, actions, the status page layout and the configuration export and import, with the request bodies, limits and the permission each operation needs. Load it into any OpenAPI tool to browse the API or to generate a client.
Secrets are masked
A password, client secret, credential header, Slack, Discord or Teams webhook URL, Telegram bot token, ntfy access token or Pushover application token in a monitor’s or channel’s config is never returned: it reads back as ••••••••. Send that value back unchanged to keep the stored secret, or send a new one to replace it. A masked value that does not match the stored secret, or one that looks like a half-edited mask, is refused with 400, so a placeholder can never be saved as a password. Secrets must be text.
A kept secret has to stay where it is sent. If a request keeps a stored secret and also changes the monitor’s url, the OAuth2 tokenUrl, the CAS server, a database host or port, or a webhook channel’s url or an ntfy channel’s serverUrl, it is refused until you enter the secret again. This also applies to a monitor test that names a saved monitor. Changing the type of a monitor or channel needs a new config in the same request.
Secrets read from a vault are references and are returned as they are. Credentials written into a URL (https://user:password@host), a query string or a request body are not recognised as secrets and are returned as stored; use the authentication fields, headers or a vault instead.
Validation
A monitor needs a name (up to 200 characters) and a known type. config, when sent, must be an object, and tags a list of up to 20 { "label", "color" } objects. intervalSecs is 10 to 86400, timeoutMs 1000 to 300000 and retries 1 to 10; values outside these ranges are refused with 400, while failureThreshold and recoveryThreshold are clamped to 1 to 20. The optional autoIncidentMinutes (1 to 10080, or null for off), autoIncidentMode (draft or published) and autoIncidentTemplateId (or null for the default template) switch on automatic incidents; a token needs incidents:write as well to set published or a template.
A maintenance window needs a name (up to 200 characters), a startsAt and an endsAt (milliseconds since the epoch, the end after the start), and every id in monitorIds must be an existing monitor. The status page layout (PUT /layout) needs a tree object.
Monitors, notification channels and actions have keys
Every monitor, notification channel and action has a unique Key next to its numeric id: 1 to 64 lowercase letters, digits, - and _, starting with a letter or digit. It is a technical value, not a setting: the admin panel does not show it in its forms. It is generated from the name when you do not send one (Public site becomes public-site, a second one public-site-2), or you give it when you create the object through the API. It never changes after that, not even when the name does, and an update that sends a key is refused with 400. The id is specific to one installation, the key is what you refer to from your own tooling.
curl -fsS -X POST -H "Authorization: Bearer $BSP_TOKEN" -H "Content-Type: application/json" \
"$BSP_URL/api/v1/admin/monitors" \
-d '{"name": "Public site", "key": "public-site", "type": "https", "config": {"url": "https://example.com"}}'
A key that is already taken answers 409, and one that is not valid 400.
Open an incident from CI/CD
An incident has a status of investigating, identified, monitoring or resolved, and an impact of minor, major or critical. Subscribers are notified unless you send "notifySubscribers": false.
# Open an incident
curl -fsS -X POST -H "Authorization: Bearer $BSP_TOKEN" -H "Content-Type: application/json" \
"$BSP_URL/api/v1/admin/incidents" \
-d '{"title": "Deploy in progress", "status": "investigating", "impact": "minor", "monitorIds": [1]}'
# Post an update, here resolving it (use the id from the previous response)
curl -fsS -X POST -H "Authorization: Bearer $BSP_TOKEN" -H "Content-Type: application/json" \
"$BSP_URL/api/v1/admin/incidents/5/updates" \
-d '{"body": "Deploy finished.", "status": "resolved"}'
Prometheus metrics
GET /api/v1/admin/metrics returns the state of the instance in the Prometheus text format. It needs the metrics:read permission, so create a token with only that (Administration → API tokens) and give it to the scraper as a bearer token:
scrape_configs:
- job_name: bsp
metrics_path: /api/v1/admin/metrics
authorization:
credentials: bsp_xxxxxxxx
static_configs:
- targets: ['status.example.com']
| Metric | Meaning |
|---|---|
bsp_monitor_up | 1 when the monitor is up, 0 for any other status. A monitor that has not been checked yet has no sample. |
bsp_monitor_response_time_seconds | Response time of the latest check, when it has one. |
bsp_monitor_last_check_timestamp_seconds | Unix time of the latest check. |
bsp_monitor_certificate_expiry_timestamp_seconds | Unix time the TLS certificate of an HTTPS monitor expires. |
bsp_incidents_open | Published incidents that are not resolved. |
The monitor metrics carry the labels monitor (name), key and type. The endpoint is part of the admin API: the token limit of 300 requests per minute applies, and an unauthenticated request is answered 401.