Command-line tool
upheron lists your monitors and their status, checks a website on the spot, and keeps your workspace in a file: export it, change it, review the difference and apply it, by hand or from CI. It works on every plan, Free included, and uses only the public API, within your plan and the rate limits.
It is one JavaScript file with no dependencies, for Node.js 20 or later or Bun, downloaded from this site. The current version is 1.0.0, and its SHA-256 is:
830ff4d31b8c008d53eb93229f7f03790bfe29615921c54cb7a840826c5da5cb
Install
On macOS and Linux, download it, check it against the SHA-256 above and put it on your PATH:
curl -fsSLO https://upheron.com/downloads/upheron \
&& echo "830ff4d31b8c008d53eb93229f7f03790bfe29615921c54cb7a840826c5da5cb upheron" | shasum -a 256 -c \
&& chmod +x upheron && mkdir -p ~/.local/bin && mv upheron ~/.local/bin/
Linux without shasum has sha256sum -c instead. On Windows, download upheron, compare Get-FileHash upheron with the SHA-256 above, and run it as node upheron. The checksum is also at /downloads/upheron.sha256. To update, download it again; upheron version says which version you have.
Sign in
Create a token in Settings → API tokens (see Authentication): read is enough to list, check, export and diff; apply needs write. Give it to upheron in the UPHERON_API_KEY environment variable, or save it once:
upheron login
login reads the token without showing it, checks it, and saves it in ~/.config/upheron/config.json (%APPDATA%\upheron\config.json on Windows) readable only by you. upheron refuses a config file that others can read. UPHERON_API_KEY wins over the file; upheron logout deletes it.
Commands
| Command | What it does |
|---|---|
upheron monitors |
Every monitor with its status, kind, target and last check. |
upheron monitor <name or id> |
One monitor: status, uptime over 24 hours, 7 and 30 days, certificate and domain expiry, open incidents and vulnerability findings. |
upheron check <url> |
Checks a public website (or pings a public IPv4 address) now, from UpHeron's server: ten a minute. |
upheron export [-o file] |
Writes the workspace's contacts, monitors, status pages and maintenance windows as YAML, or JSON with -o file.json or --format json. |
upheron diff <file> |
Shows what apply would change. |
upheron apply <file> |
Creates and updates what the file describes. |
Every command takes --json for machine-readable output. Exit codes:
| Code | Meaning |
|---|---|
| 0 | Done: no changes (diff), the website is up (check), applied (apply). |
| 1 | diff found changes, or check found the website down or unreachable. |
| 2 | A mistake in the command or the file, such as an unknown field or a name used twice. |
| 3 | The API refused the request (its message is shown) or could not be reached. |
Monitoring as code
Start from your workspace as it is:
upheron export -o upheron.yaml
version: 1
contacts:
- name: Ops email
kind: email
destination: [email protected]
monitors:
- name: Shop
kind: http
url: https://shop.example.com
interval_seconds: 60
locations: [fra-1, nyc-1]
keyword: Add to cart
contacts: [Ops email]
- name: Nightly backup
kind: heartbeat
heartbeat_grace_seconds: 600
contacts: [Ops email]
status_pages:
- name: Example status
slug: example-status
components: [Shop, { monitor: Nightly backup, display_name: Backups }]
appearance: { theme: dark }
maintenance_windows:
- name: Database upgrade
monitor: Shop
starts_at: "2026-12-01T02:00:00Z"
ends_at: "2026-12-01T03:00:00Z"
- name: Backup window
starts_at: "2026-12-01T02:00:00+01:00"
ends_at: "2026-12-01T02:30:00+01:00"
recurrence: { frequency: daily }
Change it, then upheron diff upheron.yaml and upheron apply upheron.yaml. How the file is read:
- Names are the keys. Each item is matched with the one of the same name in the workspace, so names must be unique within a section, in the file and among what the file lists in the workspace. Renaming an item in the file creates a new one. Contacts, monitors and tabs are named in references too: a monitor's
contacts,tabandescalation_policy, a status page'scomponents, a maintenance window'smonitor(left out, the window covers every monitor). - What is left out is left alone. A section the file does not have is not managed, and neither is a field an item does not give: export leaves out fields at their default, so if you want a default kept, write it. The fields are those of the API (
paused: truepauses a monitor). - Deleting needs
--delete. Items of a managed section that the file does not list are shown as deletions but kept;upheron apply --deletedeletes them.--dry-runshows whatapplywould do. Maintenance windows that have ended are never exported, changed or deleted; a repeating one has ended once it has no occurrences left. - Write-only fields are those the API never returns: a contact's
destination,tokenandoptions, a monitor'srequest_headers,request_bodyandrepository_token, and check options such as transactionsteps. They are sent when the item is created;--write-secretssends them again. Keep secrets out of the file in the repository; the export shows a contact's destination only as adestination_hint. A contact's kind and destination, and a monitor's kind, cannot change: give the new one another name. - A maintenance window's
recurrence(repeating windows) is compared by the keys the file gives, so{ frequency: daily }matches a rule the API filled in with its interval and time zone; a change sends the file's rule, and the API fills in the rest again. Occurrences skipped or moved in the dashboard are not in the file and stay as they are. check_optionsare sent whole. Changing one option sends all the options in the file, and options it does not give are removed, so list every option of a check you change, write-only ones included.- When the file manages status pages, monitors it creates get no status page of their own. New monitors are created with an
Idempotency-Key, so a retry never makes a second one;upheronwaits out rate limits and retries what is safe to retry.
JSON files work the same way, and YAML may use the usual block and flow styles, quotes, comments and | blocks; anchors and tags are not supported.
In CI
Review changes to the file in pull requests and apply them when they are merged. In GitHub Actions, with a write token saved as the secret UPHERON_API_KEY:
name: Monitoring
on:
pull_request:
paths: [upheron.yaml]
push:
branches: [main]
paths: [upheron.yaml]
jobs:
upheron:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Install upheron
run: |
curl -fsSLO https://upheron.com/downloads/upheron
curl -fsSL https://upheron.com/downloads/upheron.sha256 | sha256sum -c
chmod +x upheron
- name: Show the changes
if: github.event_name == 'pull_request'
run: ./upheron diff upheron.yaml || [ $? -eq 1 ]
env:
UPHERON_API_KEY: ${{ secrets.UPHERON_API_KEY }}
- name: Apply
if: github.event_name == 'push'
run: ./upheron apply upheron.yaml
env:
UPHERON_API_KEY: ${{ secrets.UPHERON_API_KEY }}
To fail a scheduled job when someone changed the workspace by hand, run upheron diff upheron.yaml: it exits 1 when the workspace and the file differ. Runners have Node.js; elsewhere, install Node.js 20 or later or Bun first. To pin a version, check the download against its SHA-256 from this page instead of the .sha256 file: an update then stops the job until you take it.