---
title: "Update a recipient"
method: PUT
path: "/api/v1/recipients/{recipient}"
tags: ["Recipients"]
---

# Update a recipient

`PUT /api/v1/recipients/{recipient}`

## Request

- Base URL: `https://wardenpoint.com` (the document declares no server; this is the origin it was published from)
- URL: `https://wardenpoint.com/api/v1/recipients/{recipient}`
- Auth: API key in header `X-API-Key`

Updates the profile, contacts and groups of a recipient. `name` is required on every call; every other field is optional and an omitted one is left as it is — including `is_active`, so renaming a disabled recipient does not re-enable them. `contacts` and `groups` are authoritative when present — anything missing from the list is removed. `preferences` is merged into the existing object rather than replacing it, and so is each contact `metadata` you do not send; its size, its nesting depth and its `calls` section are validated — see the field description in the request schema. The minimum interval between voice calls is NOT settable here (not even through `preferences.calls`): it has its own endpoint and its own floor. PATCH is accepted on the same path with identical semantics.

## Path parameters

- `recipient` string, uuid, required

## Request body

- RecipientUpdateRequest
  - `name` string, required: Display name.
  - `is_active` boolean: Whether the recipient may receive alerts. Omit it to leave the current state alone — renaming a disabled recipient does not re-enable them.
  - `preferences` object, nullable: Free-form preferences, merged into the stored object rather than replacing it. Bounded in size and nesting depth (8 KiB / 6 levels by default) — an oversized object is rejected rather than stored. The `calls` section is NOT free-form: it holds the call policy this recipient is delivered under, and accepts exactly `counted_outcomes` (a non-empty list of `answered` | `declined` | `no_answer` | `failed`) and `substitute_text` (boolean). Any other key under `calls` is rejected, including `call_min_interval_minutes` — the interval lives elsewhere, has its own endpoint and a floor this route cannot lower.
  - `groups` string[], nullable: UUIDs of the recipient groups. Omit to leave group membership untouched, send [] to remove from every group.
  - `contacts` RecipientContactInput[], nullable: Full contact list. Omit to leave contacts untouched, send [] to remove all of them; anything missing from a non-empty list is deleted.
    - `uuid` string, uuid, nullable: Existing contact to update. Omit to create a new one.
    - `contact_type` string: Contact type slug: telegram, phone, email, internal_sip, … Either this or contact_type_id is required.
    - `contact_type_id` integer: Numeric contact type id, as used by the dashboard. Prefer contact_type — the numeric id is not exposed to API clients.
    - `value` string: The address itself. May be empty only for OAuth-bound types (slack, telegram_bot_chat_id), whose value arrives from the bind callback.
    - `is_primary` boolean: At most one contact may be primary; extra flags are dropped.
    - `metadata` object, nullable: Free-form data stored with the contact, also returned when you read the recipient. Sending it replaces the stored object wholesale; omitting it keeps what is stored, so a read-modify-write of one field is safe. Some keys are ours and are re-derived on save (phone voice zone, the Teams and SIP binding) — leave them as you found them.

## Response `200`

Updated recipient.

- object
  - `data` Recipient: A person or endpoint alerts are delivered to.
    - `uuid` string, uuid: Stable identifier — every recipient endpoint takes this.
    - `name` string: Display name.
    - `is_active` boolean: False means the recipient is skipped by delivery.
    - `call_min_interval_minutes` integer: Minimum interval between voice calls to this person, in minutes. Read-only here — it has its own endpoint and a floor of 5.
    - `created_at` string, date-time
    - `updated_at` string, date-time
    - `delivery` object: Whether an alert addressed to this recipient has anywhere to go. A recipient with no contact — or with contacts only on channels this company has not got working — looks configured, joins groups, sits in escalation chains and receives nothing; this is the field that says so. It answers "is there somewhere to send", not "will we send": a disabled recipient (is_active false) with a working contact is still reported deliverable, because nothing needs fixing beyond re-enabling them.
      - `deliverable` boolean: False means nothing reaches this recipient right now.
      - `reason` 'no_usable_channel' | 'no_contact' | 'no_deliverable_contact', nullable: Why not. `no_usable_channel` — the company has no working delivery channel at all, so EVERY recipient is undeliverable and adding contacts will not help; fix it in the dashboard and check `GET /capabilities`. `no_contact` — the recipient has no contact yet. `no_deliverable_contact` — contacts exist, but all of them sit on channels that are disabled, not included in the plan, not configured, or still waiting for an OAuth binding to complete. Null when deliverable.
      - `message` string, nullable: The same fact in words, in the language of the request. Null when deliverable.
    - `contacts` RecipientContact[]: Present only on single-recipient responses.
      - `uuid` string, uuid
      - `contact_type` string: Slug of the contact type — the same value the write endpoints accept.
      - `value` string: The address itself: a Telegram handle, a phone number in E.164, an email.
      - `is_primary` boolean: The contact preferred when a channel could use more than one of this recipient's addresses. At most one per recipient is primary.
      - `is_active` boolean: Flipped to false automatically after repeated delivery failures.
      - `is_verified` boolean: A bookkeeping flag an operator sets by hand. Nothing in delivery consults it — an unverified contact is used exactly like a verified one, so do not read this as "reachable". `is_active` is the flag that actually gates delivery.
      - `metadata` object, nullable: Free-form data stored with the contact, plus keys we derive ourselves (phone voice zone, the Teams and SIP binding). Returned so a read-modify-write cycle can send it back unchanged.
    - `groups` object[]: Present only on single-recipient responses.
      - `uuid` string, uuid
      - `name` string

## Other responses

- `401`: API key missing, invalid, revoked or expired.
- `403`: API key lacks config.write, or the recipient belongs to another company.
- `404`: No recipient with this UUID.
- `422`: Validation failed — unknown contact type, malformed contact value, two contacts of the same type, a contact UUID that belongs to another recipient, or an internal SIP extension that does not exist in this company or is already taken. Nothing is written when this is returned; the whole update is one transaction.

---

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