---
title: "Add a contact to a recipient"
method: POST
path: "/api/v1/recipients/{recipient}/contacts"
tags: ["Recipients"]
---

# Add a contact to a recipient

`POST /api/v1/recipients/{recipient}/contacts`

## 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}/contacts`
- Auth: API key in header `X-API-Key`

Attaches one delivery address to a recipient. A recipient may hold at most one contact per type, so a repeated call answers 409 instead of creating a second row — a retry after a timeout never produces a duplicate, and the fix for a real conflict is to update the existing contact. Phone numbers are normalised to E.164 and enriched with a voice-cost zone on save, so the stored value can differ from the one sent. internal_sip goes through extension allocation rather than a plain insert: pass an existing free extension number, or "__create_new__" to have one allocated.

## Path parameters

- `recipient` string, uuid, required

## Request body

- RecipientContactCreateRequest
  - `contact_type` string, required: Contact type slug: telegram, phone, email, internal_sip, slack, msteams, … A recipient may hold at most one contact per type.
  - `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: a Telegram handle, a phone number (normalised to E.164 on save), an email. May be empty only for externally bound types (slack, telegram_bot_chat_id, msteams). For internal_sip pass an existing free extension number, or "__create_new__" to have one allocated.
  - `is_primary` boolean: Makes this the primary contact and clears the flag on every other contact of the recipient. Defaults to false.
  - `label` string, nullable: Short human note shown next to the contact.

## Response `201`

Contact created.

- object
  - `data` RecipientContact: One delivery address of a recipient.
    - `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.

## 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.
- `409`: The recipient already has a contact of this type — update that one instead.
- `422`: Rejected: unknown contact type slug, a type the plan does not include, a missing value for a type that requires one, a value that does not match the type, or an internal_sip extension that is missing or already taken. An unknown contact_type slug is reported under the field name contact_type_id — that is the resolved field the rules run on.

---

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