---
title: API reference
description: Every UpHeron API endpoint with parameters, responses and examples. Generated from the OpenAPI description at /openapi.json.
---

# API reference

Base URL: `https://upheron.com/api/v1`. Send your token as `X-API-Key` (see [Authentication](/docs/authentication)). Requests and responses are JSON; lists come back as `{"data": [...]}`. The machine-readable version of this page is [`/openapi.json`](/openapi.json).

Operations marked **Paid** can answer `402 Payment Required` with an MPP challenge; see [Payments](/docs/payments). Everything else is free within the [rate limits](/docs/rate-limits).

## Account

### GET /account

Plan slots, credit and prices

Responses: 200, 401, 429.

```bash
curl -X GET https://upheron.com/api/v1/account \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### PUT /account/billing

Set invoice details (name, address, country, VAT number)

| Body field | Type | Notes |
|---|---|---|
| `billing_name` | string,null |  |
| `billing_address` | string,null |  |
| `billing_country` | string,null | ISO 3166-1 alpha-2, decides the VAT treatment. |
| `billing_vat_id` | string,null | EU VAT number with country prefix; enables the reverse charge for EU businesses outside Bulgaria. |

Responses: 200, 401, 403, 422, 429.

```bash
curl -X PUT https://upheron.com/api/v1/account/billing \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"billing_country": "DE", "billing_vat_id": "DE123456789"}'
```

### GET /account/credit

Credit movements, newest first

Responses: 200, 401, 429.

```bash
curl -X GET https://upheron.com/api/v1/account/credit \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### GET /alert-channels

Notification contacts

Responses: 200, 401, 429.

```bash
curl -X GET https://upheron.com/api/v1/alert-channels \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /alert-channels

Add a notification contact (email contacts must confirm a link first)

| Body field | Type | Notes |
|---|---|---|
| `name` (required) | string |  |
| `kind` (required) | string |  |
| `destination` (required) | string | Email address or URL. |

Responses: 201, 401, 403, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/alert-channels \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Ops", "kind": "email", "destination": "ops@example.com"}'
```

### DELETE /alert-channels/{id}

Remove a notification contact

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 204, 401, 403, 404, 429.

```bash
curl -X DELETE https://upheron.com/api/v1/alert-channels/$ID \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /alert-channels/{id}/test

Send a test alert

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 403, 404, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/alert-channels/$ID/test \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

## Monitors

### GET /locations

Monitoring locations you can choose

Responses: 200, 401, 429.

```bash
curl -X GET https://upheron.com/api/v1/locations \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### GET /monitors

Every monitor and its current status

Responses: 200, 401, 429.

