---
title: "Deprecated: create or replace the legacy single webhook for a monitor"
method: PUT
path: "/api/v1/monitors/{monitorID}/webhook"
deprecated: true
---

# Deprecated: create or replace the legacy single webhook for a monitor

`PUT /api/v1/monitors/{monitorID}/webhook`

## Request

- Base URL: `https://api.uptimemonitoring.com`
- URL: `https://api.uptimemonitoring.com/api/v1/monitors/{monitorID}/webhook`
- Auth: HTTP bearer

> **Deprecated.**

Deprecated alias (issue #212), backed by recipients. If this
monitor has no attached webhook-type recipient, creates one named
after the monitor, attaches it, and returns it (with its secret)
in the legacy shape. If one is already attached, this updates
ITS url and returns the SAME id and secret — including when that
recipient is shared with other monitors via
`PUT /api/v1/monitors/{monitorID}/recipients`, in which case the
URL change applies to every monitor sharing it, not just this
one. Prefer `POST /api/v1/recipients` +
`PUT /api/v1/monitors/{monitorID}/recipients` for new
integrations. The `url` must point to a public hostname;
private/loopback/link-local/mDNS URLs are rejected with
`400 {"error":"url must be a valid http(s) URL"}` (SSRF
hardening).

## Path parameters

- `monitorID` integer, required

## Request body

- object: The `url` must be valid UTF-8 with no null bytes and no ASCII control characters (U+0000..U+001F, U+007F). Violations return HTTP 400.
  - `url` string, uri, required

## Response `200`

Webhook

- Webhook: Configured notification endpoint. The signed JSON body for an HTTP attempt contains `event`, `monitor_id`, `account_id`, `occurred_at`, `delivery_id`, `attempt`, plus `reason`/`monitor_name`/`monitor_url` when non-empty. Since issue #165, the body also carries `collapsed_transitions` (integer) when a delivery superseded one or more earlier transitions for the same monitor+webhook pair — e.g. a down→up→down→up flap against a slow-to-recover subscriber can collapse to a survivor carrying `collapsed_transitions: 3`. The field is omitted entirely (not sent as 0) when nothing was collapsed, so existing subscribers see a byte-identical body to before this field existed.
  - `id` integer
  - `monitor_id` integer
  - `url` string, uri
  - `secret` string: HMAC-SHA256 signing secret. Prefix `whs_live_`.
  - `created_at` string, date-time

## Other responses

- `400`: Bad request
- `404`: Monitor not found
- `413`: Request body exceeds the 64 KB hard limit. Per docs/SPEC.md §Hard Limits the dispatcher rejects any payload larger than 65,536 bytes before it is decoded.
- `415`: The request `Content-Type` is not `application/json`. Write operations (POST, PUT, PATCH) require that header; a missing or non-JSON media type is rejected before the body is read. The `charset` parameter is accepted and ignored, so `application/json; charset=utf-8` is valid.
- `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.

---

[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)
