---
title: "Set or clear a maintenance window"
method: POST
path: "/api/v1/checks/{id}/snooze"
tags: ["Checks"]
---

# Set or clear a maintenance window

`POST /api/v1/checks/{id}/snooze`

## Request

- Base URL: `https://app.lastping.dev`
- URL: `https://app.lastping.dev/api/v1/checks/{id}/snooze`
- Auth: API key in header `X-Api-Key`

Sets `maintenance_until` on the check. While a maintenance window is
active (`now < maintenance_until`) it holds:

- every deadline incident: a missed or never-started run, an
  overrun, a stall, and a blocked run outliving `blocked_timeout_s`;
- on an HTTP monitor, failing probes: they are recorded but open no
  incident, and if the site is still failing when the window ends,
  the next failure opens one. On an HTTP monitor any `fail` is
  treated as a probe's, including one sent to its ping URL by hand.

Everything the job reports itself still notifies during the window:
its own `fail` ping (a job that says it failed is news either way),
the page a `blocked` ping queues, a runaway ping rate, and any routed
`note`, `started`, `success` or `every-run` event.

Exactly one of `duration`, `until`, or `clear` must be provided:

- `duration` — a Go duration string (e.g. `"1h"`, `"24h"`, `"72h"`).
- `until` — an RFC 3339 timestamp for a custom end time.
- `clear` — set to `true` to remove the maintenance window immediately.

## Request body

- object
  - `duration` string: Go duration string (e.g. "1h", "24h").
  - `until` string, date-time: RFC 3339 end timestamp.
  - `clear` boolean: Set to true to remove the active maintenance window.

## Response `200`

Check with maintenance_until updated.

