# Watch a TLS certificate's expiry (Certificate expiry monitor)

The **Certificate expiry** monitor (API type `sslExp`, shown in the app as **Certificate expiration**) connects to
an endpoint over TLS, reads the certificate and reminds you before it expires. It is different from a Website
monitor's handshake check: that one confirms the certificate works right now; this one tracks the expiry date and
warns weeks ahead.

:::tip[Usually attached]
If the host already has a Website or API monitor, switch on **Certificate Expiration** there instead - see
[Attach sub-checks to a monitor](/monitors/types/attached-sub-checks/). Use a standalone monitor for endpoints you
do not otherwise monitor, such as a mail server's TLS port.
:::

## At a glance

| | |
|---|---|
| API type token | `sslExp` |
| Runs from | HostTracker's checkpoint fleet, chosen by HostTracker - no location picker |
| Schedule | every 6 hours, fixed |
| Plan gates | the Certificate expiry type is a package feature (`sslExp`) |

## How it decides

- **Reminders**: when the certificate has exactly **30**, **7** or **1** day left, the monitor sends an
  informational reminder to its contacts subscribed to **Up** (not to voice-call contacts). At most one reminder
  per day per threshold.
- **Down**: when the endpoint does not answer or does not speak TLS, or when its certificate is expired, revoked,
  self-signed or otherwise untrusted, incompletely chained, or issued for a different host name. The handshake is
  validated strictly, whatever the TLS settings of your other monitors. A failure is re-checked from other
  checkpoints before it counts. If the revocation server cannot be reached, the check does not fail for that
  reason alone.

## Settings reference

A Certificate expiry monitor has no type-specific settings: its whole configuration is the endpoint. The name,
tags, **Full Log**, **Open Stats** and subscriptions work as described in
[Common monitor fields](/monitors/types/http/#common-monitor-fields).

| Setting (app label) | API field | Type / allowed values | Default | Plan limits | What it does for you |
|---|---|---|---|---|---|
| **Domain / IP** | `url` | `host` or `host:port` | required; port 443 | - | The TLS endpoint. Add a port for anything other than HTTPS, for example `mail.example.com:465`. |
| Interval | `interval` | ignored | 6 hours | - | The schedule is fixed; a sent value is replaced and the response carries a warning. |
| Locations | `locations` | not accepted | - | - | HostTracker picks the checkpoints; sending pools is refused. |

The reminder days are fixed at 30, 7 and 1 for a standalone monitor. For other days, use a Website or Port
monitor with the API field `certWatchDays`.

## Set it up in the app

1. On the **Sites** dashboard, click **Add Monitor** and choose **Certificate expiration** in **Monitoring Type**.
2. Enter the host (and `:port` if not 443) in **Domain / IP** and a name.
3. Check **Alert Subscriptions** - reminders go to contacts subscribed to **Up**, problems to those subscribed to
   **Down**.
4. Click **Save**.

## Do it with the API or MCP

```bash
curl -X POST https://api2.host-tracker.com/monitor \
  -H "Authorization: Bearer $HT_TOKEN" -H "Content-Type: application/json" \
  -d '{ "type": "sslExp", "url": "mail.example.com:465", "name": "Mail TLS certificate" }'
```

No `interval`, `settings` or `locations` are needed. Update the endpoint or name with
`PATCH /monitor/{id}`:

```bash
curl -X PATCH https://api2.host-tracker.com/monitor/<monitor-id> \
  -H "Authorization: Bearer $HT_TOKEN" -H "Content-Type: application/json" \
  -d '{ "url": "mail.example.com:993" }'
```

MCP: `create_monitor(type="sslExp", url="mail.example.com:465", name="Mail TLS certificate")` - no `interval`,
no `pools`.

Read the certificate details with `GET /monitor/{monitorId}/attached` (the `sslExp` block: `notAfter`,
`notBefore`, `daysLeft`, `checkedAt`) or `get_monitor(id, expand="attached")`. Webhooks receive
`certificate.expiring` on each reminder.

## What happens next

The first check runs shortly after you save, then every 6 hours. You see the expiry date and days left on the
monitor. On renewal the days-left count resets and the reminders start over at the next 30-day mark.

## Limits and gotchas

- `403 package_limit` - your package does not include Certificate expiry monitors.
- `422 validation_failed` with `reason: pool_not_supported_for_type` - omit `locations`.
- A certificate that expires between two checks can take up to 6 hours to show as Down.
- If you also run a Website monitor on the same host, attaching **Certificate Expiration** there gives the same
  reminders without a second monitor.

## Related

- [Attach sub-checks to a monitor](/monitors/types/attached-sub-checks/)
- [Domain expiry monitor](/monitors/types/domain-expiry/)
- [TLS handshake policy](/monitors/advanced/tls-policy/)
- [Certificate expiry counted as down](/troubleshooting/cert-expiry-counted-down/)