```bash
curl -X GET https://upheron.com/api/v1/monitors \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /monitors

Create a monitor (paid when no plan slot is free, or without an account) · **Paid** · token optional

Free while the plan has a free monitor slot. Otherwise costs the per-location price for 30 days (`billing_period: monthly`) or ten times that for life (`lifetime`), taken from credit; if credit is short the response is 402 with an MPP challenge for the difference. Ask POST /monitors/quote first to see the price.

Without an API token the request is always paid (agent-plan limits: 60-second minimum interval, no group monitors). After payment the 201 response also contains `api_key` and `workspace`: a new pay-as-you-go workspace that owns the monitor. The key is shown once.

| Parameter | In | Notes |
|---|---|---|
| `Idempotency-Key` | header | Repeating a request with the same key within 24 hours returns the monitor the first request created, without charging again. |

| Body field | Type | Notes |
|---|---|---|
| `name` (required) | string | Shown in alerts and on status pages. |
| `kind` | `http`, `api`, `ssl`, `domain`, `dns`, `blacklist`, `email_auth`, `malware`, `tcp`, `ssh`, `smtp`, `imap`, `pop`, `ftps`, `ping`, `ntp`, `udp`, `minecraft`, `transaction`, `micro_transaction`, `extended_transaction`, `group`, `cloud_status`, `page_speed`, `webhook`, `heartbeat`, `repository` | What to check. `heartbeat` and `webhook` wait for your calls instead of probing. `repository` reads a GitHub or GitLab repository's dependency manifests daily and alerts on vulnerabilities in them, on every plan; put the repository URL in `url` (optionally …/tree/branch/folder) and, for a private repository (Pro plan or a paid monitor), an access token in `check_options.token`. Default `"http"`. |
| `url` | string | URL, or host[:port] for network checks. |
| `method` | `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` | Default `"GET"`. |
| `interval_seconds` | integer | Seconds between checks. Paid monitors may use 10 or more on any plan; monitors in plan slots follow the plan (300 on Free, 10 on Pro). Default `300`. |
| `timeout_ms` | integer | Default `10000`. |
| `locations` | array | Location codes from GET /locations. Defaults to the first location. |
| `expected_status_min` | integer | Default `200`. |
| `expected_status_max` | integer | Default `399`. |
| `keyword` | string | Text the response body must contain. |
| `request_headers` | object | Sent with the check; stored encrypted and never returned. |
| `request_body` | string |  |
| `check_options` | object | Kind-specific options, such as `json_path`/`expected_value` for `api`, `steps` for transactions, `warn_days` for ssl. Ports go in `url` as host:port. See /docs/api#check-options. |
| `failure_threshold` | integer | Failed checks in a row before an incident opens. The default alerts on the first failed check. Default `1`. |
| `recovery_threshold` | integer | Default `2`. |
| `confirmation_threshold` | integer | Locations that must agree a check failed. Default `1`. |
| `heartbeat_grace_seconds` | integer | For heartbeat and webhook monitors. |
| `expiry_alerts` | boolean | `http` and `api` monitors: check the domain registration and (for HTTPS) the TLS certificate daily. Domain alerts come 30, 14, 7, 3 and 1 days before expiry; certificate alerts only once automatic renewal should have happened (a sixth of the certificate's lifetime, at most 14 days). Uses no extra monitor. Default `true`. |
| `vulnerability_alerts` | boolean | Paid plans, `http` and `api` monitors: scan the website weekly for the software it runs and alert on newly published vulnerabilities in it (OSV.dev with the GitHub Advisory Database, NVD, new CVE records, CISA KEV, endoflife.date). Default `false`. |
| `vulnerability_severity` | `low`, `medium`, `high`, `critical` | The lowest severity that alerts. Actively exploited vulnerabilities and releases reaching end of support always alert. Default `"low"`. |
| `charts` | `both`, `uptime`, `response` | Charts on public status pages: uptime bars (the last 90 days, or the whole history), the last 24 hours of response time, or both. Default `"both"`. |
| `alert_channel_ids` | array | Notification contacts to alert. Defaults to all of the workspace's contacts. |
| `billing_period` | `monthly`, `lifetime` | Only for paid monitors (no free plan slot). `monthly` costs the per-location price every 30 days, renewed from credit; `lifetime` costs ten times that once and never renews. Default `"monthly"`. |

Responses: 200, 201, 401, 402, 403, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Example", "url": "https://example.com"}'
```

### POST /monitors/quote

Price a monitor without creating it

| Parameter | In | Notes |
|---|---|---|
| `Idempotency-Key` | header | Repeating a request with the same key within 24 hours returns the monitor the first request created, without charging again. |

