---
title: "Replace the set of recipients attached to a monitor"
method: PUT
path: "/api/v1/monitors/{monitorID}/recipients"
---

# Replace the set of recipients attached to a monitor

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

## Request

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

Full replacement, not a merge. `recipient_ids` entries must be
positive and unique (400 before any write, for either violation).
An id not owned by the calling account returns 400 and writes
nothing. Removing a recipient from the set cancels that pair's
queued (`pending`/`retrying`) webhook_deliveries rows in the same
transaction, not just future transitions — but this is a bound on
enqueued state, not a guarantee about what has already left the
wire: the same documented race as delivery supersede (see
`docs/SPEC.md`'s outbox section) means an attempt the Worker already
passed its liveness check for just before this transaction commits
can still complete. Whether it is recorded in the delivery log
depends on which update commits first: if this transaction's delete
(scoped to `pending`/`retrying` rows) runs first, the row is gone
and the Worker's later terminal-status update is a no-op, so the
attempt is NOT recorded; if the Worker's terminal-status update
lands first, the row is already `delivered` (or `failed`) and this
transaction's delete — which only targets `pending`/`retrying` rows
— leaves it in place, so the attempt IS recorded. Both outcomes are
possible; this is not a guarantee either way. `{"recipient_ids":
[]}` detaches everything, after which `silent_monitors` on
`GET /api/v1/account` counts this monitor if it is still enabled.

## Path parameters

- `monitorID` integer, required

## Request body

- MonitorRecipients: `GET`/`PUT` responses always carry both `recipient_ids` and `recipients` (resolved from the same snapshot), so a client reading either field sees the attached set. `PUT` request bodies accept exactly one of `recipient_ids` (today's form) or `recipients` (issue #338, per-pair `down_delay_s`) — specifying both, or specifying neither, is 400. Either field, when present, must not be JSON `null` (400) — only an explicit `[]` detaches every recipient. Omitting `down_delay_s` on a `recipients` entry keeps an already-attached pair's stored delay, or defaults a newly-attached pair to `0`; the `recipient_ids` form always keeps every attached pair's existing delay.
  - `recipient_ids` integer[]: Must be positive and unique.
  - `recipients` object[]
    - `id` integer, required
    - `down_delay_s` 0 | 60 | 120 | 180 | 240 | 300 | 600 | 900 | 1200 | 1500 | 1800 | 3600 | 7200 | 10800 | 14400: Seconds to hold a "down" alert before sending it, so a blip shorter than this never reaches the recipient at all — like Monitive's alert delay. `up`/`flapping` are always immediate. Optional on write; always present on read.
    - `attached_at` string, date-time: Read-only (issue #396) — when this monitor/recipient attachment was made, stamped by the Postgres server clock. A kept attachment keeps its `attached_at` across a `PUT` that only changes its `down_delay_s`. This is the per-monitor boundary `DELETE /api/v1/recipients/{recipientID}?replaced_by=` measures a replacement recipient's delivery coverage against. Ignored if sent on a request.

## Response `200`

The resulting attached set

- MonitorRecipients: `GET`/`PUT` responses always carry both `recipient_ids` and `recipients` (resolved from the same snapshot), so a client reading either field sees the attached set. `PUT` request bodies accept exactly one of `recipient_ids` (today's form) or `recipients` (issue #338, per-pair `down_delay_s`) — specifying both, or specifying neither, is 400. Either field, when present, must not be JSON `null` (400) — only an explicit `[]` detaches every recipient. Omitting `down_delay_s` on a `recipients` entry keeps an already-attached pair's stored delay, or defaults a newly-attached pair to `0`; the `recipient_ids` form always keeps every attached pair's existing delay.
  - `recipient_ids` integer[]: Must be positive and unique.
  - `recipients` object[]
    - `id` integer, required
    - `down_delay_s` 0 | 60 | 120 | 180 | 240 | 300 | 600 | 900 | 1200 | 1500 | 1800 | 3600 | 7200 | 10800 | 14400: Seconds to hold a "down" alert before sending it, so a blip shorter than this never reaches the recipient at all — like Monitive's alert delay. `up`/`flapping` are always immediate. Optional on write; always present on read.
    - `attached_at` string, date-time: Read-only (issue #396) — when this monitor/recipient attachment was made, stamped by the Postgres server clock. A kept attachment keeps its `attached_at` across a `PUT` that only changes its `down_delay_s`. This is the per-monitor boundary `DELETE /api/v1/recipients/{recipientID}?replaced_by=` measures a replacement recipient's delivery coverage against. Ignored if sent on a request.

## Other responses

- `400`: Bad request (invalid id, or an id not owned by this account)
- `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)
