---
title: "Replace organization contact policy"
method: PUT
path: "/contact-policy"
tags: ["Contacts"]
---

# Replace organization contact policy

`PUT /contact-policy`

## Request

- Base URL: `https://api.primitive.dev/v1`
- URL: `https://api.primitive.dev/v1/contact-policy`
- Auth: HTTP bearer

Receiver-side email notification admission preferences; never task, tool, code execution or account authority. Rules take effect only in receivers implementing this current contact-policy contract. Older receivers may continue their previous exact-contact notifications until updated. Ordinary email delivery, storage, webhooks and explicit reply waits remain independent of these preferences. Organization owners/admins using session, OAuth or signed dashboard credentials may read/write all policies. Current human members may read/write only their own personal agent policy, bound to their membership incarnation. Connected credentials may only GET their own agent composite; they cannot write either policy. Function and signed capability credentials are not granted access. Rules are unordered. Exact membership notify:false always silences. Next use matching agent rules, otherwise matching organization rules; silence wins ties within that scope. If neither scope matches, existing exact membership notify:true allows using its own activation metadata; otherwise only enabled contact-request intake is allowed. Owner policy silence therefore cannot be bypassed by a connected agent adding a notify:true membership. Patterns are canonical lowercase bare mailboxes, *@example.com, research-*@example.com or *@*.example.com. Only a terminal local-part * and a leading whole domain-label *. are supported; subdomain patterns exclude the apex and require a literal multi-label suffix. No regular expressions, question marks, universal domains or wildcard TLDs. Domain-only UI input must be converted to *@domain. PUT fully replaces up to 100 rules and the request-intake option using exactly one CAS precondition. Duplicate pattern/effect pairs are rejected. if_absent returns an identical existing document, otherwise 409. A missing document reads as empty rules, null version/timestamps, false request intake for the organization and null (inherit) for the agent. Reset overrides with empty rules and null request intake. Allow rules preserve server activation metadata while retained unchanged; removing/recreating or changing a rule to allow resets it. Request intake defaults off; agent null inherits the organization. No-op writes preserve versions. Agent composite effective_version changes with either policy document, connection identity, generation or successful claim; effective_since is the latest policy mutation, connection creation or successful claim. Reclaiming a connection invalidates prior admission snapshots and starts a fresh rule/request cutoff; routine heartbeats do not. Rule/request admissions require received_at >= both the selected activation time and effective_since. Consequently even unrelated policy edits suppress queued older rule/request admissions, without deleting email history or affecting explicit reply waits. Exact membership fallback retains its own notify_since and generation but must still recheck current policy denies and effective_version. Before dispatch, receivers must recheck the current composite version and applicable activation generation and membership; stop new admissions when policy is unavailable or older than 30 seconds. Snapshot fields explain scope and matched rules locally; the API does not execute tasks or dispatch notifications.

## Request body

- union
  - PutContactPolicyCreate
    - `rules` ContactPolicyRuleInput[], required
      - `pattern` string, required: Trim outer whitespace, then require ASCII before lowercase normalization. Exact mailbox or restricted mailbox glob. See operation description.
      - `effect` 'allow' | 'silence', required
    - `allow_contact_requests` boolean, required
    - `if_absent` true, required
  - PutContactPolicyReplace
    - `rules` ContactPolicyRuleInput[], required
      - `pattern` string, required: Trim outer whitespace, then require ASCII before lowercase normalization. Exact mailbox or restricted mailbox glob. See operation description.
      - `effect` 'allow' | 'silence', required
    - `allow_contact_requests` boolean, required
    - `if_version` string, uuid, required

## Response `200`

Current policy

- object
  - `success` true, required
  - `data` ContactPolicy, required
    - `rules` ContactPolicyRule[], required
      - `pattern` string, required: Trim outer whitespace, then require ASCII before lowercase normalization. Exact mailbox or restricted mailbox glob. See operation description.
      - `effect` 'allow' | 'silence', required
      - `notify_since` string, date-time, nullable, required
      - `notification_generation` string, uuid, nullable, required
    - `contact_request_since` string, date-time, nullable, required
    - `contact_request_generation` string, uuid, nullable, required
    - `version` string, uuid, nullable, required
    - `updated_at` string, date-time, nullable, required
    - `allow_contact_requests` boolean, required

## Other responses

- `400`: Invalid request parameters
- `401`: Invalid or missing API key
- `403`: Authenticated caller lacks permission for the operation
- `404`: Resource not found
- `409`: contact_conflict: policy precondition did not match
- `429`: Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.

## Changes

> 32 revisions in range; 1 not diffed.

- **2026-11-03** `bce409c97acb`: 186 warning
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `400`
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `401`
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `403`
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `404`
  - …182 more
  - …this revision’s changelog is incomplete
- **2026-10-21** `0360ea8d4f3d`: 78 warning
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `400`
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `401`
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `403`
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `404`
  - …74 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/primitive/apis/primitive-api/changes/contact-policy/put.md)

---

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