| Body field | Type | Notes |
|---|---|---|
| `name` (required) | string | Shown in alerts and on status pages. |
| `kind` | `http`, `api`, `ssl`, `domain`, `dns`, `blacklist`, `email_auth`, `malware`, `tcp`, `ssh`, `smtp`, `imap`, `pop`, `ftps`, `ping`, `ntp`, `udp`, `minecraft`, `transaction`, `micro_transaction`, `extended_transaction`, `group`, `cloud_status`, `page_speed`, `webhook`, `heartbeat`, `repository` | What to check. `heartbeat` and `webhook` wait for your calls instead of probing. `repository` reads a GitHub or GitLab repository's dependency manifests daily and alerts on vulnerabilities in them, on every plan; put the repository URL in `url` (optionally …/tree/branch/folder) and, for a private repository (Pro plan or a paid monitor), an access token in `check_options.token`. Default `"http"`. |
| `url` | string | URL, or host[:port] for network checks. |
| `method` | `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` | Default `"GET"`. |
| `interval_seconds` | integer | Seconds between checks. Paid monitors may use 10 or more on any plan; monitors in plan slots follow the plan (300 on Free, 10 on Pro). Default `300`. |
| `timeout_ms` | integer | Default `10000`. |
| `locations` | array | Location codes from GET /locations. Defaults to the first location. |
| `expected_status_min` | integer | Default `200`. |
| `expected_status_max` | integer | Default `399`. |
| `keyword` | string | Text the response body must contain. |
| `request_headers` | object | Sent with the check; stored encrypted and never returned. |
| `request_body` | string |  |
| `check_options` | object | Kind-specific options, such as `json_path`/`expected_value` for `api`, `steps` for transactions, `warn_days` for ssl. Ports go in `url` as host:port. See /docs/api#check-options. |
| `failure_threshold` | integer | Failed checks in a row before an incident opens. The default alerts on the first failed check. Default `1`. |
| `recovery_threshold` | integer | Default `2`. |
| `confirmation_threshold` | integer | Locations that must agree a check failed. Default `1`. |
| `heartbeat_grace_seconds` | integer | For heartbeat and webhook monitors. |
| `expiry_alerts` | boolean | `http` and `api` monitors: check the domain registration and (for HTTPS) the TLS certificate daily. Domain alerts come 30, 14, 7, 3 and 1 days before expiry; certificate alerts only once automatic renewal should have happened (a sixth of the certificate's lifetime, at most 14 days). Uses no extra monitor. Default `true`. |
| `vulnerability_alerts` | boolean | Paid plans, `http` and `api` monitors: scan the website weekly for the software it runs and alert on newly published vulnerabilities in it (OSV.dev with the GitHub Advisory Database, NVD, new CVE records, CISA KEV, endoflife.date). Default `false`. |
| `vulnerability_severity` | `low`, `medium`, `high`, `critical` | The lowest severity that alerts. Actively exploited vulnerabilities and releases reaching end of support always alert. Default `"low"`. |
| `charts` | `both`, `uptime`, `response` | Charts on public status pages: uptime bars (the last 90 days, or the whole history), the last 24 hours of response time, or both. Default `"both"`. |
| `alert_channel_ids` | array | Notification contacts to alert. Defaults to all of the workspace's contacts. |
| `billing_period` | `monthly`, `lifetime` | Only for paid monitors (no free plan slot). `monthly` costs the per-location price every 30 days, renewed from credit; `lifetime` costs ten times that once and never renews. Default `"monthly"`. |

Responses: 200, 401, 403, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/quote \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Example", "url": "https://example.com"}'
```

### GET /monitors/{id}

A monitor with uptime, recent results, 90 daily bars, its whole history and incidents

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 404, 429.

```bash
curl -X GET https://upheron.com/api/v1/monitors/$ID \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### PATCH /monitors/{id}

Change a monitor (adding locations to a paid monitor is paid) · **Paid**

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

| Body field | Type | Notes |
|---|---|---|
| `name` (required) | string | Shown in alerts and on status pages. |
| `kind` | `http`, `api`, `ssl`, `domain`, `dns`, `blacklist`, `email_auth`, `malware`, `tcp`, `ssh`, `smtp`, `imap`, `pop`, `ftps`, `ping`, `ntp`, `udp`, `minecraft`, `transaction`, `micro_transaction`, `extended_transaction`, `group`, `cloud_status`, `page_speed`, `webhook`, `heartbeat`, `repository` | What to check. `heartbeat` and `webhook` wait for your calls instead of probing. `repository` reads a GitHub or GitLab repository's dependency manifests daily and alerts on vulnerabilities in them, on every plan; put the repository URL in `url` (optionally …/tree/branch/folder) and, for a private repository (Pro plan or a paid monitor), an access token in `check_options.token`. Default `"http"`. |
| `url` | string | URL, or host[:port] for network checks. |
| `method` | `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` | Default `"GET"`. |
| `interval_seconds` | integer | Seconds between checks. Paid monitors may use 10 or more on any plan; monitors in plan slots follow the plan (300 on Free, 10 on Pro). Default `300`. |
| `timeout_ms` | integer | Default `10000`. |
| `locations` | array | Location codes from GET /locations. Defaults to the first location. |
| `expected_status_min` | integer | Default `200`. |
| `expected_status_max` | integer | Default `399`. |
| `keyword` | string | Text the response body must contain. |
| `request_headers` | object | Sent with the check; stored encrypted and never returned. |
| `request_body` | string |  |
| `check_options` | object | Kind-specific options, such as `json_path`/`expected_value` for `api`, `steps` for transactions, `warn_days` for ssl. Ports go in `url` as host:port. See /docs/api#check-options. |
| `failure_threshold` | integer | Failed checks in a row before an incident opens. The default alerts on the first failed check. Default `1`. |
| `recovery_threshold` | integer | Default `2`. |
| `confirmation_threshold` | integer | Locations that must agree a check failed. Default `1`. |
| `heartbeat_grace_seconds` | integer | For heartbeat and webhook monitors. |
| `expiry_alerts` | boolean | `http` and `api` monitors: check the domain registration and (for HTTPS) the TLS certificate daily. Domain alerts come 30, 14, 7, 3 and 1 days before expiry; certificate alerts only once automatic renewal should have happened (a sixth of the certificate's lifetime, at most 14 days). Uses no extra monitor. Default `true`. |
| `vulnerability_alerts` | boolean | Paid plans, `http` and `api` monitors: scan the website weekly for the software it runs and alert on newly published vulnerabilities in it (OSV.dev with the GitHub Advisory Database, NVD, new CVE records, CISA KEV, endoflife.date). Default `false`. |
| `vulnerability_severity` | `low`, `medium`, `high`, `critical` | The lowest severity that alerts. Actively exploited vulnerabilities and releases reaching end of support always alert. Default `"low"`. |
| `charts` | `both`, `uptime`, `response` | Charts on public status pages: uptime bars (the last 90 days, or the whole history), the last 24 hours of response time, or both. Default `"both"`. |
| `alert_channel_ids` | array | Notification contacts to alert. Defaults to all of the workspace's contacts. |
| `billing_period` | `monthly`, `lifetime` | Only for paid monitors (no free plan slot). `monthly` costs the per-location price every 30 days, renewed from credit; `lifetime` costs ten times that once and never renews. Default `"monthly"`. |

Responses: 200, 401, 402, 403, 404, 422, 429.

```bash
curl -X PATCH https://upheron.com/api/v1/monitors/$ID \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Example", "url": "https://example.com"}'
```

### DELETE /monitors/{id}

Delete a monitor (frees its plan slot; paid monitors are not refunded)

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 204, 401, 403, 404, 429.

```bash
curl -X DELETE https://upheron.com/api/v1/monitors/$ID \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /monitors/{id}/quote

Price a monitor change without applying it

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

| Body field | Type | Notes |
|---|---|---|
| `name` (required) | string | Shown in alerts and on status pages. |
| `kind` | `http`, `api`, `ssl`, `domain`, `dns`, `blacklist`, `email_auth`, `malware`, `tcp`, `ssh`, `smtp`, `imap`, `pop`, `ftps`, `ping`, `ntp`, `udp`, `minecraft`, `transaction`, `micro_transaction`, `extended_transaction`, `group`, `cloud_status`, `page_speed`, `webhook`, `heartbeat`, `repository` | What to check. `heartbeat` and `webhook` wait for your calls instead of probing. `repository` reads a GitHub or GitLab repository's dependency manifests daily and alerts on vulnerabilities in them, on every plan; put the repository URL in `url` (optionally …/tree/branch/folder) and, for a private repository (Pro plan or a paid monitor), an access token in `check_options.token`. Default `"http"`. |
| `url` | string | URL, or host[:port] for network checks. |
| `method` | `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` | Default `"GET"`. |
| `interval_seconds` | integer | Seconds between checks. Paid monitors may use 10 or more on any plan; monitors in plan slots follow the plan (300 on Free, 10 on Pro). Default `300`. |
| `timeout_ms` | integer | Default `10000`. |
| `locations` | array | Location codes from GET /locations. Defaults to the first location. |
| `expected_status_min` | integer | Default `200`. |
| `expected_status_max` | integer | Default `399`. |
| `keyword` | string | Text the response body must contain. |
| `request_headers` | object | Sent with the check; stored encrypted and never returned. |
| `request_body` | string |  |
| `check_options` | object | Kind-specific options, such as `json_path`/`expected_value` for `api`, `steps` for transactions, `warn_days` for ssl. Ports go in `url` as host:port. See /docs/api#check-options. |
| `failure_threshold` | integer | Failed checks in a row before an incident opens. The default alerts on the first failed check. Default `1`. |
| `recovery_threshold` | integer | Default `2`. |
| `confirmation_threshold` | integer | Locations that must agree a check failed. Default `1`. |
| `heartbeat_grace_seconds` | integer | For heartbeat and webhook monitors. |
| `expiry_alerts` | boolean | `http` and `api` monitors: check the domain registration and (for HTTPS) the TLS certificate daily. Domain alerts come 30, 14, 7, 3 and 1 days before expiry; certificate alerts only once automatic renewal should have happened (a sixth of the certificate's lifetime, at most 14 days). Uses no extra monitor. Default `true`. |
| `vulnerability_alerts` | boolean | Paid plans, `http` and `api` monitors: scan the website weekly for the software it runs and alert on newly published vulnerabilities in it (OSV.dev with the GitHub Advisory Database, NVD, new CVE records, CISA KEV, endoflife.date). Default `false`. |
| `vulnerability_severity` | `low`, `medium`, `high`, `critical` | The lowest severity that alerts. Actively exploited vulnerabilities and releases reaching end of support always alert. Default `"low"`. |
| `charts` | `both`, `uptime`, `response` | Charts on public status pages: uptime bars (the last 90 days, or the whole history), the last 24 hours of response time, or both. Default `"both"`. |
| `alert_channel_ids` | array | Notification contacts to alert. Defaults to all of the workspace's contacts. |
| `billing_period` | `monthly`, `lifetime` | Only for paid monitors (no free plan slot). `monthly` costs the per-location price every 30 days, renewed from credit; `lifetime` costs ten times that once and never renews. Default `"monthly"`. |

Responses: 200, 401, 403, 404, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/quote \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Example", "url": "https://example.com"}'
```

### POST /monitors/{id}/renew

Renew a monthly paid monitor for 30 more days · **Paid**

Renewals happen automatically every hour from credit. Call this to renew early (the 30 days are added to the remaining time) or to resume a monitor that was paused for non-payment. Pays from credit, or answers 402 with an MPP challenge.

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 402, 403, 404, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/renew \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Example", "url": "https://example.com"}'
```

### POST /monitors/{id}/renew/quote

Price a renewal

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 403, 404, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/renew/quote \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /monitors/{id}/pause

Stop checking

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 403, 404, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/pause \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /monitors/{id}/resume

Start checking again

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 403, 404, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/resume \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

## Vulnerabilities

### GET /monitors/{id}/vulnerabilities

Findings in the website's software (exploited and most severe first) and the software they were matched on

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 404, 429.

```bash
curl -X GET https://upheron.com/api/v1/monitors/$ID/vulnerabilities \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /monitors/{id}/vulnerabilities/scan

Scan the website for its software and check it now instead of waiting for the weekly scan

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 202, 401, 402, 403, 404, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/vulnerabilities/scan \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /monitors/{id}/vulnerabilities/{finding_id}/fixed

Record that a finding's software was upgraded: to version, or by default to the first version that fixes it; the monitor is checked again

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |
| `finding_id` (required) | path | string |

| Body field | Type | Notes |
|---|---|---|
| `version` | string | The version installed; defaults to the finding's fix_version. |

Responses: 200, 401, 402, 403, 404, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/vulnerabilities/{finding_id}/fixed \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Example", "url": "https://example.com"}'
```

### POST /monitors/{id}/software

Add software the website runs, by name (Debian, nginx), package (npm:lodash, wp-plugin:slug) or NVD product (cpe:vendor:product)

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

| Body field | Type | Notes |
|---|---|---|
| `name` (required) | string |  |
| `version` | string,null |  |

Responses: 201, 401, 402, 403, 404, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/software \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Debian", "version": "12"}'
```

### POST /monitors/{id}/software/import

Import a manifest, lockfile, Dockerfile, Compose file or a plain list (one "name version" per line); importing a filename again replaces what it added

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

| Body field | Type | Notes |
|---|---|---|
| `content` (required) | string | The file's text, or the list. |
| `filename` | string | Tells the format; leave out for a plain list. |
| `name` | string | Labels the import; importing under the same label again replaces it. Defaults to the filename, or "software list" for a list. |

Responses: 200, 401, 402, 403, 404, 422, 429.

```bash
curl -X POST https://upheron.com/api/v1/monitors/$ID/software/import \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content": "Debian 12\nnginx 1.24.0\nPHP 8.2.12\nwp-plugin:woocommerce 9.3.3"}'
```

### DELETE /monitors/{id}/software/import

Remove everything a file imported

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |
| `file` (required) | query | string |

Responses: 200, 401, 402, 403, 404, 422, 429.

```bash
curl -X DELETE https://upheron.com/api/v1/monitors/$ID/software/import \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### PATCH /monitors/{id}/software/{software_id}

Set an entry's version (it then counts as added by hand), or ignore or restore it

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |
| `software_id` (required) | path | string |

| Body field | Type | Notes |
|---|---|---|
| `version` | string,null |  |
| `ignored` | boolean |  |

Responses: 200, 401, 402, 403, 404, 422, 429.

```bash
curl -X PATCH https://upheron.com/api/v1/monitors/$ID/software/$SOFTWARE_ID \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"version": "1.24.0"}'
```

### DELETE /monitors/{id}/software/{software_id}

Remove an entry; software the scan found is ignored instead, so it is not added back

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |
| `software_id` (required) | path | string |

Responses: 200, 401, 402, 403, 404, 422, 429.

```bash
curl -X DELETE https://upheron.com/api/v1/monitors/$ID/software/$SOFTWARE_ID \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### GET /software-catalog

Software known by name; any package (npm:, composer:, pypi:, gem:, go:, maven:, nuget:, cargo:), wp-plugin:/wp-theme: slug or cpe:vendor:product works too

Responses: 200, 401, 429.

```bash
curl -X GET https://upheron.com/api/v1/software-catalog \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

## Results

### GET /monitors/{id}/results

Recent check results, newest first

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |
| `limit` | query | integer |

Responses: 200, 401, 404, 429.

```bash
curl -X GET https://upheron.com/api/v1/monitors/$ID/results \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### GET /monitors/{id}/uptime

Daily uptime for any range, kept for as long as the monitor

One entry per UTC day, oldest first. Without `from` and `to`, every day from the first check (`since`) to today. At most 3660 days per request.

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |
| `from` | query | string |
| `to` | query | string |

Responses: 200, 401, 404, 422, 429.

```bash
curl -X GET https://upheron.com/api/v1/monitors/$ID/uptime \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### GET /incidents

Incidents, newest first

Responses: 200, 401, 429.

```bash
curl -X GET https://upheron.com/api/v1/incidents \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### GET /incidents/{id}

One incident with its events

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 404, 429.

```bash
curl -X GET https://upheron.com/api/v1/incidents/$ID \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### POST /incidents/{id}/acknowledge

Acknowledge an incident

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 403, 404, 429.

```bash
curl -X POST https://upheron.com/api/v1/incidents/$ID/acknowledge \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

## Payments

### POST /credits

Buy prepaid credit with MPP · **Paid**

Always answered with 402 and an MPP challenge for `amount_cents` until paid. Cards (Stripe shared payment tokens) need at least $0.50.

| Body field | Type | Notes |
|---|---|---|
| `amount_cents` (required) | integer |  |

Responses: 200, 401, 402, 403, 422, 429, 503.

```bash
curl -X POST https://upheron.com/api/v1/credits \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount_cents": 500}'
```

### GET /payments

Payments, newest first

Responses: 200, 401, 429.

```bash
curl -X GET https://upheron.com/api/v1/payments \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### GET /payments/{id}

One payment

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 404, 429.

```bash
curl -X GET https://upheron.com/api/v1/payments/$ID \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```

### GET /payments/{id}/receipt

Receipt with seller and VAT details (JSON, or Markdown with Accept: text/markdown)

| Parameter | In | Notes |
|---|---|---|
| `id` (required) | path | string |

Responses: 200, 401, 404, 429.

```bash
curl -X GET https://upheron.com/api/v1/payments/$ID/receipt \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY"
```


## Check options

`check_options` carries the settings specific to a monitor `kind`. The most common:

| Kind | Options |
|---|---|
| `http`, `api` | `json_path` (dot-separated) and `expected_value` (JSON), `max_latency_ms` (100–60000), `headers_only` (`http` only: stop after the response headers; ignored with `keyword` or `json_path`) |
| `transaction`, `micro_transaction`, `extended_transaction` | `steps`: up to 5, 3 or 10 HTTP requests, each with `url`, `method`, `headers`, `body`, `keyword`, `expected_status_min`, `expected_status_max`, `json_path`, `expected_value`, `max_latency_ms` |
| `ssl`, `domain` | `warn_days` (1–365): fail this many days before expiry |
| `dns` | `record_type` (`A`, `AAAA`, `CNAME`, `MX`, `TXT`, `NS`, `SOA`, `SRV`) and an optional `expected_answer` |
| `blacklist` | `dnsbl_zone`: the provider's query zone; `lookup`: `domain` (default, a domain list), `mail_servers` (the IPv4 addresses of the domain's MX servers) or `host` (the target's own IPv4 addresses), for IP lists |
| `email_auth` | `dkim_selectors` (up to 10, for example `["google"]`) and `dmarc_policy` (`none`, `quarantine` or `reject`: the weakest policy that passes). `url` is the sending domain |
| `smtp`, `imap`, `pop`, `ftps` | `security`: `tls` (from the start) or `starttls` |
| `udp` | `payload_base64` (1–512 bytes) and an optional `expected_text` |
| `minecraft` | `edition`: `java` (default; TCP, the SRV record or port 25565) or `bedrock` (UDP, port 19132) |
| `group` | `member_ids` (monitors in the same workspace) and `group_policy` (`all` or `any`) |
| `page_speed` | `api_key` (Google PageSpeed Insights), `strategy` (`mobile` or `desktop`), `minimum_score` (0–100) |
| `malware` | `api_key` (Google Web Risk) |

Network checks (`tcp`, `ssh`, mail, `ftps`, `ntp`, `udp`, `minecraft`, `ssl`) take `host` or `host:port` in `url`; `tcp` and `udp` need the port.

`http` and `api` monitors alert 30, 14, 7, 3 and 1 days before their domain registration expires and, for HTTPS, before their TLS certificate expires without having been renewed: certificate alerts start at a sixth of the certificate's lifetime, at most 14 days ahead, after automatic renewal (Let's Encrypt, Cloudflare) should have happened. Send `"expiry_alerts": false` to turn both off. The monitor reports `domain_name`, `domain_expires_at`, `cert_issuer` and `cert_expires_at` after the daily checks.

On paid plans, `http` and `api` monitors can also alert on vulnerabilities in the software their website runs: send `"vulnerability_alerts": true`, and optionally `"vulnerability_severity"` (`low`, the default, `medium`, `high` or `critical`) for the lowest severity that alerts. Actively exploited vulnerabilities and releases reaching end of support always alert. Free plans get `422` with `plan_required`.

The software is found by a weekly scan of the website (`POST /monitors/{id}/vulnerabilities/scan` runs one now) and can be told directly: `POST /monitors/{id}/software/import` takes a file's text and optional `filename` (package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, composer.json/.lock, requirements.txt, Pipfile.lock, poetry.lock, Gemfile.lock, go.mod, Cargo.lock, pom.xml, .csproj, Dockerfile, docker-compose.yml, .nvmrc, .tool-versions) or a plain list with one `name version` per line, such as `Debian 12`, `nginx 1.24.0` or `npm:lodash 4.17.21` ([format and supported files](/docs/software)). `POST /monitors/{id}/software` adds one entry. `GET /monitors/{id}/vulnerabilities` returns the software and the findings: exploited and most severe first, each with `severity`, `fixed_in`, `fix_version` (the first version that fixes it), `exploited_on` (CISA's exploited list) and `version_known` (false when the advisory only may apply). After upgrading, `POST /monitors/{id}/vulnerabilities/{finding_id}/fixed` records the new version (by default `fix_version`, or `{"version": "…"}`) and checks again. These endpoints answer `402` with `plan_required` on plans without vulnerability alerts.

