---
title: "Engage the global dispatcher kill switch"
method: POST
path: "/api/v1/admin/kill-switch"
tags: ["Admin"]
---

# Engage the global dispatcher kill switch

`POST /api/v1/admin/kill-switch`

## Request

- Base URL: `https://api.uptimemonitoring.com`
- URL: `https://api.uptimemonitoring.com/api/v1/admin/kill-switch`
- Auth: HTTP bearer

Creates the sentinel file at `KILL_SWITCH_FILE` (requested
mode `0644`, masked by the dispatcher's umask) when it does
not already exist. An existing sentinel of any kind (regular
file of any mode or content, directory, FIFO, socket, or a
symlink to one) is left untouched: the handler never opens
or truncates it, so a retry cannot fail on a read-only or
non-regular sentinel. Symlinks are followed, so
`KILL_SWITCH_FILE` and every directory on its resolved chain
must be writable only by trusted operators. Once observed by
the watcher, every wopher dispatch is gated off and
`POST /api/v1/monitors/{id}/test` returns 503. Webhook
delivery, the DNS re-resolver, evidence flush, and read APIs
continue to run.

Requires admin role per #18.

**Idempotent.** Repeat calls return 200 with the same
body whether or not the sentinel file pre-existed; this
endpoint never returns 409. Operators in an emergency
want "make it engaged" semantics; a 409 on a benign retry
is hostile.

When the handler's own check of the sentinel file, made
before it touches the file, finds the file absent, and the
file operation completes without a fatal error, the
dispatcher fires the `kill_switch_flipped` webhook (when both
`SECURITY_ALERT_WEBHOOK_URL` and
`SECURITY_ALERT_WEBHOOK_SECRET` are configured) with `actor`
set to the calling admin's GitHub username. A URL configured
without a secret disables delivery entirely — the dispatcher
logs a `[security:webhook_disabled]` warning at startup and
sends nothing on this or any other security-alert event.
That check is not synchronized with other writers, so the
actor-attributed alert reflects what the check saw, not
whether this call changed the file: concurrent calls, or an
out-of-band `touch`/`rm` between the check and the write, can
make the two differ. A call whose check finds the file
already present writes nothing and fires no actor-attributed
alert, but still runs the watcher confirmation step; if that
confirmation is the first to observe an out-of-band change
made since the watcher's last poll, the watcher's own
notification path can emit an alert with no `actor`.
The handler makes a best-effort attempt to suppress the
watcher's own poll-loop alert for the same flip via a
one-shot flag; concurrent REST flips can race that flag
and produce two alerts for one transition, and a failed
sentinel-file write can leave it armed and suppress an
unrelated later alert. Webhook delivery for this event is
not exactly-once.

The response's `active` field is the state the watcher
actually confirmed after the file write, not necessarily
the requested one: if the post-write confirmation hits a
filesystem error, the write already happened but the
in-memory state could not be confirmed, and the response
is `503` reporting the last known state instead of `200`
with a possibly-wrong `active:true`. The `kill_switch_flipped`
webhook still fires in that case, with `active:true` (the
requested/written state) — the file write is the real event,
and withholding the alert would mean a completed engage could
go unreported (the suppressed watcher poll won't fire it
either, and a client retry afterward is a no-op).

Returns 503 `{"error":"kill switch not configured"}` when
`KILL_SWITCH_FILE` is unset.

## Response `200`

Kill switch is engaged.

- KillSwitchStatus
  - `active` boolean, required: Whether the global kill switch is currently engaged. Reflects the watcher's in-memory state, which is updated on a 5 s poll cadence (out-of-band flips can lag up to 5 s; REST-driven flips propagate within milliseconds).
  - `sentinel_path` string, required: Absolute path of the sentinel file the watcher is polling — the value of `KILL_SWITCH_FILE` at process start.

## Other responses

- `401`: Missing or invalid credentials.
- `403`: Authenticated but not an admin.
- `429`: Per-account dispatcher rate limit exceeded (200 requests/minute). The `Retry-After` header gives the integer seconds until at least one token has refilled. The `X-RateLimit-*` trio reflects the bucket whose rejection produced this response — usually the global 200/min cap; on `POST /api/v1/monitors` a 429 may instead reflect the per-route 20/min creation limit.
- `500`: Either a stat of the sentinel path failed for a reason other than it being missing (e.g. permission denied on a parent directory, a symlink loop), or creating a missing sentinel failed (e.g. dispatcher process lacks write permission to the sentinel directory). Operators should resolve the host-side permissions and retry.
- `503`: Either `KILL_SWITCH_FILE` is unset (`{"error":"kill switch not configured"}`), or the sentinel file write succeeded but the watcher could not confirm the new state afterward (a filesystem error naming the failure and the last known `active` value it fell back to).

---

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