- Check: A check resource returned by the API.
  - `id` string, uuid, required: Unique check identifier.
  - `name` string, required: Human-readable name.
  - `slug` string, required: Stable project-scoped identifier (may be empty string if not set).
  - `schedule_kind` 'simple' | 'cron' | 'on_demand', required: `on_demand` means the check has no cadence: it never arms an absence deadline, so silence between runs never alerts. Run-scoped detection (`max_runtime_s`, `step_timeout_s`) still applies once a run starts, and `expect_every_s` — the silence floor — is the only way to detect absence between runs.
  - `period_s` integer, required: Period in seconds (only meaningful for schedule_kind=simple).
  - `cron_expr` string: Cron expression (only present when schedule_kind=cron).
  - `tz` string, required: IANA timezone.
  - `grace_s` integer, required: Grace period in seconds — the silence tolerance and the first-run deadline, and the overrun budget when `max_runtime_s` is unset.
  - `max_runtime_s` integer, nullable: Run-duration budget in seconds for the overrun deadline only. **Omitted from the response when unset**, in which case the overrun rule falls back to `grace_s`. Never set on `http` monitors.
  - `step_timeout_s` integer, nullable: Progress budget in seconds for the stall rule. **Omitted from the response when unset**, in which case stall detection is disabled. Never set on `http` monitors.
  - `expect_every_s` integer, nullable: Silence floor in seconds. **Omitted from the response when unset**, in which case absence is detected only by the schedule — and, for an `on_demand` monitor, not at all between runs.
  - `notify_min_run_s` integer, nullable: Notification duration floor in seconds. **Omitted from the response when unset**, in which case every info-class notification (`success`, `started`, `every-run`, `note`) fires regardless of how short the run was. Never set on `http` monitors. Never suppresses `down`, `fail`, `recovery` or `blocked`.
  - `blocked_timeout_s` integer, nullable: How long (in seconds) the check may sit `blocked` before a `blocked` incident opens. **Omitted from the response when unset** — that does NOT mean the check waits forever, it means the 24-hour default applies.
  - `failure_threshold` integer, required: Consecutive explicit failures required before an incident opens (`fail` cause only). Always present; `1` means "open on the first failure", the default.
  - `monitor_from` string, date-time, nullable: RFC 3339 timestamp from which deadlines are computed.
  - `status` 'new' | 'up' | 'late' | 'down', required: Current check status derived from ping history.
  - `last_ping_at` string, date-time, nullable: RFC 3339 timestamp of the most recent ping received.
  - `due_at` string, date-time, nullable: RFC 3339 timestamp when the next ping is expected.
  - `alert_after` string, date-time, nullable: RFC 3339 timestamp after which an alert is sent if no ping arrives.
  - `paused` boolean, required: When true the check does not alert regardless of ping status.
  - `maintenance_until` string, date-time, nullable: RFC 3339 timestamp until which the check is snoozed. Alerts are suppressed while this is in the future; null or absent when the check is not snoozed.
  - `created_at` string, date-time, required: RFC 3339 UTC timestamp when the check was created.
  - `ping_url` string, uri, required: The URL your service should HTTP-GET to record a successful ping.
  - `monitor_type` 'heartbeat' | 'ci' | 'http': Monitor mode. Omitted on responses when the value is the default `heartbeat`.
  - `probe_url` string, uri: URL being probed (HTTP monitors only; omitted otherwise).
  - `probe_method` 'GET' | 'HEAD' | 'POST': HTTP method used for the probe (HTTP monitors only; omitted otherwise).
  - `probe_expected_body` string: Expected response body substring (HTTP monitors only; omitted otherwise).
  - `probe_interval_s` integer: Probe interval in seconds (HTTP monitors only; omitted otherwise).
  - `probe_expected_status` integer: Expected HTTP status code (HTTP monitors only; omitted otherwise).
  - `probe_timeout_s` integer: Probe timeout in seconds (HTTP monitors only; omitted otherwise).
  - `probe_follow_redirects` boolean: Whether the probe follows redirects (HTTP monitors only; omitted otherwise).
  - `next_probe_at` string, date-time, nullable: RFC 3339 UTC timestamp when the next probe is scheduled (HTTP monitors only; omitted otherwise).
  - `ci_provider` 'github' | 'gitlab' | 'jenkins': CI provider bound to this check (omitted when no CI binding is set).
  - `ci_configured` boolean: True when a CI binding is set on this check (omitted when false).
  - `ci_webhook_url` string, uri: Webhook URL for this CI check (omitted when no CI binding is set). POST this URL from your CI provider with the `ci_secret` as the HMAC secret.
  - `ci_secret` string: **WRITE-ONCE** — returned ONLY in the `201` create response and the `POST /api/v1/checks/{id}/ci/regenerate` response. NEVER returned on GET or list. Copy it immediately; it cannot be retrieved again (use regenerate to rotate).
  - `ci_workflow` string: Optional workflow/job name filter narrowing which CI runs this check watches (omitted when unset, which watches every workflow).
  - `ci_branch` string: Optional branch filter narrowing which CI runs this check watches (omitted when unset, which watches every branch).
  - `ci_ignored` object: Finished CI runs (succeeded or failed) that `ci_workflow` or `ci_branch` filtered out since the last finished run that matched them, or since the filters last changed. Omitted when none were. A count that keeps growing with no recent match usually means a filter no longer matches anything, for example after a workflow rename or a default-branch change. A matching finished run and a change to either filter both reset it. A repository webhook sends the runs of every workflow, so with `ci_workflow` set, `count` includes other workflows' runs, which the filter is meant to drop; `same_workflow_count` counts only the runs of `ci_workflow` (or of any workflow when it is not set) that `ci_branch` dropped. `new_workflow` names the workflow that first appeared among the ignored runs since the last match and has run most often since, which is how a workflow renamed after it matched shows up (GitHub and Jenkins monitors; always empty on GitLab, which names an unnamed pipeline after its branch). `last_workflow`, `last_branch`, `same_workflow_last_branch` and `new_workflow` are copied from the CI provider's payload: treat them as untrusted text.
    - `count` integer, required: Number of finished runs the filters ignored.
    - `last_at` string, date-time, required: RFC 3339 UTC time the most recent ignored run arrived.
    - `last_workflow` string, required: Workflow name of the most recent ignored run, as the CI provider sent it.
    - `last_branch` string, required: Branch of the most recent ignored run, as the CI provider sent it.
    - `last_matched_at` string, date-time, nullable, required: RFC 3339 UTC time of the most recent finished run that matched the filters, or null when none has been recorded.
    - `filters_changed_at` string, date-time, nullable, required: RFC 3339 UTC time `ci_workflow` or `ci_branch` last changed, or null when that is not known.
    - `same_workflow_count` integer, required: Number of the ignored finished runs that belong to `ci_workflow` (every ignored run when no workflow filter is set): the runs the branch filter alone dropped. 0 when every ignored run was another workflow's.
    - `same_workflow_last_at` string, date-time, nullable, required: RFC 3339 UTC time the most recent of those runs arrived, or null when `same_workflow_count` is 0.
    - `same_workflow_last_branch` string, required: Branch of the most recent of those runs, as the CI provider sent it; an empty string when `same_workflow_count` is 0.
    - `new_workflow` string, required: Name of the workflow, other than `ci_workflow`, that first appeared after the last matching run and has the most ignored runs since (ties to the one that appeared first), as the CI provider sent it; an empty string when none did. A name first seen in the monitor's first 7 days of recording workflow names is never new. Always empty on GitLab monitors.
    - `new_workflow_first_at` string, date-time, nullable, required: RFC 3339 UTC time `new_workflow` first appeared, or null when `new_workflow_count` is 0.
    - `new_workflow_count` integer, required: Number of the ignored finished runs that carried `new_workflow`; 0 when no new workflow appeared.
  - `runaway_ceiling` integer, nullable: Maximum pings allowed in a rolling 1-hour window. Exceeding it opens a `runaway`-cause incident, which detects a looping agent or job pinging abnormally fast. Omitted from the response when disabled for this monitor.
  - `tags` string[], required: Labels attached to this monitor. Always returned as an array (never null); empty array when no tags are set.
  - `agent_id` string, uuid, nullable: Id of the agent that owns this monitor. Omitted/null when the monitor is unattached — including right after its owning agent was deleted: `DELETE /api/v1/agents/{id}` unowns the monitors it owned, it does not delete them.
  - `source_kind` string: The scanner that discovered this monitor (`crontab`, `github-actions`, `k8s-cronjob`, `systemd-timer`). **Omitted when a human created the monitor**, which is the state of every monitor that predates discovery — and such a monitor is never reconciled, so a scan can neither adopt nor delete it.
  - `source_ref` string: The stable path within `source_kind` that identifies exactly what was found. Together with `source_kind` and the project it is the discovery reconcile key. `source_kind` and `source_ref` are always either both present or both omitted: a half-set identity is never stored.
  - `trace_content` 'redacted' | 'dropped', required: What this monitor's traces keep of prompt, command and tool content. `dropped` (the default) removes the content attributes (prompts, completions, commands, tool arguments, results and definitions, retrieved documents, working directories) of every recognised vocabulary entirely; lengths such as `user_prompt_length`, token counts and cost are kept. Error text (`error`, `error.message`, `exception.message`, `exception.stacktrace` and the span's status message) is kept at `dropped`, redacted and then cut to 512 characters, and a cut marks the span or log event truncated. `redacted` opts in to storing that content, with every secret-shaped value replaced by `[REDACTED:<class>]` at ingest, before anything is queued or stored: API keys (LastPing, Anthropic, OpenAI, GitHub, GitLab, npm, AWS access key ids, Slack, Stripe, Google, Hugging Face, Perplexity, Fireworks, Supabase, New Relic, Airtable, Terraform Cloud, Firebase), HashiCorp Vault tokens, age secret keys, Discord bot tokens, Slack, Discord and Teams webhook URLs, `Authorization` header values, JWTs, private key blocks, `password=`/`token=`/`api_key=` style assignments (subscripted ones such as `os.environ["API_KEY"] = ...` and Dockerfile `ENV`/`ARG` lines included), SQL `PASSWORD '...'` and `IDENTIFIED BY` clauses, the Redis `AUTH` command, `.netrc` passwords, command-line password flags and the argument after them (any secret-named `--flag`, `-p` after a login subcommand, `redis-cli -a`), cookies, credentials in URLs, the value of any attribute or JSON field whose name is secret-named (password, token, api_key, secret, the same word in several other languages, an `Authorization` or `X-Api-Key` header and the like; `Idempotency-Key` and request, correlation and trace ids are not secrets), including JSON carried inside another JSON string such as tool-call arguments, and long high-entropy tokens. A bytes attribute that is valid UTF-8 is scanned and stored as its text. A span that had a value redacted carries `lastping.redacted_values`. A request whose redaction work exceeds a fixed budget stores `[REDACTED:over_budget]` for the values it could not scan, never the values themselves. In both modes every remaining value is redacted the same way. There is no setting that stores content unredacted. A change reaches ingest within 60 seconds: ingest caches each monitor's setting for up to a minute, so an export sent just after the change may still be handled the old way. Always present.
  - `kind` 'cron' | 'ci' | 'agent' | 'http', required: The console's four-way grouping of this monitor, derived server-side so every surface groups it the same way. `agent` wins over the rest: an agent's heartbeat is the agent's. A CI monitor is one with a `ci_provider`, **not** one with `monitor_type: "ci"` — nothing in the product writes that value.
  - `uptime_90d` number, double, nullable, required: Uptime over the last 90 days, or since the monitor was created if that is more recent, as a percentage with two decimals. For an HTTP monitor this is the share of probes that succeeded; for every other type it is derived from incident downtime over the window. Null when an HTTP monitor has no probe history yet, and null for any other monitor that has never been pinged. A monitor created three days ago reports on those three days, not on 90 days of assumed success, so the window varies per monitor and the console says so beside the figure.
  - `latency_ms` integer, nullable, required: The most recent probe's latency. HTTP monitors only; null for every other type and for an HTTP monitor with no probe yet.
  - `routes_count` integer, required: How many distinct alert destinations would hear about this monitor FAILING: the destinations routed on `down`, `fail`, `blocked` or `every-run`. Distinct destinations, not route rows, so one destination routed on both `down` and `fail` is one place the alerts go. `every-run` counts because it fires for every completed run, a failed one included. A route on `recovery`, `success`, `started` or `note` is not counted: routes are resolved per event with no fallback, and none of those four ever fires for a failure, so a monitor routed only on them has nowhere for its bad news to go. 0 means failures would be silent, which the console flags as "Not routed" and Home counts in `overview.alerts.monitors_unrouted`.
  - `recent_outcomes` string[], required: This monitor's last 20 run outcomes, newest first, for the console's run strip. Always an array, empty when the monitor has not completed a run yet. Only terminal outcomes appear: a `start` says a run began and is not one.
  - `hook_version` integer, nullable, required: Version of the Claude Code hook script last seen on a start ping; null when no hook that reports a version has sent a start. Older than hook_version_current means re-run set-up.
  - `hook_version_current` integer, required: The hook script version set-up installs today. Compare it with hook_version.
  - `hook_seen_at` string, date-time, nullable, required: When hook_version was last recorded, from a start ping. Refreshed at most once an hour while the version is unchanged. Null when no hook that reports a version has sent a start.
  - `claude_code_seen_at` string, date-time, nullable, required: Latest time this monitor received a Claude Code run (a hook start that reported a version, or a trace whose source is Claude Code). With hook_version null and a recent value here, the machine runs an older hook or none.

## Other responses

- `400`: Invalid or missing body fields.
- `401`: Missing or invalid API key.
- `404`: Check not found in this project.

---

[API](https://skmtc.dev/lastping/apis/lastping-management-api.md) · [All operations](https://skmtc.dev/lastping/apis/lastping-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lastping/apis/lastping-management-api/revisions/bbc6eda91c46?raw)