A `heartbeat` monitor's `heartbeat_url` takes a GET or POST after each successful run. Add `/fail` to the URL to report a failed run: the incident opens at once instead of after the failure threshold.

Invalid options are reported as `422` with the offending fields.

## Notification contacts

A workspace alerts its notification contacts when a monitor goes down and recovers. Add them with `POST /api/v1/alert-channels`:

```bash
curl https://upheron.com/api/v1/alert-channels \
  -H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Ops", "kind": "email", "destination": "ops@example.com"}'
```

An email contact receives a confirmation link and is alerted only after it is opened. New monitors alert every contact unless you pass `alert_channel_ids`. Pay-as-you-go workspaces can use email and webhook contacts.

## Errors

Errors have a JSON body with a machine-readable `error` and a human-readable `message`; validation errors add `fields`.

```json
{ "error": "validation_failed", "message": "Some fields are invalid.", "fields": { "url": ["can't be blank"] } }
```

| Status | Meaning |
|---|---|
| 400, 422 | The request is invalid; read `error`, `message` and `fields` |
| 401 | Missing, invalid, revoked or expired token |
| 402 | Payment required; see [Payments](/docs/payments) |
| 403 | The token lacks the `write` scope |
| 404 | No such resource in this workspace |
| 429 | Rate limited; wait `Retry-After` seconds |
| 5xx | Temporary problem; retry with backoff (and an `Idempotency-Key` when creating) |
